mirror of
https://github.com/rr-/szurubooru.git
synced 2025-07-17 08:26:24 +00:00
Compare commits
2 Commits
6438e67ed6
...
master
Author | SHA1 | Date | |
---|---|---|---|
f66a8d2a96 | |||
ee7e9ef2a3 |
@ -1,4 +1,5 @@
|
||||
node_modules/*
|
||||
public/
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
**/.gitignore
|
||||
|
@ -1,3 +1,26 @@
|
||||
FROM --platform=$BUILDPLATFORM node:lts-alpine as development
|
||||
WORKDIR /opt/app
|
||||
|
||||
RUN apk --no-cache add \
|
||||
dumb-init \
|
||||
nginx \
|
||||
git
|
||||
|
||||
RUN ln -sf /opt/app/nginx.conf.docker /etc/nginx/nginx.conf
|
||||
RUN rm -rf /var/www
|
||||
RUN ln -sf /opt/app/public/ /var/www
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
ARG BUILD_INFO="docker-development"
|
||||
ENV BUILD_INFO=${BUILD_INFO}
|
||||
ENV BACKEND_HOST="server"
|
||||
|
||||
CMD ["/opt/app/docker-start-dev.sh"]
|
||||
VOLUME ["/data"]
|
||||
|
||||
|
||||
FROM --platform=$BUILDPLATFORM node:lts as builder
|
||||
WORKDIR /opt/app
|
||||
|
||||
|
@ -315,7 +315,7 @@ function makeOutputDirs() {
|
||||
}
|
||||
|
||||
function watch() {
|
||||
let wss = new WebSocket.Server({ port: 8080 });
|
||||
let wss = new WebSocket.Server({ port: environment === "development" ? 8081 : 8080 });
|
||||
const liveReload = !process.argv.includes('--no-live-reload');
|
||||
|
||||
function emitReload() {
|
||||
|
@ -36,7 +36,6 @@ $button-disabled-background-color = #CCC
|
||||
$post-thumbnail-border-color = $main-color
|
||||
$post-thumbnail-no-tags-border-color = #F44
|
||||
$default-tag-category-background-color = $active-tab-background-color
|
||||
$default-pool-category-background-color = $active-tab-background-color
|
||||
$new-tag-background-color = #DFC
|
||||
$new-tag-text-color = black
|
||||
$implied-tag-background-color = #FFC
|
||||
|
@ -1,100 +1,47 @@
|
||||
@import colors
|
||||
|
||||
.pool-list
|
||||
ul
|
||||
list-style-type: none
|
||||
padding: 0
|
||||
display: flex
|
||||
align-content: flex-end
|
||||
flex-wrap: wrap
|
||||
margin: 0 -0.25em
|
||||
table
|
||||
width: 100%
|
||||
border-spacing: 0
|
||||
text-align: left
|
||||
line-height: 1.3em
|
||||
tr:hover td
|
||||
background: $top-navigation-color
|
||||
th, td
|
||||
padding: 0.1em 0.5em
|
||||
th
|
||||
white-space: nowrap
|
||||
background: $top-navigation-color
|
||||
.names
|
||||
width: 84%
|
||||
.post-count
|
||||
text-align: center
|
||||
width: 8%
|
||||
.creation-time
|
||||
text-align: center
|
||||
width: 8%
|
||||
white-space: pre
|
||||
ul
|
||||
list-style-type: none
|
||||
margin: 0
|
||||
padding: 0
|
||||
display: inline
|
||||
li
|
||||
padding: 0
|
||||
display: inline
|
||||
&:not(:last-child):after
|
||||
content: ', '
|
||||
@media (max-width: 800px)
|
||||
.posts
|
||||
display: none
|
||||
|
||||
li
|
||||
position: relative
|
||||
flex-grow: 1
|
||||
margin: 2em 1.5em 2em 1.2em
|
||||
display: inline-block
|
||||
text-align: left
|
||||
min-width: 10em
|
||||
width: 12vw
|
||||
&:not(.flexbox-dummy)
|
||||
min-height: 7.5em
|
||||
height: 9vw
|
||||
|
||||
.thumbnail-wrapper
|
||||
display: inline-block
|
||||
width: 100%
|
||||
height: 100%
|
||||
line-height: 80%
|
||||
font-size: 80%
|
||||
color: white
|
||||
outline: none
|
||||
border-right: 20px solid transparent
|
||||
&:before
|
||||
content: ' '
|
||||
display: block
|
||||
position: relative
|
||||
width: 100%
|
||||
height: 20px
|
||||
bottom: 20px
|
||||
|
||||
.thumbnail
|
||||
width: 100%
|
||||
height: 100%
|
||||
outline-offset: -2px
|
||||
background-size: cover
|
||||
transition: top .1s ease-in-out, right .1s ease-in-out
|
||||
background-position: 50% 30%
|
||||
position: absolute
|
||||
display: inline-block
|
||||
box-shadow: 0 0 0 1px rgba(0,0,0,0.2)
|
||||
|
||||
.thumbnail-1, .thumbnail.empty
|
||||
right: -4px
|
||||
top: -4px
|
||||
z-index: 30
|
||||
|
||||
.thumbnail-2
|
||||
right: -10px
|
||||
top: -10px
|
||||
z-index: 20
|
||||
|
||||
.thumbnail-3
|
||||
right: -16px
|
||||
top: -16px
|
||||
z-index: 10
|
||||
|
||||
.pool-name
|
||||
color: black
|
||||
font-size: 1em
|
||||
text-align: center
|
||||
a
|
||||
width: 100%
|
||||
display: inline-block
|
||||
|
||||
a:active, a:focus
|
||||
.thumbnail
|
||||
outline: 2px solid $main-color !important
|
||||
|
||||
.pool-list ul li:hover
|
||||
.thumbnail-wrapper
|
||||
.thumbnail-1
|
||||
right: -0px
|
||||
top: -0px
|
||||
|
||||
.thumbnail-3
|
||||
right: -20px
|
||||
top: -20px
|
||||
|
||||
.pool-list ul li:has(a:focus), .pool-list ul li:has(a:active)
|
||||
.thumbnail-wrapper
|
||||
.thumbnail-1
|
||||
right: -0px
|
||||
top: -0px
|
||||
|
||||
.thumbnail-3
|
||||
right: -20px
|
||||
top: -20px
|
||||
.darktheme .pool-list
|
||||
table
|
||||
tr:hover td
|
||||
background: $top-navigation-color-darktheme
|
||||
th
|
||||
background: $top-navigation-color-darktheme
|
||||
|
||||
.pool-list-header
|
||||
label
|
||||
@ -114,21 +61,3 @@
|
||||
.darktheme .pool-list-header
|
||||
.append
|
||||
color: $inactive-link-color-darktheme
|
||||
|
||||
.post-flow
|
||||
ul
|
||||
li
|
||||
min-width: inherit
|
||||
width: inherit
|
||||
margin: 0 0.25em 0.5em 0.25em
|
||||
&:not(.flexbox-dummy)
|
||||
height: 14vw
|
||||
.thumbnail
|
||||
position: static
|
||||
outline-offset: -1px
|
||||
.thumbnail-wrapper.no-tags
|
||||
.thumbnail
|
||||
outline: 2px solid $post-thumbnail-no-tags-border-color
|
||||
&:hover a, a:active, a:focus
|
||||
.thumbnail
|
||||
outline: 2px solid $main-color !important
|
||||
|
@ -1,39 +0,0 @@
|
||||
@import colors
|
||||
|
||||
.pool-navigator-container
|
||||
padding: 0
|
||||
margin: 0 auto
|
||||
|
||||
.pool-info-wrapper
|
||||
box-sizing: border-box
|
||||
width: 100%
|
||||
margin: 0 0 1em 0
|
||||
display: flex
|
||||
padding: 0.5em 1em
|
||||
border: 1px solid $line-color
|
||||
background: $top-navigation-color
|
||||
|
||||
.pool-name
|
||||
flex: 1 1
|
||||
text-align: center
|
||||
overflow: hidden
|
||||
white-space: nowrap
|
||||
-o-text-overflow: ellipsis
|
||||
text-overflow: ellipsis
|
||||
|
||||
.first, .last
|
||||
flex-basis: 1em
|
||||
|
||||
.first, .prev, .next, .last
|
||||
flex: 0 1
|
||||
white-space: nowrap
|
||||
|
||||
>span
|
||||
padding-top: 2px
|
||||
padding-bottom: 2px
|
||||
margin: 0 .25em
|
||||
|
||||
|
||||
.darktheme .pool-navigator-container .pool-info-wrapper
|
||||
border: 1px solid $top-navigation-color-darktheme
|
||||
background: $window-color-darktheme
|
@ -1,9 +0,0 @@
|
||||
.pool-navigators>ul
|
||||
list-style-type: none
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
>li
|
||||
margin-bottom: 1em
|
||||
&:last-child
|
||||
margin-bottom: 0
|
@ -121,6 +121,7 @@
|
||||
.thumbnail
|
||||
width: 4em
|
||||
height: 3em
|
||||
background-position: 50% 30%
|
||||
li
|
||||
margin: 0 0.3em 0.3em 0
|
||||
display: inline-block
|
||||
|
17
client/docker-start-dev.sh
Executable file
17
client/docker-start-dev.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/dumb-init /bin/sh
|
||||
|
||||
# Integrate environment variables
|
||||
sed -i "s|__BACKEND__|${BACKEND_HOST}|" \
|
||||
/etc/nginx/nginx.conf
|
||||
|
||||
# Start server
|
||||
nginx &
|
||||
|
||||
# Watch source for changes and build app
|
||||
# FIXME: It's not ergonomic to run `npm i` outside of the build step.
|
||||
# However, the mounting of different directories into the
|
||||
# client container's /opt/app causes node_modules to disappear
|
||||
# (the mounting causes client/Dockerfile's RUN npm install
|
||||
# to silently clobber).
|
||||
# Find a way to move `npm i` into client/Dockerfile.
|
||||
npm i && npm run watch -- --polling
|
@ -2,10 +2,10 @@
|
||||
|
||||
# Integrate environment variables
|
||||
sed -i "s|__BACKEND__|${BACKEND_HOST}|" \
|
||||
/etc/nginx/nginx.conf
|
||||
/etc/nginx/nginx.conf
|
||||
sed -i "s|__BASEURL__|${BASE_URL:-/}|g" \
|
||||
/var/www/index.htm \
|
||||
/var/www/manifest.json
|
||||
/var/www/index.htm \
|
||||
/var/www/manifest.json
|
||||
|
||||
# Start server
|
||||
exec nginx
|
||||
|
@ -329,10 +329,6 @@
|
||||
<td><code>feature-time</code></td>
|
||||
<td>alias of <code>feature-time</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pool</code></td>
|
||||
<td>pool order, requires pool named token</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class='pool-delete'>
|
||||
<form>
|
||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id + ' -sort:pool'}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
||||
|
||||
<ul class='input'>
|
||||
<li>
|
||||
|
@ -1,49 +0,0 @@
|
||||
<div class='pool-navigator-container'>
|
||||
<div class='pool-info-wrapper'>
|
||||
<span class='first'>
|
||||
<% if (ctx.canViewPosts && ctx.previousPost && ctx.firstPost) { %>
|
||||
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.firstPost.id, ctx.parameters) %>'>
|
||||
<% } %>
|
||||
«
|
||||
<% if (ctx.canViewPosts && ctx.previousPost && ctx.firstPost) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</span>
|
||||
<span class='prev'>
|
||||
<% if (ctx.canViewPosts && ctx.previousPost) { %>
|
||||
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.previousPost.id, ctx.parameters) %>'>
|
||||
<% } %>
|
||||
‹ prev
|
||||
<% if (ctx.canViewPosts && ctx.previousPost) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</span>
|
||||
<span class='pool-name'>
|
||||
<% if (ctx.canViewPools) { %>
|
||||
<a class='<%- ctx.linkClass %>' href='<%= ctx.formatClientLink("pool", ctx.pool.id) %>'>
|
||||
<% } %>
|
||||
Pool: <%- ctx.getPrettyName(ctx.pool.names[0]) %>
|
||||
<% if (ctx.canViewPools) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</span>
|
||||
<span class='next'>
|
||||
<% if (ctx.canViewPosts && ctx.nextPost) { %>
|
||||
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.nextPost.id, ctx.parameters) %>'>
|
||||
<% } %>
|
||||
next ›
|
||||
<% if (ctx.canViewPosts && ctx.nextPost) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</span>
|
||||
<span class='last'>
|
||||
<% if (ctx.canViewPosts && ctx.nextPost && ctx.lastPost) { %>
|
||||
<a class='<%- ctx.linkClass %>' href='<%= ctx.getPostUrl(ctx.lastPost.id, ctx.parameters) %>'>
|
||||
<% } %>
|
||||
»
|
||||
<% if (ctx.canViewPosts && ctx.nextPost && ctx.lastPost) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
@ -1,4 +0,0 @@
|
||||
<div class='pool-navigators'>
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
@ -18,6 +18,6 @@
|
||||
<section class='description'>
|
||||
<hr/>
|
||||
<%= ctx.makeMarkdown(ctx.pool.description || 'This pool has no description yet.') %>
|
||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id + ' -sort:pool'}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -1,19 +1,48 @@
|
||||
<% if (ctx.postFlow) { %><div class='pool-list post-flow'><% } else { %><div class='pool-list'><% } %>
|
||||
<div class='pool-list table-wrap'>
|
||||
<% if (ctx.response.results.length) { %>
|
||||
<ul>
|
||||
<% for (let pool of ctx.response.results) { %>
|
||||
<li data-pool-id='<%= pool.id %>'>
|
||||
<a class='thumbnail-wrapper' href='<%= ctx.canViewPools ? ctx.formatClientLink("pool", pool.id) : "" %>'>
|
||||
<% if (ctx.canViewPosts) { %>
|
||||
<%= ctx.makePoolThumbnails(pool.posts, ctx.postFlow) %>
|
||||
<table>
|
||||
<thead>
|
||||
<th class='names'>
|
||||
<% if (ctx.parameters.query == 'sort:name' || !ctx.parameters.query) { %>
|
||||
<a href='<%- ctx.formatClientLink('pools', {query: '-sort:name'}) %>'>Pool name(s)</a>
|
||||
<% } else { %>
|
||||
<a href='<%- ctx.formatClientLink('pools', {query: 'sort:name'}) %>'>Pool name(s)</a>
|
||||
<% } %>
|
||||
</a>
|
||||
<div class='pool-name'>
|
||||
<%= ctx.makePoolLink(pool.id, false, false, pool, name) %>
|
||||
</div>
|
||||
</li>
|
||||
<% } %>
|
||||
<%= ctx.makeFlexboxAlign() %>
|
||||
</ul>
|
||||
</th>
|
||||
<th class='post-count'>
|
||||
<% if (ctx.parameters.query == 'sort:post-count') { %>
|
||||
<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>
|
||||
<% } %>
|
||||
</th>
|
||||
<th class='creation-time'>
|
||||
<% if (ctx.parameters.query == 'sort:creation-time') { %>
|
||||
<a href='<%- ctx.formatClientLink('pools', {query: '-sort:creation-time'}) %>'>Created on</a>
|
||||
<% } else { %>
|
||||
<a href='<%- ctx.formatClientLink('pools', {query: 'sort:creation-time'}) %>'>Created on</a>
|
||||
<% } %>
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (let pool of ctx.response.results) { %>
|
||||
<tr>
|
||||
<td class='names'>
|
||||
<ul>
|
||||
<% for (let name of pool.names) { %>
|
||||
<li><%= ctx.makePoolLink(pool.id, false, false, pool, name) %></li>
|
||||
<% } %>
|
||||
</ul>
|
||||
</td>
|
||||
<td class='post-count'>
|
||||
<a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + pool.id}) %>'><%- pool.postCount %></a>
|
||||
</td>
|
||||
<td class='creation-time'>
|
||||
<%= ctx.makeRelativeTime(pool.creationTime) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
</div>
|
||||
|
@ -52,10 +52,6 @@
|
||||
<div class='content'>
|
||||
<div class='post-container'></div>
|
||||
|
||||
<% if (ctx.canListPools && ctx.canViewPools) { %>
|
||||
<div class='pool-navigators-container'></div>
|
||||
<% } %>
|
||||
|
||||
<div class='after-mobile-controls'>
|
||||
<% if (ctx.canCreateComments) { %>
|
||||
<h2>Add comment</h2>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const router = require("../router.js");
|
||||
const api = require("../api.js");
|
||||
const settings = require("../models/settings.js");
|
||||
const uri = require("../util/uri.js");
|
||||
const PoolList = require("../models/pool_list.js");
|
||||
const topNavigation = require("../models/top_navigation.js");
|
||||
@ -14,6 +13,7 @@ const EmptyView = require("../views/empty_view.js");
|
||||
const fields = [
|
||||
"id",
|
||||
"names",
|
||||
"posts",
|
||||
"creationTime",
|
||||
"postCount",
|
||||
"category",
|
||||
@ -100,21 +100,14 @@ class PoolListController {
|
||||
return uri.formatClientLink("pools", parameters);
|
||||
},
|
||||
requestPage: (offset, limit) => {
|
||||
const canEditPosts = api.hasPrivilege("pools:edit") || api.hasPrivilege("pools:edit:posts");
|
||||
const effectiveFields = fields.concat([canEditPosts ? "posts": "postsMicro"]);
|
||||
return PoolList.search(
|
||||
this._ctx.parameters.query,
|
||||
offset,
|
||||
limit,
|
||||
effectiveFields
|
||||
fields
|
||||
);
|
||||
},
|
||||
pageRenderer: (pageCtx) => {
|
||||
Object.assign(pageCtx, {
|
||||
canViewPosts: api.hasPrivilege("posts:view"),
|
||||
canViewPools: api.hasPrivilege("pools:view"),
|
||||
postFlow: settings.get().postFlow,
|
||||
});
|
||||
return new PoolsPageView(pageCtx);
|
||||
},
|
||||
});
|
||||
|
@ -11,7 +11,6 @@ const PostList = require("../models/post_list.js");
|
||||
const PostMainView = require("../views/post_main_view.js");
|
||||
const BasePostController = require("./base_post_controller.js");
|
||||
const EmptyView = require("../views/empty_view.js");
|
||||
const PoolNavigatorListControl = require("../controls/pool_navigator_list_control.js");
|
||||
|
||||
class PostMainController extends BasePostController {
|
||||
constructor(ctx, editMode) {
|
||||
@ -27,7 +26,6 @@ class PostMainController extends BasePostController {
|
||||
]).then(
|
||||
(responses) => {
|
||||
const [post, aroundResponse] = responses;
|
||||
let aroundPool = null;
|
||||
|
||||
// remove junk from query, but save it into history so that it can
|
||||
// be still accessed after history navigation / page refresh
|
||||
@ -41,36 +39,23 @@ class PostMainController extends BasePostController {
|
||||
)
|
||||
: uri.formatClientLink("post", ctx.parameters.id);
|
||||
router.replace(url, ctx.state, false);
|
||||
misc.splitByWhitespace(parameters.query).forEach((item) => {
|
||||
const found = item.match(/^pool:([0-9]+)/i);
|
||||
if (found) {
|
||||
const activePool = parseInt(found[1]);
|
||||
post.pools.map((pool) => {
|
||||
if (pool.id == activePool) {
|
||||
aroundPool = pool;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._post = post;
|
||||
this._view = new PostMainView({
|
||||
post: post,
|
||||
editMode: editMode,
|
||||
prevPostId: aroundPool
|
||||
? (aroundPool.previousPost ? aroundPool.previousPost.id : null)
|
||||
: (aroundResponse.prev ? aroundResponse.prev.id : null),
|
||||
nextPostId: aroundPool
|
||||
? (aroundPool.nextPost ? aroundPool.nextPost.id : null)
|
||||
: (aroundResponse.next ? aroundResponse.next.id : null),
|
||||
prevPostId: aroundResponse.prev
|
||||
? aroundResponse.prev.id
|
||||
: null,
|
||||
nextPostId: aroundResponse.next
|
||||
? aroundResponse.next.id
|
||||
: null,
|
||||
canEditPosts: api.hasPrivilege("posts:edit"),
|
||||
canDeletePosts: api.hasPrivilege("posts:delete"),
|
||||
canFeaturePosts: api.hasPrivilege("posts:feature"),
|
||||
canListComments: api.hasPrivilege("comments:list"),
|
||||
canCreateComments: api.hasPrivilege("comments:create"),
|
||||
canListPools: api.hasPrivilege("pools:list"),
|
||||
canViewPools: api.hasPrivilege("pools:view"),
|
||||
parameters: parameters,
|
||||
});
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const api = require("../api.js");
|
||||
const misc = require("../util/misc.js");
|
||||
const events = require("../events.js");
|
||||
const views = require("../util/views.js");
|
||||
|
||||
const template = views.getTemplate("pool-navigator");
|
||||
|
||||
class PoolNavigatorControl extends events.EventTarget {
|
||||
constructor(hostNode, poolPostNearby) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._poolPostNearby = poolPostNearby;
|
||||
|
||||
views.replaceContent(
|
||||
this._hostNode,
|
||||
template({
|
||||
pool: poolPostNearby,
|
||||
parameters: { query: `pool:${poolPostNearby.id}` },
|
||||
linkClass: misc.makeCssName(poolPostNearby.category, "pool"),
|
||||
canViewPosts: api.hasPrivilege("posts:view"),
|
||||
canViewPools: api.hasPrivilege("pools:view"),
|
||||
firstPost: poolPostNearby.firstPost,
|
||||
previousPost: poolPostNearby.previousPost,
|
||||
nextPost: poolPostNearby.nextPost,
|
||||
lastPost: poolPostNearby.lastPost,
|
||||
getPrettyName: misc.getPrettyName,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PoolNavigatorControl;
|
@ -1,49 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const events = require("../events.js");
|
||||
const views = require("../util/views.js");
|
||||
const PoolNavigatorControl = require("../controls/pool_navigator_control.js");
|
||||
|
||||
const template = views.getTemplate("pool-navigator-list");
|
||||
|
||||
class PoolNavigatorListControl extends events.EventTarget {
|
||||
constructor(hostNode, poolPostNearby) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._poolPostNearby = poolPostNearby;
|
||||
this._indexToNode = {};
|
||||
|
||||
for (const entry of this._poolPostNearby) {
|
||||
this._installPoolNavigatorNode(entry);
|
||||
}
|
||||
}
|
||||
|
||||
get _poolNavigatorListNode() {
|
||||
return this._hostNode;
|
||||
}
|
||||
|
||||
_installPoolNavigatorNode(poolPostNearby) {
|
||||
const poolListItemNode = document.createElement("div");
|
||||
const poolControl = new PoolNavigatorControl(
|
||||
poolListItemNode,
|
||||
poolPostNearby,
|
||||
);
|
||||
this._indexToNode[poolPostNearby.id] = poolListItemNode;
|
||||
this._poolNavigatorListNode.appendChild(poolListItemNode);
|
||||
}
|
||||
|
||||
_uninstallPoolNavigatorNode(index) {
|
||||
const poolListItemNode = this._indexToNode[index];
|
||||
poolListItemNode.parentNode.removeChild(poolListItemNode);
|
||||
}
|
||||
|
||||
_evtAdd(e) {
|
||||
this._installPoolNavigatorNode(e.detail.index);
|
||||
}
|
||||
|
||||
_evtRemove(e) {
|
||||
this._uninstallPoolNavigatorNode(e.detail.index);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PoolNavigatorListControl;
|
@ -3,7 +3,7 @@
|
||||
const config = require("./config.js");
|
||||
|
||||
if (config.environment == "development") {
|
||||
var ws = new WebSocket("ws://" + location.hostname + ":8080");
|
||||
var ws = new WebSocket("ws://" + location.hostname + ":8081");
|
||||
ws.addEventListener("open", function (event) {
|
||||
console.log("Live-reloading websocket connected.");
|
||||
});
|
||||
|
@ -36,7 +36,7 @@ class Pool extends events.EventTarget {
|
||||
}
|
||||
|
||||
get posts() {
|
||||
return this._postsMicro || this._posts;
|
||||
return this._posts;
|
||||
}
|
||||
|
||||
get postCount() {
|
||||
@ -51,22 +51,6 @@ class Pool extends events.EventTarget {
|
||||
return this._lastEditTime;
|
||||
}
|
||||
|
||||
get firstPost() {
|
||||
return this._firstPost;
|
||||
}
|
||||
|
||||
get lastPost() {
|
||||
return this._lastPost;
|
||||
}
|
||||
|
||||
get previousPost() {
|
||||
return this._previousPost;
|
||||
}
|
||||
|
||||
get nextPost() {
|
||||
return this._nextPost;
|
||||
}
|
||||
|
||||
set names(value) {
|
||||
this._names = value;
|
||||
}
|
||||
@ -185,15 +169,10 @@ class Pool extends events.EventTarget {
|
||||
_creationTime: response.creationTime,
|
||||
_lastEditTime: response.lastEditTime,
|
||||
_postCount: response.postCount || 0,
|
||||
_postsMicro: response.postsMicro,
|
||||
_firstPost: response.firstPost || null,
|
||||
_lastPost: response.lastPost || null,
|
||||
_previousPost: response.previousPost || null,
|
||||
_nextPost: response.nextPost || null,
|
||||
};
|
||||
|
||||
for (let obj of [this, this._orig]) {
|
||||
obj._posts.sync(response.posts || []);
|
||||
obj._posts.sync(response.posts);
|
||||
}
|
||||
|
||||
Object.assign(this, map);
|
||||
|
@ -40,36 +40,19 @@ function makeRelativeTime(time) {
|
||||
);
|
||||
}
|
||||
|
||||
function makeThumbnail(url, klass, extraProperties) {
|
||||
function makeThumbnail(url) {
|
||||
return makeElement(
|
||||
"span",
|
||||
url
|
||||
? {
|
||||
class: klass || "thumbnail",
|
||||
class: "thumbnail",
|
||||
style: `background-image: url(\'${url}\')`,
|
||||
}
|
||||
: { class: "thumbnail empty" },
|
||||
makeElement("img", Object.assign({ alt: "thumbnail", src: url }, extraProperties || {}))
|
||||
makeElement("img", { alt: "thumbnail", src: url })
|
||||
);
|
||||
}
|
||||
|
||||
function makePoolThumbnails(posts, postFlow) {
|
||||
if (posts.length == 0) {
|
||||
return makeThumbnail(null);
|
||||
}
|
||||
if (postFlow) {
|
||||
return makeThumbnail(posts.at(0).thumbnailUrl);
|
||||
}
|
||||
|
||||
let s = "";
|
||||
|
||||
for (let i = 0; i < Math.min(3, posts.length); i++) {
|
||||
s += makeThumbnail(posts.at(i).thumbnailUrl, "thumbnail thumbnail-" + (i+1), i === 0 ? {fetchPriority: "high"} : {});
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function makeRadio(options) {
|
||||
_imbueId(options);
|
||||
return makeElement(
|
||||
@ -271,7 +254,7 @@ function makePoolLink(id, includeHash, includeCount, pool, name) {
|
||||
misc.escapeHtml(text)
|
||||
)
|
||||
: makeElement(
|
||||
"div",
|
||||
"span",
|
||||
{ class: misc.makeCssName(category, "pool") },
|
||||
misc.escapeHtml(text)
|
||||
);
|
||||
@ -453,7 +436,6 @@ function getTemplate(templatePath) {
|
||||
makeFileSize: makeFileSize,
|
||||
makeMarkdown: makeMarkdown,
|
||||
makeThumbnail: makeThumbnail,
|
||||
makePoolThumbnails: makePoolThumbnails,
|
||||
makeRadio: makeRadio,
|
||||
makeCheckbox: makeCheckbox,
|
||||
makeSelect: makeSelect,
|
||||
|
@ -30,7 +30,7 @@ class PoolCreateView extends events.EventTarget {
|
||||
}
|
||||
|
||||
for (let node of this._formNode.querySelectorAll(
|
||||
"input, select, textarea"
|
||||
"input, select, textarea, posts"
|
||||
)) {
|
||||
node.addEventListener("change", (e) => {
|
||||
this.dispatchEvent(new CustomEvent("change"));
|
||||
|
@ -10,7 +10,6 @@ const PostContentControl = require("../controls/post_content_control.js");
|
||||
const PostNotesOverlayControl = require("../controls/post_notes_overlay_control.js");
|
||||
const PostReadonlySidebarControl = require("../controls/post_readonly_sidebar_control.js");
|
||||
const PostEditSidebarControl = require("../controls/post_edit_sidebar_control.js");
|
||||
const PoolNavigatorListControl = require("../controls/pool_navigator_list_control.js");
|
||||
const CommentControl = require("../controls/comment_control.js");
|
||||
const CommentListControl = require("../controls/comment_list_control.js");
|
||||
|
||||
@ -58,7 +57,6 @@ class PostMainView {
|
||||
this._installSidebar(ctx);
|
||||
this._installCommentForm();
|
||||
this._installComments(ctx.post.comments);
|
||||
this._installPoolNavigators(ctx);
|
||||
|
||||
const showPreviousImage = () => {
|
||||
if (ctx.prevPostId) {
|
||||
@ -139,20 +137,6 @@ class PostMainView {
|
||||
}
|
||||
}
|
||||
|
||||
_installPoolNavigators(ctx) {
|
||||
const poolNavigatorsContainerNode = document.querySelector(
|
||||
"#content-holder .pool-navigators-container"
|
||||
);
|
||||
if (!poolNavigatorsContainerNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.poolNavigatorsControl = new PoolNavigatorListControl(
|
||||
poolNavigatorsContainerNode,
|
||||
ctx.post.pools,
|
||||
);
|
||||
}
|
||||
|
||||
_installCommentForm() {
|
||||
const commentFormContainer = document.querySelector(
|
||||
"#content-holder .comment-form-container"
|
||||
|
264
client/package-lock.json
generated
264
client/package-lock.json
generated
@ -27,19 +27,13 @@
|
||||
"html-minifier": "^3.5.18",
|
||||
"jimp": "^0.13.0",
|
||||
"pretty-error": "^3.0.3",
|
||||
"stylus": "^0.59.0",
|
||||
"stylus": "^0.54.8",
|
||||
"terser": "^4.8.1",
|
||||
"underscore": "^1.12.1",
|
||||
"watchify": "^4.0.0",
|
||||
"ws": "^7.4.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz",
|
||||
"integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.3.tgz",
|
||||
@ -522,6 +516,18 @@
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"node_modules/atob": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"atob": "bin/atob.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz",
|
||||
@ -1731,6 +1737,27 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/css": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
|
||||
"integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"source-map": "^0.6.1",
|
||||
"source-map-resolve": "^0.5.2",
|
||||
"urix": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/css-parse": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
|
||||
"integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"css": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
|
||||
@ -1768,6 +1795,15 @@
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css/node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/csso": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz",
|
||||
@ -1794,6 +1830,15 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||
@ -3631,6 +3676,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
|
||||
"deprecated": "https://github.com/lydell/resolve-url#deprecated",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
@ -3646,6 +3698,12 @@
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
@ -3736,6 +3794,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-resolve": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
|
||||
"integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"atob": "^2.1.2",
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"resolve-url": "^0.2.1",
|
||||
"source-map-url": "^0.4.0",
|
||||
"urix": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-support": {
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
|
||||
@ -3745,6 +3816,12 @@
|
||||
"source-map": "^0.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-url": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
|
||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/stream-browserify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
@ -3835,15 +3912,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stylus": {
|
||||
"version": "0.59.0",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz",
|
||||
"integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==",
|
||||
"version": "0.54.8",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
|
||||
"integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@adobe/css-tools": "^4.0.1",
|
||||
"debug": "^4.3.2",
|
||||
"css-parse": "~2.0.0",
|
||||
"debug": "~3.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"mkdirp": "~1.0.4",
|
||||
"safer-buffer": "^2.1.2",
|
||||
"sax": "~1.2.4",
|
||||
"semver": "^6.3.0",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"bin": {
|
||||
@ -3851,33 +3931,28 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/stylus"
|
||||
}
|
||||
},
|
||||
"node_modules/stylus/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"node_modules/stylus/node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/stylus/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"node_modules/stylus/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/stylus/node_modules/source-map": {
|
||||
"version": "0.7.3",
|
||||
@ -4144,6 +4219,13 @@
|
||||
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
||||
"deprecated": "Please see https://github.com/lydell/urix#deprecated",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/url": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
|
||||
@ -4520,12 +4602,6 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@adobe/css-tools": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz",
|
||||
"integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.3.tgz",
|
||||
@ -4996,6 +5072,12 @@
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"atob": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true
|
||||
},
|
||||
"available-typed-arrays": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz",
|
||||
@ -6164,6 +6246,35 @@
|
||||
"randomfill": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
|
||||
"integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"source-map": "^0.6.1",
|
||||
"source-map-resolve": "^0.5.2",
|
||||
"urix": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-parse": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
|
||||
"integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
|
||||
@ -6215,6 +6326,12 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true
|
||||
},
|
||||
"define-properties": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||
@ -7712,6 +7829,12 @@
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
|
||||
"dev": true
|
||||
},
|
||||
"ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
@ -7727,6 +7850,12 @@
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
@ -7802,6 +7931,19 @@
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
|
||||
"integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"atob": "^2.1.2",
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"resolve-url": "^0.2.1",
|
||||
"source-map-url": "^0.4.0",
|
||||
"urix": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
|
||||
@ -7811,6 +7953,12 @@
|
||||
"source-map": "^0.5.6"
|
||||
}
|
||||
},
|
||||
"source-map-url": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
|
||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
||||
"dev": true
|
||||
},
|
||||
"stream-browserify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
@ -7892,31 +8040,31 @@
|
||||
}
|
||||
},
|
||||
"stylus": {
|
||||
"version": "0.59.0",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz",
|
||||
"integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==",
|
||||
"version": "0.54.8",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
|
||||
"integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@adobe/css-tools": "^4.0.1",
|
||||
"debug": "^4.3.2",
|
||||
"css-parse": "~2.0.0",
|
||||
"debug": "~3.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"mkdirp": "~1.0.4",
|
||||
"safer-buffer": "^2.1.2",
|
||||
"sax": "~1.2.4",
|
||||
"semver": "^6.3.0",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
@ -8139,6 +8287,12 @@
|
||||
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
|
||||
"dev": true
|
||||
},
|
||||
"urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
||||
"dev": true
|
||||
},
|
||||
"url": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
|
||||
|
@ -28,7 +28,7 @@
|
||||
"html-minifier": "^3.5.18",
|
||||
"jimp": "^0.13.0",
|
||||
"pretty-error": "^3.0.3",
|
||||
"stylus": "^0.59.0",
|
||||
"stylus": "^0.54.8",
|
||||
"terser": "^4.8.1",
|
||||
"underscore": "^1.12.1",
|
||||
"watchify": "^4.0.0",
|
||||
|
37
doc/API.md
37
doc/API.md
@ -975,43 +975,6 @@ data.
|
||||
|
||||
Retrieves information about posts that are before or after an existing post.
|
||||
|
||||
## Getting pools around post
|
||||
- **Request**
|
||||
|
||||
`GET /post/<id>/pools-nearby`
|
||||
|
||||
- **Output**
|
||||
|
||||
```json5
|
||||
[
|
||||
{
|
||||
"pool": <pool>,
|
||||
"firstPost": <first-post>,
|
||||
"lastPost": <last-post>,
|
||||
"nextPost": <next-post>,
|
||||
"previousPost": <previous-post>
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
- **Field meaning**
|
||||
|
||||
- `<pool>`: The associated [micro pool resource](#micro-pool).
|
||||
- `<first-post>`: A [micro post resource](#micro-post) that displays the first post in the pool.
|
||||
- `<last-post>`: A [micro post resource](#micro-post) that displays the last post in the pool.
|
||||
- `<next-post>`: A [micro post resource](#micro-post) that displays the next post in the pool.
|
||||
- `<previous-post>`: A [micro post resource](#micro-post) that displays the previous post in the pool.
|
||||
|
||||
- **Errors**
|
||||
|
||||
- the post does not exist
|
||||
- privileges are too low
|
||||
|
||||
- **Description**
|
||||
|
||||
Retrieves extra information about any pools that the post is in.
|
||||
|
||||
## Deleting post
|
||||
- **Request**
|
||||
|
||||
|
54
docker-compose.dev.yml
Normal file
54
docker-compose.dev.yml
Normal file
@ -0,0 +1,54 @@
|
||||
## Docker Compose configuration for dev iteration
|
||||
##
|
||||
## Data is transient by using named vols.
|
||||
## Run: docker-compose -f ./docker-compose.dev.yml up
|
||||
services:
|
||||
|
||||
server:
|
||||
build:
|
||||
context: ./server
|
||||
target: development
|
||||
depends_on:
|
||||
- sql
|
||||
environment:
|
||||
## These should be the names of the dependent containers listed below,
|
||||
## or FQDNs/IP addresses if these services are running outside of Docker
|
||||
POSTGRES_HOST: sql
|
||||
## Credentials for database:
|
||||
POSTGRES_USER:
|
||||
POSTGRES_PASSWORD:
|
||||
## Commented Values are Default:
|
||||
#POSTGRES_DB: defaults to same as POSTGRES_USER
|
||||
#POSTGRES_PORT: 5432
|
||||
#LOG_SQL: 0 (1 for verbose SQL logs)
|
||||
THREADS:
|
||||
volumes:
|
||||
- "data:/data"
|
||||
- "./server/:/opt/app/"
|
||||
|
||||
client:
|
||||
build:
|
||||
context: ./client
|
||||
target: development
|
||||
depends_on:
|
||||
- server
|
||||
volumes:
|
||||
- "data:/data:ro"
|
||||
- "./client/:/opt/app/"
|
||||
- "/opt/app/public/"
|
||||
ports:
|
||||
- "${PORT}:80"
|
||||
- "8081:8081"
|
||||
|
||||
sql:
|
||||
image: postgres:11-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER:
|
||||
POSTGRES_PASSWORD:
|
||||
volumes:
|
||||
- "sql:/var/lib/postgresql/data"
|
||||
|
||||
volumes:
|
||||
data:
|
||||
sql:
|
@ -61,7 +61,42 @@ ENTRYPOINT ["pytest", "--tb=short"]
|
||||
CMD ["szurubooru/"]
|
||||
|
||||
|
||||
FROM prereqs as development
|
||||
WORKDIR /opt/app
|
||||
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
|
||||
RUN apk --no-cache add \
|
||||
dumb-init \
|
||||
py3-pip \
|
||||
py3-setuptools \
|
||||
py3-waitress \
|
||||
&& pip3 install --no-cache-dir --disable-pip-version-check \
|
||||
hupper \
|
||||
&& mkdir -p /opt/app /data \
|
||||
&& addgroup -g ${PGID} app \
|
||||
&& adduser -SDH -h /opt/app -g '' -G app -u ${PUID} app \
|
||||
&& chown -R app:app /opt/app /data
|
||||
|
||||
USER app
|
||||
CMD ["/opt/app/docker-start-dev.sh"]
|
||||
|
||||
ARG PORT=6666
|
||||
ENV PORT=${PORT}
|
||||
EXPOSE ${PORT}
|
||||
|
||||
ARG THREADS=4
|
||||
ENV THREADS=${THREADS}
|
||||
|
||||
VOLUME ["/data/"]
|
||||
|
||||
|
||||
FROM prereqs as release
|
||||
|
||||
COPY ./ /opt/app/
|
||||
RUN rm -rf /opt/app/szurubooru/tests
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
ARG PUID=1000
|
||||
|
8
server/docker-start-dev.sh
Executable file
8
server/docker-start-dev.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/dumb-init /bin/sh
|
||||
set -e
|
||||
cd /opt/app
|
||||
|
||||
alembic upgrade head
|
||||
|
||||
echo "Starting szurubooru API on port ${PORT} - Running on ${THREADS} threads"
|
||||
exec hupper -m waitress --port ${PORT} --threads ${THREADS} szurubooru.facade:app
|
@ -5,10 +5,12 @@ from szurubooru import db, errors, model, rest, search
|
||||
from szurubooru.func import (
|
||||
auth,
|
||||
favorites,
|
||||
mime,
|
||||
posts,
|
||||
scores,
|
||||
serialization,
|
||||
snapshots,
|
||||
tags,
|
||||
versions,
|
||||
)
|
||||
|
||||
|
@ -108,7 +108,6 @@ class PoolSerializer(serialization.BaseSerializer):
|
||||
"lastEditTime": self.serialize_last_edit_time,
|
||||
"postCount": self.serialize_post_count,
|
||||
"posts": self.serialize_posts,
|
||||
"postsMicro": self.serialize_posts_micro,
|
||||
}
|
||||
|
||||
def serialize_id(self) -> Any:
|
||||
@ -144,14 +143,6 @@ class PoolSerializer(serialization.BaseSerializer):
|
||||
]
|
||||
]
|
||||
|
||||
def serialize_posts_micro(self) -> Any:
|
||||
posts_micro = []
|
||||
for i, rel in enumerate(self.pool.posts):
|
||||
posts_micro.append(posts.serialize_micro_post(rel, None))
|
||||
if i == 2:
|
||||
break
|
||||
return posts_micro
|
||||
|
||||
|
||||
def serialize_pool(
|
||||
pool: model.Pool, options: List[str] = []
|
||||
|
@ -1,15 +1,12 @@
|
||||
import hmac
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from itertools import tee, chain, islice
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
from szurubooru import config, db, errors, model, rest
|
||||
from szurubooru.func import (
|
||||
auth,
|
||||
comments,
|
||||
files,
|
||||
image_hash,
|
||||
@ -18,6 +15,7 @@ from szurubooru.func import (
|
||||
pools,
|
||||
scores,
|
||||
serialization,
|
||||
snapshots,
|
||||
tags,
|
||||
users,
|
||||
util,
|
||||
@ -98,13 +96,6 @@ FLAG_MAP = {
|
||||
model.Post.FLAG_SOUND: "sound",
|
||||
}
|
||||
|
||||
# https://stackoverflow.com/a/1012089
|
||||
def _get_nearby_iter(post_list):
|
||||
previous_item, current_item, next_item = tee(post_list, 3)
|
||||
previous_item = chain([None], previous_item)
|
||||
next_item = chain(islice(next_item, 1, None), [None])
|
||||
return zip(previous_item, current_item, next_item)
|
||||
|
||||
|
||||
def get_post_security_hash(id: int) -> str:
|
||||
return hmac.new(
|
||||
@ -346,10 +337,8 @@ class PostSerializer(serialization.BaseSerializer):
|
||||
]
|
||||
|
||||
def serialize_pools(self) -> List[Any]:
|
||||
if not auth.has_privilege(self.auth_user, "pools:list"):
|
||||
return []
|
||||
return [
|
||||
{**pools.serialize_micro_pool(pool), **get_pool_posts_nearby(self.post, pool)} if auth.has_privilege(self.auth_user, "pools:view") else pools.serialize_micro_pool(pool)
|
||||
pools.serialize_micro_pool(pool)
|
||||
for pool in sorted(
|
||||
self.post.pools, key=lambda pool: pool.creation_time
|
||||
)
|
||||
@ -979,38 +968,3 @@ def search_by_image(image_content: bytes) -> List[Tuple[float, model.Post]]:
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
def serialize_safe_post(
|
||||
post: Optional[model.Post]
|
||||
) -> rest.Response:
|
||||
return {"id": getattr(post, "post_id", None)} if post else None
|
||||
|
||||
|
||||
def serialize_id_post(
|
||||
post_id: Optional[int]
|
||||
) -> rest.Response:
|
||||
return serialize_safe_post(try_get_post_by_id(post_id)) if post_id else None
|
||||
|
||||
|
||||
def get_pool_posts_nearby(
|
||||
post: model.Post, pool: model.Pool
|
||||
) -> rest.Response:
|
||||
prev_post_id = None
|
||||
next_post_id = None
|
||||
first_post_id = pool.posts[0].post_id,
|
||||
last_post_id = pool.posts[-1].post_id,
|
||||
|
||||
for previous_item, current_item, next_item in _get_nearby_iter(pool.posts):
|
||||
if post.post_id == current_item.post_id:
|
||||
if previous_item != None:
|
||||
prev_post_id = previous_item.post_id
|
||||
if next_item != None:
|
||||
next_post_id = next_item.post_id
|
||||
break
|
||||
|
||||
return {
|
||||
"firstPost": serialize_id_post(first_post_id),
|
||||
"lastPost": serialize_id_post(last_post_id),
|
||||
"previousPost": serialize_id_post(prev_post_id),
|
||||
"nextPost": serialize_id_post(next_post_id),
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict, Optional, Tuple, Callable, Union
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
@ -114,26 +114,12 @@ def _pool_filter(
|
||||
query: SaQuery, criterion: Optional[criteria.BaseCriterion], negated: bool
|
||||
) -> SaQuery:
|
||||
assert criterion
|
||||
from szurubooru.search.configs import util as search_util
|
||||
subquery = db.session.query(model.PoolPost.post_id.label("foreign_id"))
|
||||
subquery = subquery.options(sa.orm.lazyload("*"))
|
||||
subquery = search_util.create_num_filter(model.PoolPost.pool_id)(subquery, criterion, False)
|
||||
subquery = subquery.subquery("t")
|
||||
expression = model.Post.post_id.in_(subquery)
|
||||
if negated:
|
||||
expression = ~expression
|
||||
return query.filter(expression)
|
||||
|
||||
|
||||
def _pool_sort(
|
||||
query: SaQuery, pool_id: Optional[int], order: str
|
||||
) -> SaQuery:
|
||||
if pool_id is None:
|
||||
return query
|
||||
db_query = query.join(model.PoolPost, sa.and_(model.PoolPost.post_id == model.Post.post_id, model.PoolPost.pool_id == pool_id))
|
||||
if order == tokens.SortToken.SORT_DESC:
|
||||
return db_query.order_by(model.PoolPost.order.desc())
|
||||
return db_query.order_by(model.PoolPost.order.asc())
|
||||
return search_util.create_subquery_filter(
|
||||
model.Post.post_id,
|
||||
model.PoolPost.post_id,
|
||||
model.PoolPost.pool_id,
|
||||
search_util.create_num_filter,
|
||||
)(query, criterion, negated)
|
||||
|
||||
|
||||
def _category_filter(
|
||||
@ -167,7 +153,6 @@ def _category_filter(
|
||||
class PostSearchConfig(BaseSearchConfig):
|
||||
def __init__(self) -> None:
|
||||
self.user = None # type: Optional[model.User]
|
||||
self.pool_id = None # type: Optional[int]
|
||||
|
||||
def on_search_query_parsed(self, search_query: SearchQuery) -> SaQuery:
|
||||
new_special_tokens = []
|
||||
@ -192,10 +177,6 @@ class PostSearchConfig(BaseSearchConfig):
|
||||
else:
|
||||
new_special_tokens.append(token)
|
||||
search_query.special_tokens = new_special_tokens
|
||||
self.pool_id = None
|
||||
for token in search_query.named_tokens:
|
||||
if token.name == "pool" and isinstance(token.criterion, criteria.PlainCriterion):
|
||||
self.pool_id = token.criterion.value
|
||||
|
||||
def create_around_query(self) -> SaQuery:
|
||||
return db.session.query(model.Post).options(sa.orm.lazyload("*"))
|
||||
@ -401,7 +382,7 @@ class PostSearchConfig(BaseSearchConfig):
|
||||
)
|
||||
|
||||
@property
|
||||
def sort_columns(self) -> Dict[str, Union[Tuple[SaColumn, str], Callable[[SaQuery], None]]]:
|
||||
def sort_columns(self) -> Dict[str, Tuple[SaColumn, str]]:
|
||||
return util.unalias_dict(
|
||||
[
|
||||
(
|
||||
@ -463,10 +444,6 @@ class PostSearchConfig(BaseSearchConfig):
|
||||
["feature-date", "feature-time"],
|
||||
(model.Post.last_feature_time, self.SORT_DESC),
|
||||
),
|
||||
(
|
||||
["pool"],
|
||||
lambda subquery, order: _pool_sort(subquery, self.pool_id, order)
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -205,7 +205,6 @@ def create_subquery_filter(
|
||||
filter_column: SaColumn,
|
||||
filter_factory: SaColumn,
|
||||
subquery_decorator: Callable[[SaQuery], None] = None,
|
||||
order: SaQuery = None,
|
||||
) -> Filter:
|
||||
filter_func = filter_factory(filter_column)
|
||||
|
||||
|
@ -181,19 +181,14 @@ class Executor:
|
||||
_format_dict_keys(self.config.sort_columns),
|
||||
)
|
||||
)
|
||||
entry = self.config.sort_columns[
|
||||
column, default_order = self.config.sort_columns[
|
||||
sort_token.name
|
||||
]
|
||||
if callable(entry):
|
||||
order = _get_order(sort_token.order, sort_token.SORT_DESC)
|
||||
db_query = entry(db_query, order)
|
||||
else:
|
||||
column, default_order = entry
|
||||
order = _get_order(sort_token.order, default_order)
|
||||
if order == sort_token.SORT_ASC:
|
||||
db_query = db_query.order_by(column.asc())
|
||||
elif order == sort_token.SORT_DESC:
|
||||
db_query = db_query.order_by(column.desc())
|
||||
order = _get_order(sort_token.order, default_order)
|
||||
if order == sort_token.SORT_ASC:
|
||||
db_query = db_query.order_by(column.asc())
|
||||
elif order == sort_token.SORT_DESC:
|
||||
db_query = db_query.order_by(column.desc())
|
||||
|
||||
db_query = self.config.finalize_query(db_query)
|
||||
return db_query
|
||||
|
@ -1,4 +1,4 @@
|
||||
from typing import Any, Callable, Union
|
||||
from typing import Any, Callable
|
||||
|
||||
SaColumn = Any
|
||||
SaQuery = Any
|
||||
|
@ -14,7 +14,6 @@ def inject_config(config_injector):
|
||||
"privileges": {
|
||||
"posts:list": model.User.RANK_REGULAR,
|
||||
"posts:view": model.User.RANK_REGULAR,
|
||||
"pools:list": model.User.RANK_REGULAR,
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -126,25 +125,3 @@ def test_trying_to_retrieve_single_without_privileges(
|
||||
context_factory(user=user_factory(rank=model.User.RANK_ANONYMOUS)),
|
||||
{"post_id": 999},
|
||||
)
|
||||
|
||||
|
||||
def test_get_pool_post_around(user_factory, post_factory, pool_factory, pool_post_factory):
|
||||
p1 = post_factory(id=1)
|
||||
p2 = post_factory(id=2)
|
||||
p3 = post_factory(id=3)
|
||||
db.session.add_all([p1, p2, p3])
|
||||
|
||||
pool = pool_factory(id=1)
|
||||
db.session.add(pool)
|
||||
|
||||
pool_posts = [pool_post_factory(pool=pool, post=p1), pool_post_factory(pool=pool, post=p2), pool_post_factory(pool=pool, post=p3)]
|
||||
db.session.add_all(pool_posts)
|
||||
|
||||
result = posts.get_pool_posts_nearby(p1, pool)
|
||||
assert result["previousPost"] == None and result["nextPost"]["id"] == 2
|
||||
|
||||
result = posts.get_pool_posts_nearby(p2, pool)
|
||||
assert result["previousPost"]["id"] == 1 and result["nextPost"]["id"] == 3
|
||||
|
||||
result = posts.get_pool_posts_nearby(p3, pool)
|
||||
assert result["previousPost"]["id"] == 2 and result["nextPost"] == None
|
||||
|
@ -105,14 +105,7 @@ def test_serialize_post(
|
||||
pool_category_factory,
|
||||
config_injector,
|
||||
):
|
||||
config_injector({
|
||||
"privileges": {
|
||||
"pools:list": model.User.RANK_REGULAR,
|
||||
"pools:view": model.User.RANK_REGULAR,
|
||||
},
|
||||
"data_url": "http://example.com/",
|
||||
"secret": "test"
|
||||
})
|
||||
config_injector({"data_url": "http://example.com/", "secret": "test"})
|
||||
with patch("szurubooru.func.comments.serialize_comment"), patch(
|
||||
"szurubooru.func.users.serialize_micro_user"
|
||||
), patch("szurubooru.func.posts.files.has"):
|
||||
@ -256,10 +249,6 @@ def test_serialize_post(
|
||||
"description": "desc",
|
||||
"category": "test-cat1",
|
||||
"postCount": 1,
|
||||
"firstPost": {"id": 1},
|
||||
"lastPost": {"id": 1},
|
||||
"previousPost": None,
|
||||
"nextPost": None,
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@ -267,10 +256,6 @@ def test_serialize_post(
|
||||
"description": "desc2",
|
||||
"category": "test-cat2",
|
||||
"postCount": 1,
|
||||
"firstPost": {"id": 1},
|
||||
"lastPost": {"id": 1},
|
||||
"previousPost": None,
|
||||
"nextPost": None,
|
||||
},
|
||||
],
|
||||
"user": "post author",
|
||||
|
@ -725,7 +725,6 @@ def test_filter_by_feature_date(
|
||||
"sort:fav-time",
|
||||
"sort:feature-date",
|
||||
"sort:feature-time",
|
||||
"sort:pool",
|
||||
],
|
||||
)
|
||||
def test_sort_tokens(verify_unpaged, post_factory, input):
|
||||
@ -866,45 +865,6 @@ def test_tumbleweed(
|
||||
verify_unpaged("-special:tumbleweed", [1, 2, 3])
|
||||
|
||||
|
||||
def test_sort_pool(
|
||||
post_factory, pool_factory, pool_category_factory, verify_unpaged
|
||||
):
|
||||
post1 = post_factory(id=1)
|
||||
post2 = post_factory(id=2)
|
||||
post3 = post_factory(id=3)
|
||||
post4 = post_factory(id=4)
|
||||
pool1 = pool_factory(
|
||||
id=1,
|
||||
names=["pool1"],
|
||||
description="desc",
|
||||
category=pool_category_factory("test-cat1"),
|
||||
)
|
||||
pool1.posts = [post1, post4, post3]
|
||||
pool2 = pool_factory(
|
||||
id=2,
|
||||
names=["pool2"],
|
||||
description="desc",
|
||||
category=pool_category_factory("test-cat2"),
|
||||
)
|
||||
pool2.posts = [post3, post4, post2]
|
||||
db.session.add_all(
|
||||
[
|
||||
post1,
|
||||
post2,
|
||||
post3,
|
||||
post4,
|
||||
pool1,
|
||||
pool2
|
||||
]
|
||||
)
|
||||
db.session.flush()
|
||||
verify_unpaged("pool:1 sort:pool", [1, 4, 3])
|
||||
verify_unpaged("pool:2 sort:pool", [3, 4, 2])
|
||||
verify_unpaged("pool:1 pool:2 sort:pool", [4, 3])
|
||||
verify_unpaged("pool:2 pool:1 sort:pool", [3, 4])
|
||||
verify_unpaged("sort:pool", [1, 2, 3, 4])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,expected_post_ids",
|
||||
[
|
||||
|
Reference in New Issue
Block a user