szurubooru/client/js/models/post.js

465 lines
13 KiB
JavaScript
Raw Normal View History

'use strict';
const api = require('../api.js');
const uri = require('../util/uri.js');
2016-07-05 21:20:28 +02:00
const tags = require('../tags.js');
const events = require('../events.js');
2017-10-01 21:46:53 +02:00
const TagList = require('./tag_list.js');
2016-07-22 13:27:52 +02:00
const NoteList = require('./note_list.js');
const CommentList = require('./comment_list.js');
2020-05-04 11:20:23 +02:00
const PoolList = require('./pool_list.js');
2020-05-05 00:15:30 +02:00
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 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');
}
get canvasWidth() {
return this._canvasWidth || 800;
}
get canvasHeight() {
return this._canvasHeight || 450;
}
get fileSize() {
return this._fileSize || 0;
}
get newContent() {
throw 'Invalid operation';
}
get newThumbnail() {
throw 'Invalid operation';
}
get flags() {
return this._flags;
}
get tags() {
return this._tags;
}
get tagNames() {
return this._tags.map(tag => tag.names[0]);
}
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) {
2020-05-05 00:15:30 +02:00
let op = Pool.get(pool.id).then(response => {
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) {
2020-05-05 00:15:30 +02:00
let op = Pool.get(pool.id).then(response => {
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)) {
2017-10-01 21:46:53 +02:00
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)) {
2017-10-01 21:46:53 +02:00
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;
}
2016-09-29 21:36:59 +02:00
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
2017-01-07 16:24:56 +01:00
return apiPromise.then(response => {
2020-05-05 00:15:30 +02:00
if (misc.arraysDiffer(this._pools, this._orig._pools)) {
return this._savePoolPosts()
2020-06-05 03:01:28 +02:00
.then(() => Promise.resolve(response));
}
return Promise.resolve(response);
}).then(response => {
2016-07-05 21:20:28 +02:00
this._updateFromResponse(response);
this.dispatchEvent(
new CustomEvent('change', {detail: {post: this}}));
if (this._newContent) {
2016-07-27 22:27:33 +02:00
this.dispatchEvent(
new CustomEvent('changeContent', {detail: {post: this}}));
}
2016-08-20 22:40:25 +02:00
if (this._newThumbnail) {
this.dispatchEvent(
new CustomEvent('changeThumbnail', {detail: {post: this}}));
}
2016-07-05 21:20:28 +02:00
return Promise.resolve();
2017-01-08 02:12:38 +01:00
}, error => {
if (error.response &&
2020-05-05 00:15:30 +02:00
error.response.name === 'PostAlreadyUploadedError') {
2017-01-08 02:12:38 +01:00
error.message =
2020-05-05 00:15:30 +02:00
`Post already uploaded (@${error.response.otherPostId})`;
}
2017-01-08 02:12:38 +01:00
return Promise.reject(error);
2016-07-05 21:20:28 +02:00
});
}
2016-08-02 10:37:56 +02:00
feature() {
return api.post(
2020-06-04 20:09:35 +02:00
uri.formatApiLink('featured-post'),
{id: this._id})
2016-08-02 10:37:56 +02:00
.then(response => {
return Promise.resolve();
});
}
2016-08-02 11:05:40 +02:00
delete() {
return api.delete(
2020-06-04 20:09:35 +02:00
uri.formatApiLink('post', this.id),
{version: this._version})
2016-08-02 11:05:40 +02:00
.then(response => {
this.dispatchEvent(new CustomEvent('delete', {
detail: {
post: this,
},
}));
return Promise.resolve();
});
2016-10-22 10:03:38 +02:00
}
merge(targetId, useOldContent) {
return api.get(uri.formatApiLink('post', targetId))
2016-10-22 10:03:38 +02:00
.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 => {
this._updateFromResponse(response);
this.dispatchEvent(new CustomEvent('change', {
detail: {
post: this,
},
}));
return Promise.resolve();
});
2016-08-02 11:05:40 +02:00
}
setScore(score) {
return api.put(
2020-06-04 20:09:35 +02:00
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 =
2020-05-05 00:15:30 +02:00
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,
_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
2020-06-04 20:09:35 +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;