szurubooru/client/js/models/post.js

510 lines
14 KiB
JavaScript
Raw Normal View History

"use strict";
const api = require("../api.js");
const uri = require("../util/uri.js");
const tags = require("../tags.js");
const events = require("../events.js");
const TagList = require("./tag_list.js");
const NoteList = require("./note_list.js");
const CommentList = require("./comment_list.js");
const PoolList = require("./pool_list.js");
const Pool = require("./pool.js");
const misc = require("../util/misc.js");
2016-07-03 13:46:49 +02:00
class Post extends events.EventTarget {
constructor() {
super();
this._orig = {};
for (let obj of [this, this._orig]) {
2017-10-01 21:46:53 +02:00
obj._tags = new TagList();
obj._notes = new NoteList();
obj._comments = new CommentList();
2020-05-04 11:20:23 +02:00
obj._pools = new PoolList();
}
this._updateFromResponse({});
}
2020-06-04 20:09:35 +02:00
get id() {
return this._id;
}
get type() {
return this._type;
}
get mimeType() {
return this._mimeType;
}
get checksumSHA1() {
return this._checksumSHA1;
}
get checksumMD5() {
return this._checksumMD5;
}
2020-06-04 20:09:35 +02:00
get creationTime() {
return this._creationTime;
}
get user() {
return this._user;
}
get safety() {
return this._safety;
}
get contentUrl() {
return this._contentUrl;
}
get fullContentUrl() {
return this._fullContentUrl;
}
get thumbnailUrl() {
return this._thumbnailUrl;
}
get source() {
return this._source;
}
get sourceSplit() {
return this._source.split("\n");
2020-06-04 20:09:35 +02:00
}
get canvasWidth() {
return this._canvasWidth || 800;
}
get canvasHeight() {
return this._canvasHeight || 450;
}
get fileSize() {
return this._fileSize || 0;
}
get newContent() {
throw "Invalid operation";
2020-06-04 20:09:35 +02:00
}
get newThumbnail() {
throw "Invalid operation";
2020-06-04 20:09:35 +02:00
}
get flags() {
return this._flags;
}
get tags() {
return this._tags;
}
get tagNames() {
return this._tags.map((tag) => tag.names[0]);
2020-06-04 20:09:35 +02:00
}
get notes() {
return this._notes;
}
get comments() {
return this._comments;
}
get relations() {
return this._relations;
}
2020-06-05 03:01:28 +02:00
get pools() {
return this._pools;
}
2020-06-04 20:09:35 +02:00
get score() {
return this._score;
}
get commentCount() {
return this._commentCount;
}
get favoriteCount() {
return this._favoriteCount;
}
get ownFavorite() {
return this._ownFavorite;
}
get ownScore() {
return this._ownScore;
}
get hasCustomThumbnail() {
return this._hasCustomThumbnail;
}
set flags(value) {
this._flags = value;
}
set safety(value) {
this._safety = value;
}
set relations(value) {
this._relations = value;
}
set newContent(value) {
this._newContent = value;
}
set newThumbnail(value) {
this._newThumbnail = value;
}
set source(value) {
this._source = value;
}
static fromResponse(response) {
const ret = new Post();
ret._updateFromResponse(response);
return ret;
}
static reverseSearch(content) {
let apiPromise = api.post(
uri.formatApiLink("posts", "reverse-search"),
{},
{ content: content }
);
let returnedPromise = apiPromise.then((response) => {
if (response.exactPost) {
response.exactPost = Post.fromResponse(response.exactPost);
}
for (let item of response.similarPosts) {
item.post = Post.fromResponse(item.post);
}
return Promise.resolve(response);
});
2017-01-07 16:24:56 +01:00
returnedPromise.abort = () => apiPromise.abort();
return returnedPromise;
}
static get(id) {
return api.get(uri.formatApiLink("post", id)).then((response) => {
return Promise.resolve(Post.fromResponse(response));
});
}
_savePoolPosts() {
const difference = (a, b) => a.filter((post) => !b.hasPoolId(post.id));
2020-05-05 00:15:30 +02:00
// find the pools where the post was added or removed
const added = difference(this.pools, this._orig._pools);
const removed = difference(this._orig._pools, this.pools);
2020-05-05 00:15:30 +02:00
let ops = [];
2020-05-05 00:15:30 +02:00
// update each pool's list of posts
for (let pool of added) {
let op = Pool.get(pool.id).then((response) => {
2020-05-05 00:15:30 +02:00
if (!response.posts.hasPostId(this._id)) {
response.posts.addById(this._id);
return response.save();
} else {
return Promise.resolve(response);
}
});
ops.push(op);
}
for (let pool of removed) {
let op = Pool.get(pool.id).then((response) => {
2020-05-05 00:15:30 +02:00
if (response.posts.hasPostId(this._id)) {
response.posts.removeById(this._id);
return response.save();
} else {
return Promise.resolve(response);
}
});
ops.push(op);
}
return Promise.all(ops);
}
2016-08-20 22:40:25 +02:00
save(anonymous) {
const files = {};
const detail = { version: this._version };
2016-07-03 13:46:49 +02:00
// send only changed fields to avoid user privilege violation
2016-08-20 22:40:25 +02:00
if (anonymous === true) {
detail.anonymous = true;
}
2016-07-03 13:46:49 +02:00
if (this._safety !== this._orig._safety) {
detail.safety = this._safety;
}
if (misc.arraysDiffer(this._flags, this._orig._flags)) {
detail.flags = this._flags;
}
if (misc.arraysDiffer(this._tags, this._orig._tags)) {
detail.tags = this._tags.map((tag) => tag.names[0]);
2016-07-05 21:20:28 +02:00
}
if (misc.arraysDiffer(this._relations, this._orig._relations)) {
2016-07-03 13:46:49 +02:00
detail.relations = this._relations;
}
2016-07-22 13:27:52 +02:00
if (misc.arraysDiffer(this._notes, this._orig._notes)) {
detail.notes = this._notes.map((note) => ({
polygon: note.polygon.map((point) => [point.x, point.y]),
2016-07-22 13:27:52 +02:00
text: note.text,
}));
}
2016-08-20 22:40:25 +02:00
if (this._newContent) {
files.content = this._newContent;
2016-07-27 22:27:33 +02:00
}
2016-08-20 22:40:25 +02:00
if (this._newThumbnail !== undefined) {
files.thumbnail = this._newThumbnail;
}
if (this._source !== this._orig._source) {
detail.source = this._source;
}
let apiPromise = this._id
? api.put(uri.formatApiLink("post", this.id), detail, files)
: api.post(uri.formatApiLink("posts"), detail, files);
2016-07-05 21:20:28 +02:00
return apiPromise
.then((response) => {
if (misc.arraysDiffer(this._pools, this._orig._pools)) {
return this._savePoolPosts().then(() =>
Promise.resolve(response)
);
}
return Promise.resolve(response);
})
.then(
(response) => {
this._updateFromResponse(response);
this.dispatchEvent(
new CustomEvent("change", { detail: { post: this } })
);
if (this._newContent) {
this.dispatchEvent(
new CustomEvent("changeContent", {
detail: { post: this },
})
);
}
if (this._newThumbnail) {
this.dispatchEvent(
new CustomEvent("changeThumbnail", {
detail: { post: this },
})
);
}
return Promise.resolve();
},
(error) => {
if (
error.response &&
error.response.name === "PostAlreadyUploadedError"
) {
error.message = `Post already uploaded (@${error.response.otherPostId})`;
}
return Promise.reject(error);
}
);
2016-07-05 21:20:28 +02:00
}
2016-08-02 10:37:56 +02:00
feature() {
return api
.post(uri.formatApiLink("featured-post"), { id: this._id })
.then((response) => {
2016-08-02 10:37:56 +02:00
return Promise.resolve();
});
}
2016-08-02 11:05:40 +02:00
delete() {
return api
.delete(uri.formatApiLink("post", this.id), {
version: this._version,
})
.then((response) => {
this.dispatchEvent(
new CustomEvent("delete", {
detail: {
post: this,
},
})
);
2016-08-02 11:05:40 +02:00
return Promise.resolve();
});
2016-10-22 10:03:38 +02:00
}
merge(targetId, useOldContent) {
return api
.get(uri.formatApiLink("post", targetId))
.then((response) => {
return api.post(uri.formatApiLink("post-merge"), {
2016-10-22 10:03:38 +02:00
removeVersion: this._version,
remove: this._id,
mergeToVersion: response.version,
mergeTo: targetId,
replaceContent: useOldContent,
});
})
.then((response) => {
2016-10-22 10:03:38 +02:00
this._updateFromResponse(response);
this.dispatchEvent(
new CustomEvent("change", {
detail: {
post: this,
},
})
);
2016-10-22 10:03:38 +02:00
return Promise.resolve();
});
2016-08-02 11:05:40 +02:00
}
setScore(score) {
return api
.put(uri.formatApiLink("post", this.id, "score"), { score: score })
.then((response) => {
const prevFavorite = this._ownFavorite;
this._updateFromResponse(response);
if (this._ownFavorite !== prevFavorite) {
this.dispatchEvent(
new CustomEvent("changeFavorite", {
detail: {
post: this,
},
})
);
}
this.dispatchEvent(
new CustomEvent("changeScore", {
detail: {
post: this,
},
})
);
return Promise.resolve();
});
}
addToFavorites() {
return api
.post(uri.formatApiLink("post", this.id, "favorite"))
.then((response) => {
const prevScore = this._ownScore;
this._updateFromResponse(response);
if (this._ownScore !== prevScore) {
this.dispatchEvent(
new CustomEvent("changeScore", {
detail: {
post: this,
},
})
);
}
this.dispatchEvent(
new CustomEvent("changeFavorite", {
detail: {
post: this,
},
})
);
return Promise.resolve();
});
}
removeFromFavorites() {
return api
.delete(uri.formatApiLink("post", this.id, "favorite"))
.then((response) => {
const prevScore = this._ownScore;
this._updateFromResponse(response);
if (this._ownScore !== prevScore) {
this.dispatchEvent(
new CustomEvent("changeScore", {
detail: {
post: this,
},
})
);
}
this.dispatchEvent(
new CustomEvent("changeFavorite", {
detail: {
post: this,
},
})
);
return Promise.resolve();
});
}
2016-07-27 22:27:33 +02:00
mutateContentUrl() {
this._contentUrl =
this._orig._contentUrl +
"?bypass-cache=" +
Math.round(Math.random() * 1000);
2016-07-27 22:27:33 +02:00
}
_updateFromResponse(response) {
2016-07-22 13:27:52 +02:00
const map = () => ({
2020-06-04 20:09:35 +02:00
_version: response.version,
_id: response.id,
_type: response.type,
_mimeType: response.mimeType,
_checksumSHA1: response.checksum,
_checksumMD5: response.checksumMD5,
2020-06-04 20:09:35 +02:00
_creationTime: response.creationTime,
_user: response.user,
_safety: response.safety,
_contentUrl: response.contentUrl,
_fullContentUrl: new URL(
response.contentUrl,
document.getElementsByTagName("base")[0].href
).href,
2020-06-04 20:09:35 +02:00
_thumbnailUrl: response.thumbnailUrl,
_source: response.source,
_canvasWidth: response.canvasWidth,
_canvasHeight: response.canvasHeight,
_fileSize: response.fileSize,
2016-07-03 13:46:49 +02:00
_flags: [...(response.flags || [])],
_relations: [...(response.relations || [])],
2016-07-03 13:46:49 +02:00
2020-06-04 20:09:35 +02:00
_score: response.score,
_commentCount: response.commentCount,
2016-07-03 13:46:49 +02:00
_favoriteCount: response.favoriteCount,
2020-06-04 20:09:35 +02:00
_ownScore: response.ownScore,
_ownFavorite: response.ownFavorite,
_hasCustomThumbnail: response.hasCustomThumbnail,
2016-07-22 13:27:52 +02:00
});
2016-07-03 13:46:49 +02:00
for (let obj of [this, this._orig]) {
2017-10-01 21:46:53 +02:00
obj._tags.sync(response.tags);
obj._notes.sync(response.notes);
obj._comments.sync(response.comments);
2020-05-04 11:20:23 +02:00
obj._pools.sync(response.pools);
}
2016-07-22 13:27:52 +02:00
Object.assign(this, map());
Object.assign(this._orig, map());
}
2020-06-04 20:09:35 +02:00
}
module.exports = Post;