aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/css/pool-list-view.styl2
-rw-r--r--client/html/pool.tpl2
-rw-r--r--client/html/pools_page.tpl4
-rw-r--r--client/js/controllers/pool_controller.js4
-rw-r--r--client/js/controls/pool_input_control.js25
-rw-r--r--client/js/models/post.js199
-rw-r--r--client/js/views/pool_merge_view.js9
-rw-r--r--server/szurubooru/func/pools.py47
8 files changed, 130 insertions, 162 deletions
diff --git a/client/css/pool-list-view.styl b/client/css/pool-list-view.styl
index 2daf694..0f57649 100644
--- a/client/css/pool-list-view.styl
+++ b/client/css/pool-list-view.styl
@@ -15,7 +15,7 @@
background: $top-navigation-color
.names
width: 84%
- .usages
+ .post-count
text-align: center
width: 8%
.creation-time
diff --git a/client/html/pool.tpl b/client/html/pool.tpl
index 5af10c9..e1e5311 100644
--- a/client/html/pool.tpl
+++ b/client/html/pool.tpl
@@ -1,5 +1,5 @@
<div class='content-wrapper' id='pool'>
- <h1><%- ctx.pool.first_name %></h1>
+ <h1><%- ctx.pool.names[0] %></h1>
<nav class='buttons'><!--
--><ul><!--
--><li data-name='summary'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id) %>'>Summary</a></li><!--
diff --git a/client/html/pools_page.tpl b/client/html/pools_page.tpl
index 6b39483..0d81180 100644
--- a/client/html/pools_page.tpl
+++ b/client/html/pools_page.tpl
@@ -11,9 +11,9 @@
</th>
<th class='post-count'>
<% if (ctx.parameters.query == 'sort:post-count') { %>
- <a href='<%- ctx.formatClientLink('pools', {query: '-sort:post-count'}) %>'>Post Count</a>
+ <a href='<%- ctx.formatClientLink('pools', {query: '-sort:post-count'}) %>'>Post count</a>
<% } else { %>
- <a href='<%- ctx.formatClientLink('pools', {query: 'sort:post-count'}) %>'>Post Count</a>
+ <a href='<%- ctx.formatClientLink('pools', {query: 'sort:post-count'}) %>'>Post count</a>
<% } %>
</th>
<th class='creation-time'>
diff --git a/client/js/controllers/pool_controller.js b/client/js/controllers/pool_controller.js
index 99e2e9b..e243cd8 100644
--- a/client/js/controllers/pool_controller.js
+++ b/client/js/controllers/pool_controller.js
@@ -105,13 +105,13 @@ class PoolController {
this._view.clearMessages();
this._view.disableForm();
e.detail.pool
- .merge(e.detail.targetPoolName, e.detail.addAlias)
+ .merge(e.detail.targetPoolId, e.detail.addAlias)
.then(() => {
this._view.showSuccess('Pool merged.');
this._view.enableForm();
router.replace(
uri.formatClientLink(
- 'pool', e.detail.targetPoolName, 'merge'),
+ 'pool', e.detail.targetPoolId, 'merge'),
null, false);
}, error => {
this._view.showError(error.message);
diff --git a/client/js/controls/pool_input_control.js b/client/js/controls/pool_input_control.js
index f53c8c9..a827206 100644
--- a/client/js/controls/pool_input_control.js
+++ b/client/js/controls/pool_input_control.js
@@ -64,10 +64,6 @@ class PoolInputControl extends events.EventTarget {
verticalShift: -2
});
- // dom events
- this._poolInputNode.addEventListener(
- 'keydown', e => this._evtInputKeyDown(e));
-
// show
this._hostNode.style.display = 'none';
this._hostNode.parentNode.insertBefore(
@@ -117,23 +113,6 @@ class PoolInputControl extends events.EventTarget {
this.dispatchEvent(new CustomEvent('change'));
}
- _evtAddPoolButtonClick(e) {
- // TODO
- // e.preventDefault();
- // this.addPoolByName(this._poolInputNode.value, SOURCE_USER_INPUT);
- // this._poolInputNode.value = '';
- }
-
- _evtInputKeyDown(e) {
- // TODO
- if (e.which == KEY_RETURN || e.which == KEY_SPACE) {
- e.preventDefault();
- // this._hideAutoComplete();
- // this.addPoolByText(this._poolInputNode.value, SOURCE_USER_INPUT);
- // this._poolInputNode.value = '';
- }
- }
-
_createListItemNode(pool) {
const className = pool.category ?
misc.makeCssName(pool.category, 'pool') :
@@ -159,10 +138,6 @@ class PoolInputControl extends events.EventTarget {
'href', uri.formatClientLink(
'posts', {query: "pool:" + pool.id}));
searchLinkNode.textContent = pool.names[0] + ' ';
- searchLinkNode.addEventListener('click', e => {
- // TODO?
- // e.preventDefault();
- });
const usagesNode = document.createElement('span');
usagesNode.classList.add('pool-usages');
diff --git a/client/js/models/post.js b/client/js/models/post.js
index e3388ec..6022ae0 100644
--- a/client/js/models/post.js
+++ b/client/js/models/post.js
@@ -8,6 +8,7 @@ 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');
class Post extends events.EventTarget {
@@ -98,22 +99,36 @@ class Post extends events.EventTarget {
_savePoolPosts() {
const difference = (a, b) => a.filter(post => !b.hasPoolId(post.id));
+
+ // 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);
+
let ops = [];
+ // update each pool's list of posts
for (let pool of added) {
- if (!pool.posts.hasPostId(this._id)) {
- pool.posts.addById(this._id);
- ops.push(pool.save());
- }
+ 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) {
- if (pool.posts.hasPostId(this._id)) {
- pool.posts.removeById(this._id);
- ops.push(pool.save());
- }
+ 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);
@@ -156,34 +171,34 @@ class Post extends events.EventTarget {
}
let apiPromise = this._id ?
- api.put(uri.formatApiLink('post', this.id), detail, files) :
- api.post(uri.formatApiLink('posts'), detail, files);
+ api.put(uri.formatApiLink('post', this.id), detail, files) :
+ api.post(uri.formatApiLink('posts'), detail, files);
return apiPromise.then(response => {
- if (this._pools !== this._orig._pools) {
+ if (misc.arraysDiffer(this._pools, this._orig._pools)) {
return this._savePoolPosts()
- .then(() => Promise.resolve(response));
+ .then(() => Promise.resolve(response));
}
return Promise.resolve(response);
}).then(response => {
this._updateFromResponse(response);
this.dispatchEvent(
- new CustomEvent('change', {detail: {post: this}}));
+ new CustomEvent('change', {detail: {post: this}}));
if (this._newContent) {
this.dispatchEvent(
- new CustomEvent('changeContent', {detail: {post: this}}));
+ new CustomEvent('changeContent', {detail: {post: this}}));
}
if (this._newThumbnail) {
this.dispatchEvent(
- new CustomEvent('changeThumbnail', {detail: {post: this}}));
+ new CustomEvent('changeThumbnail', {detail: {post: this}}));
}
return Promise.resolve();
}, error => {
if (error.response &&
- error.response.name === 'PostAlreadyUploadedError') {
+ error.response.name === 'PostAlreadyUploadedError') {
error.message =
- `Post already uploaded (@${error.response.otherPostId})`;
+ `Post already uploaded (@${error.response.otherPostId})`;
}
return Promise.reject(error);
});
@@ -191,118 +206,118 @@ class Post extends events.EventTarget {
feature() {
return api.post(
- uri.formatApiLink('featured-post'),
- {id: this._id})
- .then(response => {
- return Promise.resolve();
- });
+ uri.formatApiLink('featured-post'),
+ {id: this._id})
+ .then(response => {
+ return Promise.resolve();
+ });
}
delete() {
return api.delete(
- uri.formatApiLink('post', this.id),
- {version: this._version})
- .then(response => {
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- post: this,
- },
- }));
- return Promise.resolve();
- });
+ uri.formatApiLink('post', this.id),
+ {version: this._version})
+ .then(response => {
+ this.dispatchEvent(new CustomEvent('delete', {
+ detail: {
+ post: this,
+ },
+ }));
+ return Promise.resolve();
+ });
}
merge(targetId, useOldContent) {
return api.get(uri.formatApiLink('post', targetId))
- .then(response => {
- return api.post(uri.formatApiLink('post-merge'), {
- removeVersion: this._version,
- remove: this._id,
- mergeToVersion: response.version,
- mergeTo: targetId,
- replaceContent: useOldContent,
+ .then(response => {
+ return api.post(uri.formatApiLink('post-merge'), {
+ 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();
});
- }).then(response => {
- this._updateFromResponse(response);
- this.dispatchEvent(new CustomEvent('change', {
- detail: {
- post: this,
- },
- }));
- return Promise.resolve();
- });
}
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', {
+ 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,
},
}));
- }
- this.dispatchEvent(new CustomEvent('changeScore', {
- detail: {
- post: this,
- },
- }));
- return Promise.resolve();
- });
+ 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', {
+ .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,
},
}));
- }
- this.dispatchEvent(new CustomEvent('changeFavorite', {
- detail: {
- post: this,
- },
- }));
- return Promise.resolve();
- });
+ 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', {
+ .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,
},
}));
- }
- this.dispatchEvent(new CustomEvent('changeFavorite', {
- detail: {
- post: this,
- },
- }));
- return Promise.resolve();
- });
+ return Promise.resolve();
+ });
}
mutateContentUrl() {
this._contentUrl =
- this._orig._contentUrl +
- '?bypass-cache=' +
- Math.round(Math.random() * 1000);
+ this._orig._contentUrl +
+ '?bypass-cache=' +
+ Math.round(Math.random() * 1000);
}
_updateFromResponse(response) {
diff --git a/client/js/views/pool_merge_view.js b/client/js/views/pool_merge_view.js
index ea9fe6f..4bbef7e 100644
--- a/client/js/views/pool_merge_view.js
+++ b/client/js/views/pool_merge_view.js
@@ -14,6 +14,7 @@ class PoolMergeView extends events.EventTarget {
this._pool = ctx.pool;
this._hostNode = ctx.hostNode;
+ this._target_pool_id = null;
ctx.poolNamePattern = api.getPoolNameRegex();
views.replaceContent(this._hostNode, template(ctx));
@@ -22,9 +23,11 @@ class PoolMergeView extends events.EventTarget {
this._autoCompleteControl = new PoolAutoCompleteControl(
this._targetPoolFieldNode,
{
- confirm: pool =>
+ confirm: pool => {
+ this._target_pool_id = pool.id;
this._autoCompleteControl.replaceSelectedText(
- pool.names[0], false),
+ pool.names[0], false);
+ }
});
}
@@ -56,7 +59,7 @@ class PoolMergeView extends events.EventTarget {
this.dispatchEvent(new CustomEvent('submit', {
detail: {
pool: this._pool,
- targetPoolName: this._targetPoolFieldNode.value
+ targetPoolId: this._target_pool_id
},
}));
}
diff --git a/server/szurubooru/func/pools.py b/server/szurubooru/func/pools.py
index 4fc4d36..854650a 100644
--- a/server/szurubooru/func/pools.py
+++ b/server/szurubooru/func/pools.py
@@ -6,7 +6,6 @@ from szurubooru import config, db, model, errors, rest
from szurubooru.func import util, pool_categories, serialization, posts
-
class PoolNotFoundError(errors.NotFoundError):
pass
@@ -35,6 +34,10 @@ class InvalidPoolDescriptionError(errors.ValidationError):
pass
+class InvalidPoolRelationError(errors.ValidationError):
+ pass
+
+
def _verify_name_validity(name: str) -> None:
if util.value_exceeds_column_size(name, model.PoolName.name):
raise InvalidPoolNameError('Name is too long.')
@@ -211,45 +214,18 @@ def merge_pools(source_pool: model.Pool, target_pool: model.Pool) -> None:
raise InvalidPoolRelationError('Cannot merge pool with itself.')
def merge_posts(source_pool_id: int, target_pool_id: int) -> None:
- pass
- # alias1 = model.PostPool
- # alias2 = sa.orm.util.aliased(model.PostPool)
- # update_stmt = (
- # sa.sql.expression.update(alias1)
- # .where(alias1.pool_id == source_pool_id))
- # update_stmt = (
- # update_stmt
- # .where(
- # ~sa.exists()
- # .where(alias1.post_id == alias2.post_id)
- # .where(alias2.pool_id == target_pool_id)))
- # update_stmt = update_stmt.values(pool_id=target_pool_id)
- # db.session.execute(update_stmt)
-
- def merge_relations(
- table: model.Base, source_pool_id: int, target_pool_id: int) -> None:
- alias1 = table
- alias2 = sa.orm.util.aliased(table)
+ alias1 = model.PoolPost
+ alias2 = sa.orm.util.aliased(model.PoolPost)
update_stmt = (
sa.sql.expression.update(alias1)
- .where(alias1.parent_id == source_pool_id)
- .where(alias1.child_id != target_pool_id)
- .where(
- ~sa.exists()
- .where(alias2.child_id == alias1.child_id)
- .where(alias2.parent_id == target_pool_id))
- .values(parent_id=target_pool_id))
- db.session.execute(update_stmt)
-
+ .where(alias1.pool_id == source_pool_id))
update_stmt = (
- sa.sql.expression.update(alias1)
- .where(alias1.child_id == source_pool_id)
- .where(alias1.parent_id != target_pool_id)
+ update_stmt
.where(
~sa.exists()
- .where(alias2.parent_id == alias1.parent_id)
- .where(alias2.child_id == target_pool_id))
- .values(child_id=target_pool_id))
+ .where(alias1.post_id == alias2.post_id)
+ .where(alias2.pool_id == target_pool_id)))
+ update_stmt = update_stmt.values(pool_id=target_pool_id)
db.session.execute(update_stmt)
merge_posts(source_pool.pool_id, target_pool.pool_id)
@@ -316,7 +292,6 @@ def update_pool_description(pool: model.Pool, description: str) -> None:
pool.description = description or None
-
def update_pool_posts(pool: model.Pool, post_ids: List[int]) -> None:
assert pool
if _check_post_duplication(post_ids):

© 2015 - 2026 Jakob L. Kreuze