mirror of
https://github.com/rr-/szurubooru.git
synced 2025-07-17 08:26:24 +00:00
Compare commits
2 Commits
c2afeab96b
...
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() {
|
||||
|
@ -121,6 +121,7 @@
|
||||
.thumbnail
|
||||
width: 4em
|
||||
height: 3em
|
||||
background-position: 50% 30%
|
||||
li
|
||||
margin: 0 0.3em 0.3em 0
|
||||
display: inline-block
|
||||
|
@ -15,13 +15,10 @@ $cancel-button-color = tomato
|
||||
&.inactive .skip-duplicates
|
||||
&.inactive .always-upload-similar
|
||||
&.inactive .pause-remain-on-error
|
||||
&.inactive .upload-all-anonymous
|
||||
&.inactive #common-tags,
|
||||
&.uploading input[type=submit],
|
||||
&.uploading .skip-duplicates,
|
||||
&.uploading .always-upload-similar
|
||||
&.uploading .pause-remain-on-error
|
||||
&.uploading .upload-all-anonymous
|
||||
&:not(.uploading) .cancel
|
||||
display: none
|
||||
|
||||
@ -33,9 +30,6 @@ $cancel-button-color = tomato
|
||||
small
|
||||
font-size: 60%
|
||||
|
||||
label[for=common-tags]
|
||||
display: none !important
|
||||
|
||||
input[type=submit]
|
||||
margin-top: 1em
|
||||
|
||||
@ -55,21 +49,9 @@ $cancel-button-color = tomato
|
||||
.pause-remain-on-error
|
||||
margin-left: 1em
|
||||
|
||||
.upload-all-anonymous
|
||||
margin-left: 1em
|
||||
|
||||
form>.messages
|
||||
margin-top: 1em
|
||||
|
||||
.control-strip
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.5em
|
||||
|
||||
.control-options
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
.uploadables-container
|
||||
list-style-type: none
|
||||
margin: 0
|
||||
|
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
|
||||
|
@ -5,41 +5,29 @@
|
||||
<div class='control-strip'>
|
||||
<input type='submit' value='Upload all' class='submit'/>
|
||||
|
||||
<div class='control-options'>
|
||||
<span class='skip-duplicates'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Skip duplicate',
|
||||
name: 'skip-duplicates',
|
||||
checked: false,
|
||||
}) %>
|
||||
</span>
|
||||
<span class='skip-duplicates'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Skip duplicate',
|
||||
name: 'skip-duplicates',
|
||||
checked: false,
|
||||
}) %>
|
||||
</span>
|
||||
|
||||
<span class='always-upload-similar'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Force upload similar',
|
||||
name: 'always-upload-similar',
|
||||
checked: false,
|
||||
}) %>
|
||||
</span>
|
||||
<span class='always-upload-similar'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Force upload similar',
|
||||
name: 'always-upload-similar',
|
||||
checked: false,
|
||||
}) %>
|
||||
</span>
|
||||
|
||||
<span class='pause-remain-on-error'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Pause on error',
|
||||
name: 'pause-remain-on-error',
|
||||
checked: true,
|
||||
}) %>
|
||||
</span>
|
||||
|
||||
<span class='upload-all-anonymous'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Upload anonymously',
|
||||
name: 'upload-all-anonymous',
|
||||
checked: false,
|
||||
}) %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags'}) %>
|
||||
<span class='pause-remain-on-error'>
|
||||
<%= ctx.makeCheckbox({
|
||||
text: 'Pause on error',
|
||||
name: 'pause-remain-on-error',
|
||||
checked: true,
|
||||
}) %>
|
||||
</span>
|
||||
|
||||
<input type='button' value='Cancel' class='cancel'/>
|
||||
</div>
|
||||
|
@ -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.");
|
||||
});
|
||||
|
@ -8,10 +8,6 @@ const FileDropperControl = require("../controls/file_dropper_control.js");
|
||||
const template = views.getTemplate("post-upload");
|
||||
const rowTemplate = views.getTemplate("post-upload-row");
|
||||
|
||||
const misc = require('../util/misc.js');
|
||||
const TagAutoCompleteControl =
|
||||
require('../controls/tag_auto_complete_control.js');
|
||||
|
||||
function _mimeTypeToPostType(mimeType) {
|
||||
return (
|
||||
{
|
||||
@ -189,16 +185,6 @@ class PostUploadView extends events.EventTarget {
|
||||
this._evtFormSubmit(e)
|
||||
);
|
||||
this._formNode.classList.add("inactive");
|
||||
|
||||
if (this._commonTagsInputNode) {
|
||||
this._autoCompleteControl = new TagAutoCompleteControl(
|
||||
this._commonTagsInputNode,
|
||||
{
|
||||
confirm: tag =>
|
||||
this._autoCompleteControl.replaceSelectedText(
|
||||
misc.escapeSearchTerm(tag.names[0]), true),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enableForm() {
|
||||
@ -313,18 +299,14 @@ class PostUploadView extends events.EventTarget {
|
||||
uploadable.safety = safetyNode.value;
|
||||
}
|
||||
|
||||
let anonymous = this._uploadAllAnonymous.checked;
|
||||
if (!anonymous) {
|
||||
anonymous = rowNode.querySelector(".anonymous input:checked");
|
||||
const anonymousNode = rowNode.querySelector(
|
||||
".anonymous input:checked"
|
||||
);
|
||||
if (anonymousNode) {
|
||||
uploadable.anonymous = true;
|
||||
}
|
||||
uploadable.anonymous = anonymous;
|
||||
|
||||
uploadable.tags = [];
|
||||
if (this._commonTagsInputNode) {
|
||||
var tags = this._commonTagsInputNode.value.split(' ');
|
||||
tags = tags.filter(t => t != "").map(t => t.replace('\\', ''));
|
||||
uploadable.tags = uploadable.tags.concat(tags);
|
||||
}
|
||||
uploadable.relations = [];
|
||||
for (let [i, lookalike] of uploadable.lookalikes.entries()) {
|
||||
let lookalikeNode = rowNode.querySelector(
|
||||
@ -459,10 +441,6 @@ class PostUploadView extends events.EventTarget {
|
||||
);
|
||||
}
|
||||
|
||||
get _uploadAllAnonymous() {
|
||||
return this._hostNode.querySelector("form [name=upload-all-anonymous]");
|
||||
}
|
||||
|
||||
get _submitButtonNode() {
|
||||
return this._hostNode.querySelector("form [type=submit]");
|
||||
}
|
||||
@ -474,10 +452,6 @@ class PostUploadView extends events.EventTarget {
|
||||
get _contentInputNode() {
|
||||
return this._formNode.querySelector(".dropper-container");
|
||||
}
|
||||
|
||||
get _commonTagsInputNode() {
|
||||
return this._formNode.querySelector('form [name=common-tags]');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PostUploadView;
|
||||
|
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
|
Reference in New Issue
Block a user