Implement pool merging
This commit is contained in:
parent
ffba010ae4
commit
6b8e3f251f
8 changed files with 137 additions and 169 deletions
|
@ -15,7 +15,7 @@
|
||||||
background: $top-navigation-color
|
background: $top-navigation-color
|
||||||
.names
|
.names
|
||||||
width: 84%
|
width: 84%
|
||||||
.usages
|
.post-count
|
||||||
text-align: center
|
text-align: center
|
||||||
width: 8%
|
width: 8%
|
||||||
.creation-time
|
.creation-time
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class='content-wrapper' id='pool'>
|
<div class='content-wrapper' id='pool'>
|
||||||
<h1><%- ctx.pool.first_name %></h1>
|
<h1><%- ctx.pool.names[0] %></h1>
|
||||||
<nav class='buttons'><!--
|
<nav class='buttons'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li data-name='summary'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id) %>'>Summary</a></li><!--
|
--><li data-name='summary'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id) %>'>Summary</a></li><!--
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
</th>
|
</th>
|
||||||
<th class='post-count'>
|
<th class='post-count'>
|
||||||
<% if (ctx.parameters.query == 'sort: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 { %>
|
<% } 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>
|
||||||
<th class='creation-time'>
|
<th class='creation-time'>
|
||||||
|
|
|
@ -105,13 +105,13 @@ class PoolController {
|
||||||
this._view.clearMessages();
|
this._view.clearMessages();
|
||||||
this._view.disableForm();
|
this._view.disableForm();
|
||||||
e.detail.pool
|
e.detail.pool
|
||||||
.merge(e.detail.targetPoolName, e.detail.addAlias)
|
.merge(e.detail.targetPoolId, e.detail.addAlias)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this._view.showSuccess('Pool merged.');
|
this._view.showSuccess('Pool merged.');
|
||||||
this._view.enableForm();
|
this._view.enableForm();
|
||||||
router.replace(
|
router.replace(
|
||||||
uri.formatClientLink(
|
uri.formatClientLink(
|
||||||
'pool', e.detail.targetPoolName, 'merge'),
|
'pool', e.detail.targetPoolId, 'merge'),
|
||||||
null, false);
|
null, false);
|
||||||
}, error => {
|
}, error => {
|
||||||
this._view.showError(error.message);
|
this._view.showError(error.message);
|
||||||
|
|
|
@ -64,10 +64,6 @@ class PoolInputControl extends events.EventTarget {
|
||||||
verticalShift: -2
|
verticalShift: -2
|
||||||
});
|
});
|
||||||
|
|
||||||
// dom events
|
|
||||||
this._poolInputNode.addEventListener(
|
|
||||||
'keydown', e => this._evtInputKeyDown(e));
|
|
||||||
|
|
||||||
// show
|
// show
|
||||||
this._hostNode.style.display = 'none';
|
this._hostNode.style.display = 'none';
|
||||||
this._hostNode.parentNode.insertBefore(
|
this._hostNode.parentNode.insertBefore(
|
||||||
|
@ -117,23 +113,6 @@ class PoolInputControl extends events.EventTarget {
|
||||||
this.dispatchEvent(new CustomEvent('change'));
|
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) {
|
_createListItemNode(pool) {
|
||||||
const className = pool.category ?
|
const className = pool.category ?
|
||||||
misc.makeCssName(pool.category, 'pool') :
|
misc.makeCssName(pool.category, 'pool') :
|
||||||
|
@ -159,10 +138,6 @@ class PoolInputControl extends events.EventTarget {
|
||||||
'href', uri.formatClientLink(
|
'href', uri.formatClientLink(
|
||||||
'posts', {query: "pool:" + pool.id}));
|
'posts', {query: "pool:" + pool.id}));
|
||||||
searchLinkNode.textContent = pool.names[0] + ' ';
|
searchLinkNode.textContent = pool.names[0] + ' ';
|
||||||
searchLinkNode.addEventListener('click', e => {
|
|
||||||
// TODO?
|
|
||||||
// e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
const usagesNode = document.createElement('span');
|
const usagesNode = document.createElement('span');
|
||||||
usagesNode.classList.add('pool-usages');
|
usagesNode.classList.add('pool-usages');
|
||||||
|
|
|
@ -8,6 +8,7 @@ const TagList = require('./tag_list.js');
|
||||||
const NoteList = require('./note_list.js');
|
const NoteList = require('./note_list.js');
|
||||||
const CommentList = require('./comment_list.js');
|
const CommentList = require('./comment_list.js');
|
||||||
const PoolList = require('./pool_list.js');
|
const PoolList = require('./pool_list.js');
|
||||||
|
const Pool = require('./pool.js');
|
||||||
const misc = require('../util/misc.js');
|
const misc = require('../util/misc.js');
|
||||||
|
|
||||||
class Post extends events.EventTarget {
|
class Post extends events.EventTarget {
|
||||||
|
@ -98,22 +99,36 @@ class Post extends events.EventTarget {
|
||||||
|
|
||||||
_savePoolPosts() {
|
_savePoolPosts() {
|
||||||
const difference = (a, b) => a.filter(post => !b.hasPoolId(post.id));
|
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 added = difference(this.pools, this._orig._pools);
|
||||||
const removed = difference(this._orig._pools, this.pools);
|
const removed = difference(this._orig._pools, this.pools);
|
||||||
|
|
||||||
let ops = [];
|
let ops = [];
|
||||||
|
|
||||||
|
// update each pool's list of posts
|
||||||
for (let pool of added) {
|
for (let pool of added) {
|
||||||
if (!pool.posts.hasPostId(this._id)) {
|
let op = Pool.get(pool.id).then(response => {
|
||||||
pool.posts.addById(this._id);
|
if (!response.posts.hasPostId(this._id)) {
|
||||||
ops.push(pool.save());
|
response.posts.addById(this._id);
|
||||||
|
return response.save();
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(response);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
ops.push(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let pool of removed) {
|
for (let pool of removed) {
|
||||||
if (pool.posts.hasPostId(this._id)) {
|
let op = Pool.get(pool.id).then(response => {
|
||||||
pool.posts.removeById(this._id);
|
if (response.posts.hasPostId(this._id)) {
|
||||||
ops.push(pool.save());
|
response.posts.removeById(this._id);
|
||||||
|
return response.save();
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(response);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
ops.push(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(ops);
|
return Promise.all(ops);
|
||||||
|
@ -160,7 +175,7 @@ class Post extends events.EventTarget {
|
||||||
api.post(uri.formatApiLink('posts'), detail, files);
|
api.post(uri.formatApiLink('posts'), detail, files);
|
||||||
|
|
||||||
return apiPromise.then(response => {
|
return apiPromise.then(response => {
|
||||||
if (this._pools !== this._orig._pools) {
|
if (misc.arraysDiffer(this._pools, this._orig._pools)) {
|
||||||
return this._savePoolPosts()
|
return this._savePoolPosts()
|
||||||
.then(() => Promise.resolve(response));
|
.then(() => Promise.resolve(response));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ class PoolMergeView extends events.EventTarget {
|
||||||
|
|
||||||
this._pool = ctx.pool;
|
this._pool = ctx.pool;
|
||||||
this._hostNode = ctx.hostNode;
|
this._hostNode = ctx.hostNode;
|
||||||
|
this._target_pool_id = null;
|
||||||
ctx.poolNamePattern = api.getPoolNameRegex();
|
ctx.poolNamePattern = api.getPoolNameRegex();
|
||||||
views.replaceContent(this._hostNode, template(ctx));
|
views.replaceContent(this._hostNode, template(ctx));
|
||||||
|
|
||||||
|
@ -22,9 +23,11 @@ class PoolMergeView extends events.EventTarget {
|
||||||
this._autoCompleteControl = new PoolAutoCompleteControl(
|
this._autoCompleteControl = new PoolAutoCompleteControl(
|
||||||
this._targetPoolFieldNode,
|
this._targetPoolFieldNode,
|
||||||
{
|
{
|
||||||
confirm: pool =>
|
confirm: pool => {
|
||||||
|
this._target_pool_id = pool.id;
|
||||||
this._autoCompleteControl.replaceSelectedText(
|
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', {
|
this.dispatchEvent(new CustomEvent('submit', {
|
||||||
detail: {
|
detail: {
|
||||||
pool: this._pool,
|
pool: this._pool,
|
||||||
targetPoolName: this._targetPoolFieldNode.value
|
targetPoolId: this._target_pool_id
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ from szurubooru import config, db, model, errors, rest
|
||||||
from szurubooru.func import util, pool_categories, serialization, posts
|
from szurubooru.func import util, pool_categories, serialization, posts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PoolNotFoundError(errors.NotFoundError):
|
class PoolNotFoundError(errors.NotFoundError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -35,6 +34,10 @@ class InvalidPoolDescriptionError(errors.ValidationError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidPoolRelationError(errors.ValidationError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _verify_name_validity(name: str) -> None:
|
def _verify_name_validity(name: str) -> None:
|
||||||
if util.value_exceeds_column_size(name, model.PoolName.name):
|
if util.value_exceeds_column_size(name, model.PoolName.name):
|
||||||
raise InvalidPoolNameError('Name is too long.')
|
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.')
|
raise InvalidPoolRelationError('Cannot merge pool with itself.')
|
||||||
|
|
||||||
def merge_posts(source_pool_id: int, target_pool_id: int) -> None:
|
def merge_posts(source_pool_id: int, target_pool_id: int) -> None:
|
||||||
pass
|
alias1 = model.PoolPost
|
||||||
# alias1 = model.PostPool
|
alias2 = sa.orm.util.aliased(model.PoolPost)
|
||||||
# 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)
|
|
||||||
update_stmt = (
|
update_stmt = (
|
||||||
sa.sql.expression.update(alias1)
|
sa.sql.expression.update(alias1)
|
||||||
.where(alias1.parent_id == source_pool_id)
|
.where(alias1.pool_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)
|
|
||||||
|
|
||||||
update_stmt = (
|
update_stmt = (
|
||||||
sa.sql.expression.update(alias1)
|
update_stmt
|
||||||
.where(alias1.child_id == source_pool_id)
|
|
||||||
.where(alias1.parent_id != target_pool_id)
|
|
||||||
.where(
|
.where(
|
||||||
~sa.exists()
|
~sa.exists()
|
||||||
.where(alias2.parent_id == alias1.parent_id)
|
.where(alias1.post_id == alias2.post_id)
|
||||||
.where(alias2.child_id == target_pool_id))
|
.where(alias2.pool_id == target_pool_id)))
|
||||||
.values(child_id=target_pool_id))
|
update_stmt = update_stmt.values(pool_id=target_pool_id)
|
||||||
db.session.execute(update_stmt)
|
db.session.execute(update_stmt)
|
||||||
|
|
||||||
merge_posts(source_pool.pool_id, target_pool.pool_id)
|
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
|
pool.description = description or None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_pool_posts(pool: model.Pool, post_ids: List[int]) -> None:
|
def update_pool_posts(pool: model.Pool, post_ids: List[int]) -> None:
|
||||||
assert pool
|
assert pool
|
||||||
if _check_post_duplication(post_ids):
|
if _check_post_duplication(post_ids):
|
||||||
|
|
Loading…
Reference in a new issue