Compare commits
128 Commits
feature/on
...
feature/sl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
725dffc458 | ||
|
|
22783b837e | ||
|
|
ba18fe692f | ||
|
|
387a989caa | ||
|
|
ffab48cff0 | ||
|
|
17bf7cb140 | ||
|
|
408d837a0f | ||
|
|
56e1083ada | ||
|
|
2aa3d629da | ||
|
|
6779341db3 | ||
|
|
10a0de0637 | ||
|
|
b3185a8d18 | ||
|
|
2db6cbe6fd | ||
|
|
9bc6e0b555 | ||
|
|
98a3eeba7c | ||
|
|
de97b08f01 | ||
|
|
f2dc970731 | ||
|
|
2f8e724104 | ||
|
|
a3ab537de0 | ||
|
|
b04c4fa42d | ||
|
|
078be4ba35 | ||
|
|
c1f186a3da | ||
|
|
7aaeb0f368 | ||
|
|
b475e76189 | ||
|
|
8b6f5e8e18 | ||
|
|
695ece9165 | ||
|
|
7013161872 | ||
|
|
f19270b276 | ||
|
|
cd4955cce8 | ||
|
|
4d03946a08 | ||
|
|
60f7d063b6 | ||
|
|
a57c2c6e20 | ||
|
|
6a5445a525 | ||
|
|
40a2e6b1b4 | ||
|
|
4b48ebda90 | ||
|
|
09f498c6b3 | ||
|
|
781bac0ffa | ||
|
|
377a28c070 | ||
|
|
0046f2f494 | ||
|
|
7239b8cbdc | ||
|
|
0008d0215e | ||
|
|
2f69e48ef8 | ||
|
|
58a9903a8f | ||
|
|
0dbd8087eb | ||
|
|
ba3440b169 | ||
|
|
8a010cf3a3 | ||
|
|
e7610928e2 | ||
|
|
522b65f8ef | ||
|
|
3c90a8ca79 | ||
|
|
abd7894b6f | ||
|
|
eaaca163a0 | ||
|
|
1c4fa92c97 | ||
|
|
42b5f05c8f | ||
|
|
59701a4af8 | ||
|
|
5f1d3ba307 | ||
|
|
985675e012 | ||
|
|
f372b31b9d | ||
|
|
9612926230 | ||
|
|
57adf0c679 | ||
|
|
c28e98ec18 | ||
|
|
f27c86e29a | ||
|
|
ec94a47c8c | ||
|
|
362587d852 | ||
|
|
25f161d2b0 | ||
|
|
e5c5bbfbb4 | ||
|
|
4044e857bc | ||
|
|
f4348600e2 | ||
|
|
028f9b35a6 | ||
|
|
50d5fd21e0 | ||
|
|
a75bf333bd | ||
|
|
47975cb1a6 | ||
|
|
2ae9425b6a | ||
|
|
00b4d528c9 | ||
|
|
e58a3176ac | ||
|
|
205b0173a7 | ||
|
|
6235231db5 | ||
|
|
af61705482 | ||
|
|
46c7b3be11 | ||
|
|
547286b2e3 | ||
|
|
f68db94d91 | ||
|
|
16da296f79 | ||
|
|
d5ad562d2c | ||
|
|
c2126419d4 | ||
|
|
7028770f40 | ||
|
|
350fd29622 | ||
|
|
a6aef681a7 | ||
|
|
5256872646 | ||
|
|
ae47e5268b | ||
|
|
4b4844ecaa | ||
|
|
0ead8ce4b3 | ||
|
|
d568a235eb | ||
|
|
c3ce7d9f3a | ||
|
|
4d0ba8ef9a | ||
|
|
2f368e0a34 | ||
|
|
ad0041ba84 | ||
|
|
561d576934 | ||
|
|
a642daf77a | ||
|
|
7018f03c34 | ||
|
|
7da56c81fc | ||
|
|
2b7930a5b7 | ||
|
|
d556034349 | ||
|
|
d8341455a2 | ||
|
|
f5c7b9f0e3 | ||
|
|
a86d033f20 | ||
|
|
1fd51b00ed | ||
|
|
95ec9adfcd | ||
|
|
3446f57478 | ||
|
|
dd607af1ae | ||
|
|
ea4bb8d98e | ||
|
|
61687e3158 | ||
|
|
ca977ffec3 | ||
|
|
f539493bf5 | ||
|
|
6ffce26b08 | ||
|
|
a9f9f9d74a | ||
|
|
b338b0a08f | ||
|
|
1a4f16eaef | ||
|
|
2521aa98af | ||
|
|
a6d20a0a73 | ||
|
|
df75fbaa1b | ||
|
|
5f1a45082e | ||
|
|
9e2b6a4115 | ||
|
|
91febde2a3 | ||
|
|
b548dc011d | ||
|
|
88b8f675c1 | ||
|
|
693b1ac23f | ||
|
|
7ec12a5958 | ||
|
|
3a15406771 | ||
|
|
cc27256b14 |
23
.github/workflows/build-portal-image.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: Docker image build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the Docker image
|
||||
run: >-
|
||||
docker build . \
|
||||
--build-arg=BUILD_SERIES=dev \
|
||||
--build-arg=BUILD_ID="$(echo "$GITHUB_SHA" | head -c 12)" \
|
||||
--tag snikket/snikket-web-portal:dev
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}" | docker login -u snikket --password-stdin
|
||||
- name: Push the Docker image
|
||||
run: docker push snikket/snikket-web-portal:dev
|
||||
31
.github/workflows/build-portal-release-image.yml
vendored
@@ -1,31 +0,0 @@
|
||||
---
|
||||
name: Docker release image build
|
||||
|
||||
"on":
|
||||
push:
|
||||
tags:
|
||||
- release/*.*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the Docker image
|
||||
run: >-
|
||||
echo "Building ref $GITHUB_REF...";
|
||||
RELEASE_TAG="${GITHUB_REF#refs/tags/release/}";
|
||||
RELEASE_SERIES="${RELEASE_TAG%.*}";
|
||||
RELEASE_VER="${RELEASE_TAG#$RELEASE_SERIES.}";
|
||||
docker build . \
|
||||
--build-arg=BUILD_SERIES="$RELEASE_SERIES" \
|
||||
--build-arg=BUILD_ID="$RELEASE_VER" \
|
||||
--tag snikket/snikket-web-portal:"$RELEASE_SERIES"
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}" | docker login -u snikket --password-stdin
|
||||
- name: Push the Docker image
|
||||
run: >-
|
||||
RELEASE_TAG="${GITHUB_REF#refs/tags/release/}";
|
||||
RELEASE_SERIES="${RELEASE_TAG%.*}";
|
||||
docker push snikket/snikket-web-portal:"$RELEASE_SERIES"
|
||||
9
.github/workflows/main.yaml
vendored
@@ -48,3 +48,12 @@ jobs:
|
||||
- name: Linting
|
||||
run: |
|
||||
python -m flake8 snikket_web
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the Docker image
|
||||
run: >-
|
||||
docker build .
|
||||
|
||||
38
Dockerfile
@@ -3,44 +3,28 @@ FROM debian:buster
|
||||
ARG BUILD_SERIES=dev
|
||||
ARG BUILD_ID=0
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
COPY requirements.txt /opt/snikket-web-portal/requirements.txt
|
||||
COPY build-requirements.txt /opt/snikket-web-portal/build-requirements.txt
|
||||
COPY Makefile /opt/snikket-web-portal/Makefile
|
||||
COPY snikket_web/ /opt/snikket-web-portal/snikket_web
|
||||
COPY babel.cfg /opt/snikket-web-portal/babel.cfg
|
||||
|
||||
# This Dockerfile attempts to strike a balance between image size and time it
|
||||
# takes to do an incremental build on changes.
|
||||
# Improvements welcome.
|
||||
WORKDIR /opt/snikket-web-portal
|
||||
|
||||
RUN set -eu; \
|
||||
export DEBIAN_FRONTEND=noninteractive ; \
|
||||
apt-get update ; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
python3 python3-pip python3-setuptools python3-wheel \
|
||||
libpython3-dev \
|
||||
make build-essential \
|
||||
; \
|
||||
apt-get clean ; rm -rf /var/lib/apt/lists
|
||||
|
||||
COPY requirements.txt /opt/snikket-web-portal/requirements.txt
|
||||
COPY build-requirements.txt /opt/snikket-web-portal/build-requirements.txt
|
||||
|
||||
WORKDIR /opt/snikket-web-portal
|
||||
|
||||
RUN set -eu; \
|
||||
pip3 install -r requirements.txt; \
|
||||
pip3 install -r build-requirements.txt; \
|
||||
rm -rf /root/.cache;
|
||||
|
||||
COPY Makefile /opt/snikket-web-portal/Makefile
|
||||
COPY snikket_web/ /opt/snikket-web-portal/snikket_web
|
||||
COPY babel.cfg /opt/snikket-web-portal/babel.cfg
|
||||
|
||||
# NOTE: abusing true(1) as a terrible way to disable a specific command. If
|
||||
# one merged all the RUN commands into one, one would want to run the
|
||||
# uninstall/remove commands there, but with the split up RUN commands it is
|
||||
# rather pointless.
|
||||
RUN set -eu; \
|
||||
make; \
|
||||
true pip3 uninstall -yr build-requirements.txt; \
|
||||
true apt-get remove -y build-essential make libpython3-dev; \
|
||||
true apt-get autoremove -y; \
|
||||
pip3 uninstall -yr build-requirements.txt; \
|
||||
apt-get remove -y build-essential make libpython3-dev; \
|
||||
apt-get autoremove -y; \
|
||||
pip3 install hypercorn; \
|
||||
rm -rf /root/.cache; \
|
||||
apt-get clean ; rm -rf /var/lib/apt/lists
|
||||
@@ -48,5 +32,7 @@ RUN set -eu; \
|
||||
COPY docker/env.py /etc/snikket-web-portal/env.py
|
||||
ENV SNIKKET_WEB_PYENV=/etc/snikket-web-portal/env.py
|
||||
|
||||
ENV SNIKKET_WEB_PROSODY_ENDPOINT=http://127.0.0.1:5280/
|
||||
|
||||
ADD docker/entrypoint.sh /entrypoint.sh
|
||||
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
|
||||
|
||||
2
Makefile
@@ -31,7 +31,7 @@ force_update_translations: extract_translations
|
||||
pybabel update -i $(pot_file) -d $(translation_basepath)
|
||||
|
||||
compile_translations:
|
||||
pybabel compile -d $(translation_basepath)
|
||||
-pybabel compile -d $(translation_basepath)
|
||||
|
||||
|
||||
.PHONY: build_css clean update_translations compile_translations extract_translations force_update_translations
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
#!/bin/sh
|
||||
exec hypercorn -b "0.0.0.0:8000" 'snikket_web:create_app()'
|
||||
|
||||
export SNIKKET_WEB_DOMAIN="$SNIKKET_DOMAIN"
|
||||
|
||||
exec hypercorn -b "127.0.0.1:5765" 'snikket_web:create_app()'
|
||||
|
||||
761
docs/colours.svg
@@ -1,6 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
@@ -9,426 +7,363 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="334mm"
|
||||
height="154mm"
|
||||
viewBox="0 0 334 154"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="colours.svg"
|
||||
inkscape:export-filename="/home/horazont/tmp/colours.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="642.84838"
|
||||
inkscape:cy="251.88403"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1401"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="39"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="5"
|
||||
fit-margin-left="5"
|
||||
fit-margin-right="5"
|
||||
fit-margin-bottom="5" />
|
||||
id="svg1424"
|
||||
sodipodi:docname="out.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata5">
|
||||
id="metadata1430">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(65,-148)">
|
||||
<rect
|
||||
style="opacity:1;fill:#418fc7;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4759"
|
||||
width="24"
|
||||
height="24"
|
||||
x="120"
|
||||
y="273" />
|
||||
<rect
|
||||
y="273"
|
||||
x="-2.7815501e-08"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9362"
|
||||
style="opacity:1;fill:#062943;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="273"
|
||||
x="240"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9364"
|
||||
style="opacity:1;fill:#e4f3fd;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="273"
|
||||
x="60"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9366"
|
||||
style="opacity:1;fill:#0e4c76;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#9dccf0;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9368"
|
||||
width="24"
|
||||
height="24"
|
||||
x="180"
|
||||
y="273" />
|
||||
<rect
|
||||
style="opacity:1;fill:#0f3d62;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9370"
|
||||
width="24"
|
||||
height="24"
|
||||
x="30"
|
||||
y="273" />
|
||||
<rect
|
||||
y="273"
|
||||
x="90"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9372"
|
||||
style="opacity:1;fill:#226494;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="273"
|
||||
x="150"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9376"
|
||||
style="opacity:1;fill:#72b2e3;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="273"
|
||||
x="210"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9378"
|
||||
style="opacity:1;fill:#b5d8f3;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="243"
|
||||
x="120"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9380"
|
||||
style="opacity:1;fill:#c95e40;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#340e03;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9382"
|
||||
width="24"
|
||||
height="24"
|
||||
x="0"
|
||||
y="243" />
|
||||
<rect
|
||||
style="opacity:1;fill:#fef1ed;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9384"
|
||||
width="24"
|
||||
height="24"
|
||||
x="240"
|
||||
y="243" />
|
||||
<rect
|
||||
style="opacity:1;fill:#e2b00c;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9436"
|
||||
width="24"
|
||||
height="24"
|
||||
x="120"
|
||||
y="213" />
|
||||
<rect
|
||||
style="opacity:1;fill:#f2ac99;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9454"
|
||||
width="24"
|
||||
height="24"
|
||||
x="180"
|
||||
y="243" />
|
||||
<rect
|
||||
y="243"
|
||||
x="210"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9456"
|
||||
style="opacity:1;fill:#fbc2b3;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="243"
|
||||
x="150"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9458"
|
||||
style="opacity:1;fill:#ed947c;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#883017;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9460"
|
||||
width="24"
|
||||
height="24"
|
||||
x="60"
|
||||
y="243" />
|
||||
<rect
|
||||
y="243"
|
||||
x="30"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9462"
|
||||
style="opacity:1;fill:#681f0b;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="243"
|
||||
x="90"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9464"
|
||||
style="opacity:1;fill:#a33d21;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="183"
|
||||
x="120"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9466"
|
||||
style="opacity:1;fill:#55c644;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="213"
|
||||
x="240"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9484"
|
||||
style="opacity:1;fill:#fffcf0;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="213"
|
||||
x="0"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9486"
|
||||
style="opacity:1;fill:#302100;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="213"
|
||||
x="60"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9488"
|
||||
style="opacity:1;fill:#886600;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#563600;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9490"
|
||||
width="24"
|
||||
height="24"
|
||||
x="30"
|
||||
y="213" />
|
||||
<rect
|
||||
y="213"
|
||||
x="90"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9494"
|
||||
style="opacity:1;fill:#b98601;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="213"
|
||||
x="180"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9496"
|
||||
style="opacity:1;fill:#feed93;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="213"
|
||||
x="150"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9500"
|
||||
style="opacity:1;fill:#fde58a;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#fff7c2;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9502"
|
||||
width="24"
|
||||
height="24"
|
||||
x="210"
|
||||
y="213" />
|
||||
<rect
|
||||
style="opacity:1;fill:#8f8983;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9504"
|
||||
width="24"
|
||||
height="24"
|
||||
x="120"
|
||||
y="153" />
|
||||
<rect
|
||||
y="153"
|
||||
x="0"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9506"
|
||||
style="opacity:1;fill:#1f1b17;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="153"
|
||||
x="240"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9508"
|
||||
style="opacity:1;fill:#f6f5f4;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="153"
|
||||
x="180"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9510"
|
||||
style="opacity:1;fill:#cac3bd;fill-opacity:0.98872178;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#e3e1df;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9512"
|
||||
width="24"
|
||||
height="24"
|
||||
x="210"
|
||||
y="153" />
|
||||
<rect
|
||||
style="opacity:1;fill:#4e4a46;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9514"
|
||||
width="24"
|
||||
height="24"
|
||||
x="60"
|
||||
y="153" />
|
||||
<rect
|
||||
y="153"
|
||||
x="30"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9516"
|
||||
style="opacity:1;fill:#3d3833;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#706965;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9518"
|
||||
width="24"
|
||||
height="24"
|
||||
x="90"
|
||||
y="153" />
|
||||
<rect
|
||||
y="153"
|
||||
x="150"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9520"
|
||||
style="opacity:1;fill:#b1aca6;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ecfbe6;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9522"
|
||||
width="24"
|
||||
height="24"
|
||||
x="240"
|
||||
y="183" />
|
||||
<rect
|
||||
style="opacity:1;fill:#052f03;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9524"
|
||||
width="24"
|
||||
height="24"
|
||||
x="0"
|
||||
y="183" />
|
||||
<rect
|
||||
style="opacity:1;fill:#197713;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9526"
|
||||
width="24"
|
||||
height="24"
|
||||
x="60"
|
||||
y="183" />
|
||||
<rect
|
||||
y="183"
|
||||
x="30"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9528"
|
||||
style="opacity:1;fill:#0c4608;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="183"
|
||||
x="90"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9530"
|
||||
style="opacity:1;fill:#218a1b;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#abed9c;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9532"
|
||||
width="24"
|
||||
height="24"
|
||||
x="180"
|
||||
y="183" />
|
||||
<rect
|
||||
style="opacity:1;fill:#81e06e;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect9536"
|
||||
width="24"
|
||||
height="24"
|
||||
x="150"
|
||||
y="183" />
|
||||
<rect
|
||||
y="183"
|
||||
x="210"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect9538"
|
||||
style="opacity:1;fill:#cef6c5;fill-opacity:1;stroke:none;stroke-width:0.32483485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;line-height:1em;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-3.4391122"
|
||||
y="170.58151"
|
||||
id="text9546"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9544"
|
||||
x="-3.4391129"
|
||||
y="170.58151"
|
||||
style="stroke-width:0.26458332px">Grayscale</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;line-height:1em;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-12.554834"
|
||||
y="200.5157"
|
||||
id="text9550"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9548"
|
||||
x="-12.554835"
|
||||
y="200.5157"
|
||||
style="stroke-width:0.26458332px">Success</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;line-height:1em;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-21.180664"
|
||||
y="230.71715"
|
||||
id="text9554"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9552"
|
||||
x="-21.180664"
|
||||
y="230.71715"
|
||||
style="stroke-width:0.26458332px">Accent</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;line-height:1em;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-33.880665"
|
||||
y="261.45316"
|
||||
id="text9558"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9556"
|
||||
x="-33.880665"
|
||||
y="261.45316"
|
||||
style="stroke-width:0.26458332px">Alert</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;line-height:1em;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-17.236719"
|
||||
y="290.85278"
|
||||
id="text9562"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9560"
|
||||
x="-17.236719"
|
||||
y="290.85278"
|
||||
style="stroke-width:0.26458332px">Primary</tspan></text>
|
||||
</g>
|
||||
<defs
|
||||
id="defs1428" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1401"
|
||||
id="namedview1426"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.9666667"
|
||||
inkscape:cx="123.61033"
|
||||
inkscape:cy="67.707413"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="39"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1424" />
|
||||
<rect
|
||||
style="fill: #000000;"
|
||||
width="310"
|
||||
height="240"
|
||||
x="-25"
|
||||
y="-25"
|
||||
id="rect1332" />
|
||||
<rect
|
||||
style="fill: #1f1b17;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="0"
|
||||
y="0"
|
||||
id="rect1334" />
|
||||
<rect
|
||||
style="fill: #3d3833;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="30"
|
||||
y="0"
|
||||
id="rect1336" />
|
||||
<rect
|
||||
style="fill: #4e4a46;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="60"
|
||||
y="0"
|
||||
id="rect1338" />
|
||||
<rect
|
||||
style="fill: #706965;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="90"
|
||||
y="0"
|
||||
id="rect1340" />
|
||||
<rect
|
||||
style="fill: #8f8983;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="120"
|
||||
y="0"
|
||||
id="rect1342" />
|
||||
<rect
|
||||
style="fill: #b1aca6;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="150"
|
||||
y="0"
|
||||
id="rect1344" />
|
||||
<rect
|
||||
style="fill: #cac3bd;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="180"
|
||||
y="0"
|
||||
id="rect1346" />
|
||||
<rect
|
||||
style="fill: #e3e1df;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="210"
|
||||
y="0"
|
||||
id="rect1348" />
|
||||
<rect
|
||||
style="fill: #f6f5f4;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="240"
|
||||
y="0"
|
||||
id="rect1350" />
|
||||
<rect
|
||||
style="fill:#062243;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="0"
|
||||
y="40"
|
||||
id="rect1352" />
|
||||
<rect
|
||||
style="fill:#0f3462;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="30"
|
||||
y="40"
|
||||
id="rect1354" />
|
||||
<rect
|
||||
style="fill:#0e4276;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="60"
|
||||
y="40"
|
||||
id="rect1356" />
|
||||
<rect
|
||||
style="fill:#225994;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="90"
|
||||
y="40"
|
||||
id="rect1358" />
|
||||
<rect
|
||||
style="fill:#4182c7;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="120"
|
||||
y="40"
|
||||
id="rect1360" />
|
||||
<rect
|
||||
style="fill:#72a7e3;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="150"
|
||||
y="40"
|
||||
id="rect1362" />
|
||||
<rect
|
||||
style="fill:#9dc4f0;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="180"
|
||||
y="40"
|
||||
id="rect1364" />
|
||||
<rect
|
||||
style="fill:#b5d2f3;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="210"
|
||||
y="40"
|
||||
id="rect1366" />
|
||||
<rect
|
||||
style="fill:#e4f0fd;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="240"
|
||||
y="40"
|
||||
id="rect1368" />
|
||||
<rect
|
||||
style="fill: #340e03;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="0"
|
||||
y="80"
|
||||
id="rect1370" />
|
||||
<rect
|
||||
style="fill: #681f0b;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="30"
|
||||
y="80"
|
||||
id="rect1372" />
|
||||
<rect
|
||||
style="fill: #883017;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="60"
|
||||
y="80"
|
||||
id="rect1374" />
|
||||
<rect
|
||||
style="fill: #a33d21;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="90"
|
||||
y="80"
|
||||
id="rect1376" />
|
||||
<rect
|
||||
style="fill: #c95e40;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="120"
|
||||
y="80"
|
||||
id="rect1378" />
|
||||
<rect
|
||||
style="fill: #ed947c;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="150"
|
||||
y="80"
|
||||
id="rect1380" />
|
||||
<rect
|
||||
style="fill: #f2ac99;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="180"
|
||||
y="80"
|
||||
id="rect1382" />
|
||||
<rect
|
||||
style="fill: #fbc2b3;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="210"
|
||||
y="80"
|
||||
id="rect1384" />
|
||||
<rect
|
||||
style="fill: #fef1ed;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="240"
|
||||
y="80"
|
||||
id="rect1386" />
|
||||
<rect
|
||||
style="fill: #302100;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="0"
|
||||
y="120"
|
||||
id="rect1388" />
|
||||
<rect
|
||||
style="fill: #563600;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="30"
|
||||
y="120"
|
||||
id="rect1390" />
|
||||
<rect
|
||||
style="fill: #795b00;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="60"
|
||||
y="120"
|
||||
id="rect1392" />
|
||||
<rect
|
||||
style="fill: #a07501;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="90"
|
||||
y="120"
|
||||
id="rect1394" />
|
||||
<rect
|
||||
style="fill: #c79b0e;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="120"
|
||||
y="120"
|
||||
id="rect1396" />
|
||||
<rect
|
||||
style="fill: #f4ce3f;"
|
||||
width="20"
|
||||
height="20"
|
||||
x="150"
|
||||
y="120"
|
||||
id="rect1398" />
|
||||
<rect
|
||||
style="fill:#fee577;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="180"
|
||||
y="120"
|
||||
id="rect1400" />
|
||||
<rect
|
||||
style="fill:#fef1c1;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="210"
|
||||
y="120"
|
||||
id="rect1402" />
|
||||
<rect
|
||||
style="fill:#fff8e8;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="240"
|
||||
y="120"
|
||||
id="rect1404" />
|
||||
<rect
|
||||
style="fill:#172f03;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="0"
|
||||
y="160"
|
||||
id="rect1406" />
|
||||
<rect
|
||||
style="fill:#244608;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="30"
|
||||
y="160"
|
||||
id="rect1408" />
|
||||
<rect
|
||||
style="fill:#407713;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="60"
|
||||
y="160"
|
||||
id="rect1410" />
|
||||
<rect
|
||||
style="fill:#548f19;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="90"
|
||||
y="160"
|
||||
id="rect1412" />
|
||||
<rect
|
||||
style="fill:#7fc644;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="120"
|
||||
y="160"
|
||||
id="rect1414" />
|
||||
<rect
|
||||
style="fill:#a1e06e;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="150"
|
||||
y="160"
|
||||
id="rect1416" />
|
||||
<rect
|
||||
style="fill:#c0ed9c;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="180"
|
||||
y="160"
|
||||
id="rect1418" />
|
||||
<rect
|
||||
style="fill:#dbf6c5;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="210"
|
||||
y="160"
|
||||
id="rect1420" />
|
||||
<rect
|
||||
style="fill:#effbe6;fill-opacity:1"
|
||||
width="20"
|
||||
height="20"
|
||||
x="240"
|
||||
y="160"
|
||||
id="rect1422" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 421 KiB |
@@ -15,6 +15,7 @@ from quart import (
|
||||
render_template,
|
||||
current_app,
|
||||
redirect,
|
||||
jsonify,
|
||||
)
|
||||
|
||||
import environ
|
||||
@@ -142,7 +143,14 @@ class AppConfig:
|
||||
domain = environ.var()
|
||||
site_name = environ.var("")
|
||||
avatar_cache_ttl = environ.var(1800, converter=int)
|
||||
languages = environ.var(["de", "en"], converter=autosplit)
|
||||
languages = environ.var([
|
||||
"de",
|
||||
"en",
|
||||
"fr",
|
||||
"id",
|
||||
"po",
|
||||
], converter=autosplit)
|
||||
apple_store_url = environ.var("")
|
||||
|
||||
|
||||
_UPPER_CASE = "".join(map(chr, range(ord("A"), ord("Z")+1)))
|
||||
@@ -172,6 +180,7 @@ def create_app() -> quart.Quart:
|
||||
app.config["SNIKKET_DOMAIN"] = config.domain
|
||||
app.config["SITE_NAME"] = config.site_name or config.domain
|
||||
app.config["AVATAR_CACHE_TTL"] = config.avatar_cache_ttl
|
||||
app.config["APPLE_STORE_URL"] = config.apple_store_url
|
||||
|
||||
app.context_processor(proc)
|
||||
app.register_error_handler(
|
||||
@@ -194,6 +203,44 @@ def create_app() -> quart.Quart:
|
||||
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
@app.route("/site.webmanifest")
|
||||
def site_manifest() -> quart.Response:
|
||||
# this is needed for icons
|
||||
return jsonify(
|
||||
{
|
||||
"name": "Snikket",
|
||||
"short_name": "Snikket",
|
||||
"icons": [
|
||||
{
|
||||
"src": url_for(
|
||||
"static",
|
||||
filename="img/android-chrome-192x192.png",
|
||||
),
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": url_for(
|
||||
"static",
|
||||
filename="img/android-chrome-256x256.png",
|
||||
),
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": url_for(
|
||||
"static",
|
||||
filename="img/android-chrome-512x512.png",
|
||||
),
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
],
|
||||
"theme_color": "#fbfdff",
|
||||
"background_color": "#fbfdff",
|
||||
}
|
||||
)
|
||||
|
||||
logging_config = app.config.get("LOGGING_CONFIG")
|
||||
if logging_config is not None:
|
||||
if isinstance(logging_config, dict):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import asyncio
|
||||
import json
|
||||
import typing
|
||||
|
||||
@@ -148,8 +147,13 @@ class InvitePost(flask_wtf.FlaskForm): # type:ignore
|
||||
default=7*86400,
|
||||
)
|
||||
|
||||
reusable = wtforms.BooleanField(
|
||||
_l("Invite a group of people"),
|
||||
type_ = wtforms.RadioField(
|
||||
_l("Invitation type"),
|
||||
choices=[
|
||||
("account", _l("Individual")),
|
||||
("group", _l("Group")),
|
||||
],
|
||||
default="account",
|
||||
)
|
||||
|
||||
action_create_invite = wtforms.SubmitField(
|
||||
@@ -228,7 +232,7 @@ async def create_invite() -> typing.Union[str, quart.Response]:
|
||||
(c.id_, c.name) for c in circles
|
||||
]
|
||||
if form.validate_on_submit():
|
||||
if form.reusable.data:
|
||||
if form.type_.data == "group":
|
||||
invite = await client.create_group_invite(
|
||||
group_ids=form.circles.data,
|
||||
ttl=form.lifetime.data,
|
||||
@@ -246,7 +250,11 @@ async def create_invite() -> typing.Union[str, quart.Response]:
|
||||
@bp.route("/invitation/<id_>", methods=["GET", "POST"])
|
||||
@client.require_admin_session()
|
||||
async def edit_invite(id_: str) -> typing.Union[str, quart.Response]:
|
||||
invite_info = await client.get_invite_by_id(id_)
|
||||
try:
|
||||
invite_info = await client.get_invite_by_id(id_)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 404:
|
||||
abort(404)
|
||||
circles = await client.list_groups()
|
||||
circle_map = {
|
||||
circle.id_: circle
|
||||
@@ -325,7 +333,7 @@ class EditCircleForm(flask_wtf.FlaskForm): # type:ignore
|
||||
)
|
||||
|
||||
action_save = wtforms.SubmitField(
|
||||
_l("Apply")
|
||||
_l("Update circle")
|
||||
)
|
||||
|
||||
action_delete = wtforms.SubmitField(
|
||||
@@ -353,25 +361,21 @@ async def edit_circle(id_: str) -> typing.Union[str, quart.Response]:
|
||||
return redirect(url_for(".circles"))
|
||||
raise
|
||||
|
||||
circle_members = await asyncio.gather(*(
|
||||
client.get_user_by_localpart(
|
||||
localpart,
|
||||
session=session,
|
||||
)
|
||||
for localpart in sorted(circle.members)
|
||||
))
|
||||
|
||||
users = await client.list_users()
|
||||
users = sorted(
|
||||
await client.list_users(),
|
||||
key=lambda x: x.localpart
|
||||
)
|
||||
circle_members = [
|
||||
user for user in users
|
||||
if user.localpart in circle.members
|
||||
]
|
||||
|
||||
form = EditCircleForm()
|
||||
form.user_to_add.choices = sorted(
|
||||
(
|
||||
(u.localpart, u.localpart)
|
||||
for u in users
|
||||
if u.localpart not in circle.members
|
||||
),
|
||||
key=lambda x: x[1]
|
||||
)
|
||||
form.user_to_add.choices = [
|
||||
(user.localpart, user.localpart)
|
||||
for user in users
|
||||
if user.localpart not in circle.members
|
||||
]
|
||||
valid_users = [x[0] for x in form.user_to_add.choices]
|
||||
|
||||
invite_form = InvitePost()
|
||||
|
||||
@@ -7,6 +7,7 @@ import aiohttp
|
||||
import quart.flask_patch
|
||||
from quart import (
|
||||
Blueprint,
|
||||
current_app,
|
||||
render_template,
|
||||
redirect,
|
||||
url_for,
|
||||
@@ -56,6 +57,14 @@ async def view(id_: str) -> str:
|
||||
return await render_template("invite_invalid.html")
|
||||
raise
|
||||
|
||||
if invite.reset_localpart is not None:
|
||||
return await render_template(
|
||||
"invite_reset_view.html",
|
||||
invite=invite,
|
||||
invite_id=id_,
|
||||
account_jid="{}@{}".format(invite.reset_localpart, invite.domain)
|
||||
)
|
||||
|
||||
play_store_url = (
|
||||
"https://play.google.com/store/apps/details?" +
|
||||
urllib.parse.urlencode(
|
||||
@@ -68,9 +77,7 @@ async def view(id_: str) -> str:
|
||||
),
|
||||
)
|
||||
)
|
||||
apple_store_url = (
|
||||
"https://apps.apple.com/us/app/tigase-messenger/id1153516838"
|
||||
)
|
||||
apple_store_url = current_app.config["APPLE_STORE_URL"]
|
||||
|
||||
return await render_template(
|
||||
"invite_view.html",
|
||||
@@ -106,7 +113,14 @@ class RegisterForm(flask_wtf.FlaskForm): # type:ignore
|
||||
|
||||
@bp.route("/<id_>/register", methods=["GET", "POST"])
|
||||
async def register(id_: str) -> typing.Union[str, quart.Response]:
|
||||
invite = await client.get_public_invite_by_id(id_)
|
||||
try:
|
||||
invite = await client.get_public_invite_by_id(id_)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 404:
|
||||
return redirect(url_for(".view", id_=id_))
|
||||
|
||||
if invite.reset_localpart is not None:
|
||||
return redirect(url_for(".reset", id_=id_))
|
||||
form = RegisterForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
@@ -120,7 +134,7 @@ async def register(id_: str) -> typing.Union[str, quart.Response]:
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 409:
|
||||
form.localpart.errors.append(
|
||||
_l("That user name is already taken")
|
||||
_l("That username is already taken")
|
||||
)
|
||||
elif exc.status == 403:
|
||||
form.localpart.errors.append(
|
||||
@@ -128,7 +142,7 @@ async def register(id_: str) -> typing.Union[str, quart.Response]:
|
||||
)
|
||||
elif exc.status == 400:
|
||||
form.localpart.errors.append(
|
||||
_l("The user name was not valid")
|
||||
_l("The username is not valid")
|
||||
)
|
||||
elif exc.status == 404:
|
||||
return redirect(url_for(".view", id_=id_))
|
||||
@@ -145,6 +159,66 @@ async def register(id_: str) -> typing.Union[str, quart.Response]:
|
||||
)
|
||||
|
||||
|
||||
class ResetForm(flask_wtf.FlaskForm): # type:ignore
|
||||
password = wtforms.PasswordField(
|
||||
_l("Password"),
|
||||
)
|
||||
|
||||
password_confirm = wtforms.PasswordField(
|
||||
_l("Confirm password"),
|
||||
validators=[wtforms.validators.InputRequired(),
|
||||
wtforms.validators.EqualTo(
|
||||
"password",
|
||||
_l("The passwords must match")
|
||||
)]
|
||||
)
|
||||
|
||||
action_reset = wtforms.SubmitField(
|
||||
_l("Change password")
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/<id_>/reset", methods=["GET", "POST"])
|
||||
async def reset(id_: str) -> typing.Union[str, quart.Response]:
|
||||
try:
|
||||
invite = await client.get_public_invite_by_id(id_)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 404:
|
||||
return redirect(url_for(".view", id_=id_))
|
||||
|
||||
if invite.reset_localpart is None:
|
||||
return redirect(url_for(".register", id_=id_))
|
||||
|
||||
form = ResetForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
# log the user in? show a guide? no idea.
|
||||
try:
|
||||
jid = await client.register_with_token(
|
||||
username=invite.reset_localpart,
|
||||
password=form.password.data,
|
||||
token=id_,
|
||||
)
|
||||
except aiohttp.ClientResponseError as exc:
|
||||
if exc.status == 403:
|
||||
form.localpart.errors.append(
|
||||
_l("Registration was declined for unknown reasons")
|
||||
)
|
||||
elif exc.status == 404:
|
||||
return redirect(url_for(".view", id_=id_))
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
http_session[INVITE_SESSION_JID] = jid
|
||||
return redirect(url_for(".reset_success"))
|
||||
|
||||
return await render_template(
|
||||
"invite_reset.html",
|
||||
invite=invite,
|
||||
form=form,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/success", methods=["GET", "POST"])
|
||||
async def success() -> str:
|
||||
return await render_template(
|
||||
@@ -153,6 +227,14 @@ async def success() -> str:
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/success/reset", methods=["GET", "POST"])
|
||||
async def reset_success() -> str:
|
||||
return await render_template(
|
||||
"invite_reset_success.html",
|
||||
jid=http_session.get(INVITE_SESSION_JID, ""),
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/-")
|
||||
async def index() -> quart.Response:
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@@ -69,7 +69,7 @@ async def login() -> typing.Union[str, quart.Response]:
|
||||
await client.login(jid, password)
|
||||
except quart.exceptions.Unauthorized:
|
||||
form.password.errors.append(
|
||||
_("Invalid user name or password.")
|
||||
_("Invalid username or password.")
|
||||
)
|
||||
else:
|
||||
return redirect(url_for('user.index'))
|
||||
|
||||
@@ -60,6 +60,7 @@ class AdminUserInfo:
|
||||
|
||||
class InviteType(enum.Enum):
|
||||
REGISTER = "register"
|
||||
ROSTER = "roster"
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
@@ -100,6 +101,7 @@ class AdminInviteInfo:
|
||||
class AdminGroupInfo:
|
||||
id_: str
|
||||
name: str
|
||||
muc_jid: typing.Optional[str]
|
||||
members: typing.Collection[str]
|
||||
|
||||
@classmethod
|
||||
@@ -110,6 +112,7 @@ class AdminGroupInfo:
|
||||
return cls(
|
||||
id_=data["id"],
|
||||
name=data["name"],
|
||||
muc_jid=data.get("muc_jid") or None,
|
||||
members=data.get("members", []),
|
||||
)
|
||||
|
||||
@@ -118,6 +121,8 @@ class AdminGroupInfo:
|
||||
class PublicInviteInfo:
|
||||
inviter: typing.Optional[str]
|
||||
xmpp_uri: str
|
||||
reset_localpart: typing.Optional[str]
|
||||
domain: str
|
||||
|
||||
@classmethod
|
||||
def from_api_response(
|
||||
@@ -127,6 +132,8 @@ class PublicInviteInfo:
|
||||
return cls(
|
||||
inviter=data.get("inviter") or None,
|
||||
xmpp_uri=data["uri"],
|
||||
reset_localpart=data.get("reset", None),
|
||||
domain=data["domain"],
|
||||
)
|
||||
|
||||
|
||||
@@ -137,6 +144,7 @@ class HTTPSessionManager:
|
||||
async def _create(self) -> aiohttp.ClientSession:
|
||||
return aiohttp.ClientSession(headers={
|
||||
"Accept": "application/json",
|
||||
"Host": current_app.config["SNIKKET_DOMAIN"],
|
||||
})
|
||||
|
||||
async def teardown(self, exc: typing.Optional[BaseException]) -> None:
|
||||
@@ -197,6 +205,7 @@ class HTTPAuthSessionManager(HTTPSessionManager):
|
||||
headers={
|
||||
"Authorization": "Bearer {}".format(token),
|
||||
"Accept": "application/json",
|
||||
"Host": current_app.config["SNIKKET_DOMAIN"],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -944,10 +953,12 @@ class ProsodyClient:
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
create_muc: bool = True,
|
||||
session: aiohttp.ClientSession,
|
||||
) -> AdminGroupInfo:
|
||||
payload = {
|
||||
"name": name,
|
||||
"create_muc": create_muc,
|
||||
}
|
||||
|
||||
async with session.post(
|
||||
|
||||
@@ -11,15 +11,15 @@ $colours: (
|
||||
#f6f5f4
|
||||
],
|
||||
"blue": [
|
||||
#062943,
|
||||
#0f3d62,
|
||||
#0e4c76,
|
||||
#226494,
|
||||
#418fc7,
|
||||
#72b2e3,
|
||||
#9dccf0,
|
||||
#b5d8f3,
|
||||
#e4f3fd
|
||||
#062243,
|
||||
#0f3462,
|
||||
#0e4276,
|
||||
#225994,
|
||||
#4182c7,
|
||||
#72a7e3,
|
||||
#9dc4f0,
|
||||
#b5d2f3,
|
||||
#e4f0fd
|
||||
],
|
||||
"red": [
|
||||
#340e03,
|
||||
@@ -39,20 +39,20 @@ $colours: (
|
||||
#a07501,
|
||||
#c79b0e,
|
||||
#f4ce3f,
|
||||
#feed93,
|
||||
#fef6c1,
|
||||
#fffbe8
|
||||
#fee577,
|
||||
#fef1c1,
|
||||
#fff8e8
|
||||
],
|
||||
"green": [
|
||||
#052f03,
|
||||
#0c4608,
|
||||
#197713,
|
||||
#218a1b,
|
||||
#55c644,
|
||||
#81e06e,
|
||||
#abed9c,
|
||||
#cef6c5,
|
||||
#ecfbe6
|
||||
#172f03,
|
||||
#244608,
|
||||
#407713,
|
||||
#548f19,
|
||||
#7fc644,
|
||||
#a1e06e,
|
||||
#c0ed9c,
|
||||
#dbf6c5,
|
||||
#effbe6
|
||||
]
|
||||
);
|
||||
|
||||
@@ -171,6 +171,7 @@ $w-l4: 4rem;
|
||||
$w-l5: 6rem;
|
||||
$w-l6: 8rem;
|
||||
$w-l7: 12rem;
|
||||
$w-l8: 16rem;
|
||||
|
||||
$font-sans: "Noto Sans", sans-serif;
|
||||
$font-serif: serif;
|
||||
|
||||
@@ -45,7 +45,7 @@ main {
|
||||
/* top bar */
|
||||
|
||||
@mixin snikket-logo {
|
||||
background-image: url('/static/img/snikket-logo.svg');
|
||||
background-image: url('../img/snikket-logo.svg');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: $w-s2 0em;
|
||||
@@ -171,10 +171,10 @@ body > footer {
|
||||
|
||||
@for $n from 1 through 6 {
|
||||
div.form h#{$n}.form-title {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 1.5em;
|
||||
font-size: nth($h-sizes, 4);
|
||||
/* font-weight: bold; */
|
||||
line-height: 1.5 / (nth($h-sizes, 4) / 100%);
|
||||
margin: 1.5em / (nth($h-sizes, 4) / 100%) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,13 +222,27 @@ div.form {
|
||||
}
|
||||
|
||||
div.form.layout-expanded {
|
||||
label {
|
||||
label, legend {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: block;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type="radio"] + label, input[type="checkbox"] + label {
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
div.f-ebox {
|
||||
margin-bottom: $w-l1;
|
||||
margin: 1.5em 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
div.f-bbox {
|
||||
@@ -242,7 +256,6 @@ div.form.layout-expanded {
|
||||
border: none;
|
||||
border-bottom: $w-s4 solid $primary-500;
|
||||
margin-bottom: -$w-s4;
|
||||
padding: 0 $w-s3;
|
||||
}
|
||||
|
||||
input[type=$type].has-error {
|
||||
@@ -374,10 +387,18 @@ div.form.layout-expanded {
|
||||
}
|
||||
}
|
||||
|
||||
div.avatar-wrap {
|
||||
> .avatar {
|
||||
margin: 0;
|
||||
margin-right: $w-0;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-bottom: $w-s4 solid $primary-500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
textarea:hover {
|
||||
@@ -389,11 +410,12 @@ div.form.layout-expanded {
|
||||
}
|
||||
}
|
||||
|
||||
.f-ebox > ul {
|
||||
fieldset > ul {
|
||||
/* radio group */
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: $w-s1 0;
|
||||
padding-left: $w-l1;
|
||||
|
||||
> li {
|
||||
margin: 0;
|
||||
@@ -455,7 +477,7 @@ input[type="submit"], button, .button {
|
||||
&.primary {
|
||||
background: linear-gradient(0deg, $primary-500, $primary-600);
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
|
||||
color: $primary-900;
|
||||
color: white;
|
||||
border: none;
|
||||
/* TODO: fix vertical rhyhtm ... */
|
||||
border-radius: $w-s4;
|
||||
@@ -758,40 +780,10 @@ body#login {
|
||||
}
|
||||
|
||||
|
||||
/* welcome screen specials */
|
||||
|
||||
div.welcome-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& > .card {
|
||||
flex: 1 0 $w-l7;
|
||||
margin: $w-s1;
|
||||
@extend .el-2;
|
||||
padding: $w-s1 $w-l1;
|
||||
background: white;
|
||||
}
|
||||
|
||||
& > a.card {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
& > h2 {
|
||||
color: $primary-200;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
& > .card:hover, & > .card:active, & > .card:focus, & > .card:focus-within {
|
||||
@extend .el-3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* admin area specials */
|
||||
|
||||
#topbar > div.admin-note {
|
||||
color: $alert-500;
|
||||
color: $alert-400;
|
||||
font-size: nth($h-sizes, 5);
|
||||
margin-left: $w-l1;
|
||||
}
|
||||
@@ -799,10 +791,14 @@ div.welcome-cards {
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: $w-s1;
|
||||
}
|
||||
td, th {
|
||||
padding: $w-s1;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.elevated {
|
||||
@@ -860,6 +856,104 @@ ul.inline {
|
||||
}
|
||||
|
||||
|
||||
/* welcome screen specials */
|
||||
|
||||
#home main {
|
||||
> h1, > p {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
nav.welcome {
|
||||
> ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
|
||||
> li {
|
||||
@extend .el-3;
|
||||
background-color: white;
|
||||
|
||||
flex: 1 0 $w-l7;
|
||||
margin: $w-s1;
|
||||
padding: $w-s1 $w-l1;
|
||||
text-align: center;
|
||||
max-width: $w-l8;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
&.wide {
|
||||
flex: 1 0 auto;
|
||||
/* display: block; */
|
||||
}
|
||||
|
||||
.button {
|
||||
display: block;
|
||||
margin: $w-l1 0;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin: $w-l1 $w-0;
|
||||
--margin: $w-0 * 2;
|
||||
width: calc(100% - var(--margin));
|
||||
}
|
||||
|
||||
p {
|
||||
margin-left: $w-0;
|
||||
margin-right: $w-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.profile-card {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: $w-l1 0;
|
||||
text-align: left;
|
||||
|
||||
> div.picture {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
> div.details {
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> .display-name {
|
||||
font-size: nth($h-small-sizes, 5);
|
||||
line-height: 1.5 / (nth($h-small-sizes, 5) / 100%);
|
||||
}
|
||||
|
||||
> .address {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
> input {
|
||||
flex: 1 1 auto;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
> .button {
|
||||
flex: 0 0 auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* linearisation / responsive stuff */
|
||||
|
||||
@media screen and (max-width: $medium-screen-threshold) {
|
||||
@@ -952,6 +1046,12 @@ pre.guru-meditation {
|
||||
}
|
||||
}
|
||||
|
||||
body#login {
|
||||
.form-title {
|
||||
color: $primary-800;
|
||||
}
|
||||
}
|
||||
|
||||
body > footer {
|
||||
background-color: $gray-200;
|
||||
color: $gray-800;
|
||||
@@ -999,14 +1099,10 @@ pre.guru-meditation {
|
||||
}
|
||||
}
|
||||
|
||||
div.welcome-cards {
|
||||
& > .card {
|
||||
background: black;
|
||||
}
|
||||
|
||||
& > a.card {
|
||||
& > h2 {
|
||||
color: $primary-800;
|
||||
nav.welcome {
|
||||
> ul {
|
||||
> li {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1053,11 +1149,11 @@ pre.guru-meditation {
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background: linear-gradient(0deg, $gray-400, $gray-500);
|
||||
background: linear-gradient(0deg, $gray-200, $gray-300);
|
||||
color: $gray-900;
|
||||
|
||||
&:hover, &:focus {
|
||||
background: linear-gradient(0deg, $gray-500, $gray-600);
|
||||
background: linear-gradient(0deg, $gray-300, $gray-400);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -1120,3 +1216,52 @@ pre.guru-meditation {
|
||||
color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
/* tooltip magic */
|
||||
|
||||
.with-tooltip {
|
||||
position: relative;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
.with-tooltip:before {
|
||||
content: attr(data-tooltip); /* here's the magic */
|
||||
position: absolute;
|
||||
font-size: 87.05505633%;
|
||||
|
||||
/* vertically center */
|
||||
bottom: 100%;
|
||||
transform: translateX(-50%);
|
||||
left: 50%;
|
||||
margin-bottom: $w-s2;
|
||||
|
||||
/* basic styles */
|
||||
width:$w-l7;
|
||||
padding: $w-s1;
|
||||
background: black;
|
||||
color: $gray-900;
|
||||
text-align: center;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
.with-tooltip:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
||||
bottom: 100%;
|
||||
transform: translateX(-50%);
|
||||
left: 50%;
|
||||
margin-bottom: -$w-s1;
|
||||
|
||||
/* the arrow */
|
||||
border: 10px solid black;
|
||||
border-color: black transparent transparent transparent;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
.with-tooltip:hover:before, .with-tooltip:hover:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -183,3 +183,13 @@ div.form.layout-expanded .lwrap {
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
/* dark mode */
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
div.form.layout-expanded .lwrap {
|
||||
span {
|
||||
background: $gray-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
snikket_web/static/img/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
snikket_web/static/img/android-chrome-256x256.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
snikket_web/static/img/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
snikket_web/static/img/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
snikket_web/static/img/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
snikket_web/static/img/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
@@ -17,6 +17,11 @@ licensed under the terms of the Apache 2.0 License -->
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M9 16.2l-3.5-3.5c-.39-.39-1.01-.39-1.4 0-.39.39-.39 1.01 0 1.4l4.19 4.19c.39.39 1.02.39 1.41 0L20.3 7.7c.39-.39.39-1.01 0-1.4-.39-.39-1.01-.39-1.4 0L9 16.2z" />
|
||||
</symbol>
|
||||
<!-- from: action/delete/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-delete" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v10zM18 4h-2.5l-.71-.71c-.18-.18-.44-.29-.7-.29H9.91c-.26 0-.52.11-.7.29L8.5 4H6c-.55 0-1 .45-1 1s.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1z" />
|
||||
</symbol>
|
||||
<!-- from: action/logout/materialicons/24px.svg -->
|
||||
<symbol id="icon-logout" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
@@ -52,11 +57,6 @@ licensed under the terms of the Apache 2.0 License -->
|
||||
<path d="M0 0h24v24H0" fill="none" />
|
||||
<path d="M8 11h8v2H8zm12.1 1H22c0-2.76-2.24-5-5-5h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1zM3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM19 12h-2v3h-3v2h3v3h2v-3h3v-2h-3z" />
|
||||
</symbol>
|
||||
<!-- from: content/create/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-edit" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" />
|
||||
</symbol>
|
||||
<!-- from: content/remove_circle_outline/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-remove" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
@@ -97,14 +97,44 @@ licensed under the terms of the Apache 2.0 License -->
|
||||
<rect fill="none" height="24" width="24" />
|
||||
<g><path d="M12,12.75c1.63,0,3.07,0.39,4.24,0.9c1.08,0.48,1.76,1.56,1.76,2.73L18,17c0,0.55-0.45,1-1,1H7c-0.55,0-1-0.45-1-1l0-0.61 c0-1.18,0.68-2.26,1.76-2.73C8.93,13.14,10.37,12.75,12,12.75z M4,13c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2s-2,0.9-2,2 C2,12.1,2.9,13,4,13z M5.13,14.1C4.76,14.04,4.39,14,4,14c-0.99,0-1.93,0.21-2.78,0.58C0.48,14.9,0,15.62,0,16.43L0,17 c0,0.55,0.45,1,1,1l3.5,0v-1.61C4.5,15.56,4.73,14.78,5.13,14.1z M20,13c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2s-2,0.9-2,2 C18,12.1,18.9,13,20,13z M24,16.43c0-0.81-0.48-1.53-1.22-1.85C21.93,14.21,20.99,14,20,14c-0.39,0-0.76,0.04-1.13,0.1 c0.4,0.68,0.63,1.46,0.63,2.29V18l3.5,0c0.55,0,1-0.45,1-1L24,16.43z M12,6c1.66,0,3,1.34,3,3c0,1.66-1.34,3-3,3s-3-1.34-3-3 C9,7.34,10.34,6,12,6z" /></g>
|
||||
</symbol>
|
||||
<!-- from: social/people/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-people" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V18c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-1.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05.02.01.03.03.04.04 1.14.83 1.93 1.94 1.93 3.41V18c0 .35-.07.69-.18 1H22c.55 0 1-.45 1-1v-1.5c0-2.33-4.67-3.5-7-3.5z" />
|
||||
</symbol>
|
||||
<!-- from: social/group_add/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-create_group" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M7 10H5V8c0-.55-.45-1-1-1s-1 .45-1 1v2H1c-.55 0-1 .45-1 1s.45 1 1 1h2v2c0 .55.45 1 1 1s1-.45 1-1v-2h2c.55 0 1-.45 1-1s-.45-1-1-1zm11 1c1.66 0 2.99-1.34 2.99-3S19.66 5 18 5c-.32 0-.63.05-.91.14.57.81.9 1.79.9 2.86s-.34 2.04-.9 2.86c.28.09.59.14.91.14zm-5 0c1.66 0 2.99-1.34 2.99-3S14.66 5 13 5s-3 1.34-3 3 1.34 3 3 3zm0 2c-2 0-6 1-6 3v1c0 .55.45 1 1 1h10c.55 0 1-.45 1-1v-1c0-2-4-3-6-3zm6.62.16c.83.73 1.38 1.66 1.38 2.84v1.5c0 .17-.02.34-.05.5h2.55c.28 0 .5-.22.5-.5V16c0-1.54-2.37-2.49-4.38-2.84z" />
|
||||
</symbol>
|
||||
<!-- from: social/person_add/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-add_user" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V8c0-.55-.45-1-1-1s-1 .45-1 1v2H2c-.55 0-1 .45-1 1s.45 1 1 1h2v2c0 .55.45 1 1 1s1-.45 1-1v-2h2c.55 0 1-.45 1-1s-.45-1-1-1H6zm9 4c-2.67 0-8 1.34-8 4v1c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-1c0-2.66-5.33-4-8-4z" />
|
||||
</symbol>
|
||||
<!-- from: social/person_remove/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-remove_user" viewBox="0 0 24 24">
|
||||
<g><rect fill="none" height="24" width="24" /><rect fill="none" height="24" width="24" /></g>
|
||||
<g><path d="M14,8c0-2.21-1.79-4-4-4S6,5.79,6,8s1.79,4,4,4S14,10.21,14,8z M2,18v1c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1v-1 c0-2.66-5.33-4-8-4S2,15.34,2,18z M18,10h4c0.55,0,1,0.45,1,1v0c0,0.55-0.45,1-1,1h-4c-0.55,0-1-0.45-1-1v0 C17,10.45,17.45,10,18,10z" /></g>
|
||||
</symbol>
|
||||
<!-- from: navigation/close/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-close" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M18.3 5.71c-.39-.39-1.02-.39-1.41 0L12 10.59 7.11 5.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L10.59 12 5.7 16.89c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 13.41l4.89 4.89c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z" />
|
||||
</symbol>
|
||||
<!-- from: image/edit/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-edit" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" />
|
||||
</symbol>
|
||||
<!-- from: action/admin_panel_settings/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-admin" viewBox="0 0 24 24">
|
||||
<g><rect fill="none" height="24" width="24" /><rect fill="none" height="24" width="24" /></g>
|
||||
<g><g><path d="M17,11c0.34,0,0.67,0.04,1,0.09V7.58c0-0.8-0.47-1.52-1.2-1.83l-5.5-2.4c-0.51-0.22-1.09-0.22-1.6,0l-5.5,2.4 C3.47,6.07,3,6.79,3,7.58v3.6c0,4.54,3.2,8.79,7.5,9.82c0.55-0.13,1.08-0.32,1.6-0.55C11.41,19.47,11,18.28,11,17 C11,13.69,13.69,11,17,11z" /><path d="M17,13c-2.21,0-4,1.79-4,4c0,2.21,1.79,4,4,4s4-1.79,4-4C21,14.79,19.21,13,17,13z M17,14.38c0.62,0,1.12,0.51,1.12,1.12 s-0.51,1.12-1.12,1.12s-1.12-0.51-1.12-1.12S16.38,14.38,17,14.38z M17,19.75c-0.93,0-1.74-0.46-2.24-1.17 c0.05-0.72,1.51-1.08,2.24-1.08s2.19,0.36,2.24,1.08C18.74,19.29,17.93,19.75,17,19.75z" /></g></g>
|
||||
</symbol>
|
||||
<!-- from: content/link/materialiconsround/24px.svg -->
|
||||
<symbol id="icon-link" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path d="M17 7h-3c-.55 0-1 .45-1 1s.45 1 1 1h3c1.65 0 3 1.35 3 3s-1.35 3-3 3h-3c-.55 0-1 .45-1 1s.45 1 1 1h3c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-9 5c0 .55.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1H9c-.55 0-1 .45-1 1zm2 3H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h3c.55 0 1-.45 1-1s-.45-1-1-1H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h3c.55 0 1-.45 1-1s-.45-1-1-1z" />
|
||||
</symbol>
|
||||
</defs></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
33
snikket_web/static/img/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="260.000000pt" height="260.000000pt" viewBox="0 0 260.000000 260.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,260.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1169 2496 c-2 -2 -24 -6 -49 -9 -51 -6 -196 -42 -237 -59 -360 -146
|
||||
-607 -401 -723 -748 -49 -143 -62 -230 -62 -386 0 -177 27 -297 109 -498 115
|
||||
-282 109 -516 -18 -660 l-30 -35 38 6 c151 22 316 93 400 172 12 12 25 21 28
|
||||
21 3 0 41 -20 83 -45 181 -104 366 -152 592 -153 133 0 240 16 362 54 84 27
|
||||
228 92 228 103 0 4 -14 15 -31 25 -254 150 -478 469 -534 761 -5 22 -10 47
|
||||
-11 55 -21 97 -21 303 1 409 58 293 200 534 420 716 33 28 81 64 108 80 26 17
|
||||
47 33 47 36 0 3 -39 24 -87 47 -86 40 -217 83 -298 97 -46 7 -329 17 -336 11z
|
||||
m-117 -379 c90 -53 140 -137 140 -237 0 -231 -271 -353 -445 -199 -62 54 -89
|
||||
113 -90 197 -1 125 70 223 193 263 49 16 155 4 202 -24z"/>
|
||||
<path d="M847 2029 c-56 -29 -96 -101 -91 -161 12 -128 153 -196 261 -124 37
|
||||
24 73 83 73 118 0 23 -4 25 -45 24 -75 -2 -108 46 -93 139 2 17 -3 20 -33 21
|
||||
-20 1 -52 -7 -72 -17z"/>
|
||||
<path d="M1885 2218 c-136 -100 -265 -251 -340 -398 -40 -80 -92 -223 -100
|
||||
-281 -4 -24 -8 -46 -10 -49 -2 -3 -6 -35 -9 -71 l-6 -65 33 -1 c125 -3 325
|
||||
-57 461 -124 77 -39 178 -101 204 -126 7 -7 17 -13 20 -13 14 0 178 -166 216
|
||||
-219 39 -53 39 -53 52 -30 18 32 63 173 75 234 71 364 -31 723 -281 997 -64
|
||||
70 -219 198 -238 198 -4 0 -38 -23 -77 -52z"/>
|
||||
<path d="M1418 1245 c-7 -8 17 -171 37 -244 9 -35 28 -93 42 -128 l26 -64 41
|
||||
7 c136 22 368 118 446 182 l31 27 -50 33 c-146 94 -330 161 -491 178 -36 3
|
||||
-68 8 -71 10 -3 2 -8 1 -11 -1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
snikket_web/static/img/snikket-logo-text.svg
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
@@ -2,6 +2,8 @@
|
||||
{% from "library.j2" import action_button, custom_form_button, form_button, circle_name %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Manage circles{% endtrans %}</h1>
|
||||
<p>{% trans %}<em>Circles</em> aim to help people who are in the same social circle find each other on your service.{% endtrans %}</p>
|
||||
<p>{% trans %}Users who are in the same circle will see each other in their contact list. In addition, each circle has a group chat where the circle members are included.{% endtrans %}</p>
|
||||
{%- if circles -%}
|
||||
<form method="POST" action="{{ url_for(".create_invite") }}">
|
||||
{{- invite_form.csrf_token -}}
|
||||
@@ -20,10 +22,13 @@
|
||||
<td class="collapsible">{{ circle.members | length }}</td>
|
||||
<td class="nowrap">
|
||||
{%- call custom_form_button("create_link", invite_form.circles.name, circle.id_, slim=True, class="secondary accent") -%}
|
||||
{% trans circle_name=circle.name %}Create invitation to circle {{ circle_name }}{% endtrans %}
|
||||
{% trans circle_name=(circle | circle_name) %}Create invitation to circle {{ circle_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
{%- call action_button("more", url_for(".edit_circle", id_=circle.id_), class="primary") -%}
|
||||
{% trans circle_name=circle.name %}Show details of circle {{ circle_name }}{% endtrans %}
|
||||
{%- call action_button("people", url_for(".edit_circle", id_=circle.id_) + "#members", class="secondary") -%}
|
||||
{% trans circle_name=(circle | circle_name) %}Manage members of {{ circle_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
{%- call action_button("edit", url_for(".edit_circle", id_=circle.id_), class="primary") -%}
|
||||
{% trans circle_name=(circle | circle_name) %}Edit circle {{ circle_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
<h2 class="form-title">{% trans %}Create new invitation{% endtrans %}</h2>
|
||||
<p class="form-descr weak">{% trans %}Create a new invitation link to invite more users to your Snikket service by clicking the button below.{% endtrans %}</p>
|
||||
<div class="f-ebox">
|
||||
{{ invite_form.reusable }}
|
||||
{{ invite_form.reusable.label }}
|
||||
<fieldset>{#- -#}
|
||||
<legend>{{ invite_form.type_.label.text }}</legend>
|
||||
{{- invite_form.type_ -}}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ invite_form.lifetime.label }}
|
||||
|
||||
@@ -11,17 +11,13 @@
|
||||
<dd>{{ target_user.localpart }}</dd>
|
||||
<dt>{% trans %}Display name{% endtrans %}</dt>
|
||||
<dd>{{ target_user.display_name }}</dd>
|
||||
<dt>{% trans %}Email address{% endtrans %}</dt>
|
||||
<dd>{{ target_user.email }}</dd>
|
||||
<dt>{% trans %}Display name{% endtrans %}</dt>
|
||||
<dd>{{ target_user.phone }}</dd>
|
||||
</dl>
|
||||
{% call box("alert", _("Danger")) %}
|
||||
<p>{% trans %}The user and their data will be deleted irrevocably, permanently and immediately upon pushing the below button. <strong>There is no way back!</strong>{% endtrans %}</p>
|
||||
{% endcall %}
|
||||
<div class="f-bbox">
|
||||
{%- call standard_button("back", url_for(".index"), class="secondary") %}{% trans %}Back{% endtrans %}{% endcall -%}
|
||||
{%- call form_button("remove", form.action_delete, class="primary danger") %}{% endcall -%}
|
||||
{%- call form_button("delete", form.action_delete, class="primary danger") %}{% endcall -%}
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,15 +1,44 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% from "library.j2" import form_button, standard_button, value_or_hint, custom_form_button %}
|
||||
{% from "library.j2" import form_button, standard_button, value_or_hint, custom_form_button, clipboard_button %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
{% include "copy-snippet.html" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans circle_name=(target_circle | circle_name) %}Edit circle {{ circle_name }}{% endtrans %}</h1>
|
||||
<form method="POST">
|
||||
{{- form.csrf_token -}}
|
||||
{%- if target_circle.id_ == "default" -%}
|
||||
<input type="hidden" name="{{ form.name.name }}" value="{{ form.name.data }}">{#- -#}
|
||||
<div class="box hint form layout-expanded">
|
||||
<header>{% trans %}This is your main circle{% endtrans %}</header>
|
||||
<p>{% trans %}This circle is managed automatically and cannot be removed or renamed.{% endtrans %}</p>
|
||||
{%- if target_circle.muc_jid -%}
|
||||
<div><label for="circle-muc-jid">{% trans %}Group chat address{% endtrans %}</label></div>
|
||||
<div><input type="text" readonly="readonly" id="circle-muc-jid" value="{{ target_circle.muc_jid }}"></div>
|
||||
{%- call clipboard_button(target_circle.muc_jid, show_label=True) -%}
|
||||
{%- trans -%}Copy address{%- endtrans -%}
|
||||
{%- endcall -%}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- else -%}
|
||||
<div class="form layout-expanded">
|
||||
<h2 class="form-title">{% trans %}Circle information{% endtrans %}</h2>
|
||||
<div class="f-ebox">
|
||||
{{ form.name.label }}
|
||||
{{ form.name }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{%- if target_circle.muc_jid -%}
|
||||
<label for="circle-muc-jid">{% trans %}Group chat address{% endtrans %}</label>
|
||||
<input type="text" readonly="readonly" id="circle-muc-jid" value="{{ target_circle.muc_jid }}">
|
||||
{%- call clipboard_button(target_circle.muc_jid, show_label=True) -%}
|
||||
{%- trans -%}Copy address{%- endtrans -%}
|
||||
{%- endcall -%}
|
||||
{%- else -%}
|
||||
<p>{% trans %}This circle has no group chat associated.{% endtrans %}<p>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call standard_button("back", url_for(".circles"), class="secondary") -%}
|
||||
{% trans %}Back{% endtrans %}
|
||||
@@ -19,10 +48,11 @@
|
||||
<h3 class="form-title">{% trans %}Delete circle{% endtrans %}</h3>
|
||||
<p class="form-desc">{% trans %}Deleting a circle does not delete any users in the circle.{% endtrans %}</p>
|
||||
<div class="f-bbox">
|
||||
{%- call form_button("done", form.action_delete, class="secondary danger") %}{% endcall -%}
|
||||
{%- call form_button("delete", form.action_delete, class="secondary danger") %}{% endcall -%}
|
||||
</div>
|
||||
</div>
|
||||
<h2>{% trans %}Circle members{% endtrans %}</h2>
|
||||
{%- endif -%}
|
||||
<h2 id="members">{% trans %}Circle members{% endtrans %}</h2>
|
||||
{%- if circle_members -%}
|
||||
<div class="el-2 elevated"><table>
|
||||
<thead>
|
||||
@@ -36,7 +66,7 @@
|
||||
<td>{{ member.localpart }}</td>
|
||||
<td class="collapsible">{% call value_or_hint(member.display_name) %}{% endcall %}</td>
|
||||
<td class="nowrap">
|
||||
{%- call custom_form_button("remove", form.action_remove_user.name, member.localpart, class="primary danger", slim=True) -%}
|
||||
{%- call custom_form_button("remove_user", form.action_remove_user.name, member.localpart, class="primary danger", slim=True) -%}
|
||||
{% trans username=member.localpart %}Remove user {{ username }} from circle{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</td>
|
||||
@@ -56,12 +86,12 @@
|
||||
<div class="select-wrap">{{ form.user_to_add }}</div>
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call form_button("add", form.action_add_user, class="primary") %}{% endcall -%}
|
||||
{%- call form_button("add_user", form.action_add_user, class="primary") %}{% endcall -%}
|
||||
</div>
|
||||
</div>
|
||||
{%- else -%}
|
||||
<div class="box hint el-2">
|
||||
<header>{% trans %}No users left{% endtrans %}</header>
|
||||
<div class="elevated box success el-2">
|
||||
<header>{% trans %}All users added{% endtrans %}</header>
|
||||
<p>{% trans %}All users on this service are already in this circle.{% endtrans %}</p>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% from "library.j2" import showuri, form_button, standard_button, extract_circle_name %}
|
||||
{% from "library.j2" import showuri, form_button, standard_button, extract_circle_name, invite_type_description %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
{% include "copy-snippet.html" %}
|
||||
@@ -12,10 +12,10 @@
|
||||
<dl>
|
||||
<dt>{% trans %}Valid until{% endtrans %}</dt>
|
||||
<dd>{{ invite.expires | format_date }}</dd>
|
||||
<dt>{% trans %}Link{% endtrans %}</dt>
|
||||
<dd>{% call showuri(invite.landing_page) %}{% endcall %}</dd>
|
||||
<dt>{% trans %}Reusability{% endtrans %}</dt>
|
||||
<dd>{% if invite.reusable %}{% trans %}This invitation link can be used arbitrarily often, until it expires, is revoked or a service-wide user limit is reached.{% endtrans %}{% else %}{% trans %}This invitation link can only be used once and is then depleted.{% endtrans %}{% endif %}</dd>
|
||||
<dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt>
|
||||
<dd>{% call showuri(invite.landing_page, id_="link-field") %}{% endcall %}</dd>
|
||||
<dt>{% trans %}Invitation type{% endtrans %}</dt>
|
||||
<dd>{% call invite_type_description(invite) %}{% endcall %}</dd>
|
||||
{%- set ngroups = invite.group_ids | length -%}
|
||||
{%- if ngroups > 1 -%}
|
||||
{#- not supported via the web UI, but we should still display it properly -#}
|
||||
@@ -36,6 +36,10 @@
|
||||
{%- endif -%}
|
||||
</dd>
|
||||
{%- endif -%}
|
||||
{%- if invite.type_.value == "roster" -%}
|
||||
<dt>{% trans %}Contact{% endtrans %}</dt>
|
||||
<dd>{% trans peer_jid=invite.jid %}The user will get added as contact of {{ peer_jid }}.{% endtrans %}</dd>
|
||||
{%- endif -%}
|
||||
<dt>{% trans %}Created{% endtrans %}</dt>
|
||||
<dd>{{ invite.created_at | format_date }}</dd>
|
||||
</dl>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% block content %}
|
||||
<h1>{% trans user_name=target_user.localpart %}Edit user {{ user_name }}{% endtrans %}</h1>
|
||||
<div class="form layout-expanded"><form method="POST">
|
||||
<h2 class="form-title">{% trans %}User information{% endtrans %}</h2>
|
||||
{{ form.csrf_token }}
|
||||
<div class="f-ebox">
|
||||
{{ form.username.label }}
|
||||
{{ form.username(readonly="readonly") }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.nickname.label }}
|
||||
{{ form.nickname(readonly="readonly") }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.email.label }}
|
||||
{{ form.email(readonly="readonly") }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.phone.label }}
|
||||
{{ form.phone(readonly="readonly") }}
|
||||
</div>
|
||||
{{ form.action_save(class="primary") }}
|
||||
<input type="submit" class="a11y-only">
|
||||
<h2 class="form-title">{% trans %}Password reset{% endtrans %}</h2>
|
||||
<p>{% trans %}If the user has forgotten their password, use the below button to create a password reset link. The password reset link can be used once to change the password of the account. Transmit the link to the user via a secure channel.{% endtrans %}</p>
|
||||
{{ form.action_create_reset_link(class="secondary accent") }}
|
||||
<h2 class="form-title">{% trans %}Delete user{% endtrans %}</h2>
|
||||
<p>{% trans %}{% endtrans %}</p>
|
||||
{{ form.action_create_reset_link(class="secondary accent") }}
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
@@ -1,22 +1,43 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% set body_id = "home" %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Welcome to the administration dashboard!{% endtrans %}</h1>
|
||||
<h1>{% trans %}Welcome to the admin panel!{% endtrans %}</h1>
|
||||
<p>{% trans user_name=user_info.display_name %}At your service, {{ user_name }}.{% endtrans %}</p>
|
||||
<div class="welcome-cards">
|
||||
<a class="card" href="{{ url_for('.users') }}">
|
||||
<h2>{% trans %}Manage users{% endtrans %}</h2>
|
||||
<p>{% trans %}Modify administrative user information or delete users.{% endtrans %}</p>
|
||||
</a>
|
||||
<a class="card" href="{{ url_for('.circles') }}">
|
||||
<h2>{% trans %}Manage circles{% endtrans %}</h2>
|
||||
</a>
|
||||
<a class="card" href="{{ url_for('.invitations') }}">
|
||||
<h2>{% trans %}Manage invitations{% endtrans %}</h2>
|
||||
<p>{% trans %}Create, revoke or view invitations.{% endtrans %}</p>
|
||||
</a>
|
||||
<a class="card" href="{{ url_for('user.index') }}">
|
||||
<h2>{% trans %}Back to the main view{% endtrans %}</h2>
|
||||
<p>{% trans %}Go back to your user’s web portal page.{% endtrans %}</p>
|
||||
</a>
|
||||
</div>
|
||||
<nav class="welcome">
|
||||
<ul>
|
||||
<li>
|
||||
<h2>{% trans %}Users{% endtrans %}</h2>
|
||||
{#- -#}
|
||||
<p>{% trans %}Create password reset links or delete users.{% endtrans %}</p>
|
||||
{#- -#}
|
||||
{# <img aria-hidden="true" src="{{ url_for("static", filename="img/illus-profile.svg") }}"> #}
|
||||
{#- -#}
|
||||
<div>{% call standard_button("people", url_for(".users"), class="primary") %}{% trans %}Manage users{% endtrans %}{% endcall %}</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
<li>
|
||||
<h2>{% trans %}Circles{% endtrans %}</h2>
|
||||
{#- -#}
|
||||
<p>{% trans %}Create and manage social circles represented on your service.{% endtrans %}</p>
|
||||
{#- -#}
|
||||
<div>{% call standard_button("groups", url_for(".circles"), class="primary") %}{% trans %}Manage circles{% endtrans %}{% endcall %}</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
<li>
|
||||
<h2>{% trans %}Invitations{% endtrans %}</h2>
|
||||
{#- -#}
|
||||
<p>{% trans %}Create, revoke or copy invitations.{% endtrans %}</p>
|
||||
{#- -#}
|
||||
<div>{% call standard_button("link", url_for(".invitations"), class="primary") %}{% trans %}Manage invitations{% endtrans %}{% endcall %}</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
<li>
|
||||
{#- -#}
|
||||
<p>{% trans %}Go back to your user's web portal page.{% endtrans %}</p>
|
||||
{#- -#}
|
||||
<div>{% call standard_button("logout", url_for("user.index"), class="secondary") %}{% trans %}Exit admin panel{% endtrans %}{% endcall %}</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "admin_app.html" %}
|
||||
{% from "library.j2" import action_button, icon, clipboard_button, form_button, custom_form_button, extract_circle_name %}
|
||||
{% from "library.j2" import action_button, icon, clipboard_button, form_button, custom_form_button, extract_circle_name, invite_type_name, invite_type_description %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
{% include "copy-snippet.html" %}
|
||||
@@ -19,7 +19,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Valid until{% endtrans %}</th>
|
||||
<th class="collapsible">{% trans %}Reusable{% endtrans %}</th>
|
||||
<th class="collapsible">{% trans %}Type{% endtrans %}</th>
|
||||
<th class="collapsible">{% trans %}Circle{% endtrans %}</th>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
</tr>
|
||||
@@ -28,8 +28,7 @@
|
||||
{% for invite in invites %}
|
||||
<tr>
|
||||
<td>{{ (invite.expires - now) | format_timedelta(add_direction=True) }}</td>
|
||||
<td class="collapsible">{% if invite.reusable %}{% trans %}Yes{% endtrans %}{% else %}{% trans
|
||||
%}No{% endtrans %}{% endif %}</td>
|
||||
<td class="collapsible"><span class="with-tooltip above" data-tooltip="{% call invite_type_description(invite) %}{% endcall %}">{% call invite_type_name(invite) %}{% endcall %}</span></td>
|
||||
<td class="collapsible">
|
||||
{#- -#}
|
||||
<ul class="inline">
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<dd>
|
||||
<dt>{% trans %}Valid until{% endtrans %}</dt>
|
||||
<dd>{{ reset_link.expires | format_date }}</dd>
|
||||
<dt>{% trans %}Link{% endtrans %}</dt>
|
||||
<dd>{% call showuri(reset_link.landing_page) %}{% endcall %}</dd>
|
||||
<dt><label for="link-field">{% trans %}Link{% endtrans %}</label></dt>
|
||||
<dd>{% call showuri(reset_link.landing_page, id_="link-field") %}{% endcall %}</dd>
|
||||
</dd>
|
||||
<div class="f-bbox">
|
||||
{%- call custom_form_button("remove_link", form.action_revoke.name, reset_link.id_, class="secondary danger") -%}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
<tr>
|
||||
<th>{% trans %}Login name{% endtrans %}</th>
|
||||
<th>{% trans %}Display name{% endtrans %}</th>
|
||||
<th class="collapsible">{% trans %}Email address{% endtrans %}</th>
|
||||
<th class="collapsible">{% trans %}Phone number{% endtrans %}</th>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -19,16 +17,14 @@
|
||||
<tr>
|
||||
<td>{{ user.localpart }}</td>
|
||||
<td>{% call value_or_hint(user.display_name) %}{% endcall %}</td>
|
||||
<td class="collapsible">{% call value_or_hint(user.email) %}{% endcall %}</td>
|
||||
<td class="collapsible">{% call value_or_hint(user.phone) %}{% endcall %}</td>
|
||||
<td class="nowrap">
|
||||
{%- call action_button("remove", url_for(".delete_user", localpart=user.localpart), class="secondary") -%}
|
||||
{%- call action_button("delete", url_for(".delete_user", localpart=user.localpart), class="secondary") -%}
|
||||
{% trans user_name=user.localpart %}Delete user {{ user_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
{%- call action_button("bug_report", url_for(".debug_user", localpart=user.localpart), class="secondary") -%}
|
||||
{% trans user_name=user.localpart %}Show debug information for {{ user_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
{%- call custom_form_button("create_link", reset_form.action_create.name, user.localpart, class="secondary", slim=True) -%}
|
||||
{%- call custom_form_button("passwd", reset_form.action_create.name, user.localpart, class="secondary", slim=True) -%}
|
||||
{% trans user_name=user.localpart %}Create password reset link for {{ user_name }}{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</form>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "unauth.html" %}
|
||||
{% from "library.j2" import avatar with context %}
|
||||
{% from "library.j2" import standard_button %}
|
||||
{% block head_lead %}
|
||||
<title>{% trans %}Snikket Web Portal{% endtrans %}</title>
|
||||
{% endblock %}
|
||||
{% block topbar_right %}
|
||||
{{- super() -}}
|
||||
<nav class="usermenu">{{ user_info.display_name }}{% call avatar(user_info.address, user_info.avatar_hash ) %}{% endcall %}</nav>
|
||||
{% call standard_button("logout", url_for("user.logout"), class="tertiary") %}{% trans %}Log out{% endtrans %}{% endcall %}
|
||||
{%- endblock %}
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/common.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/app.css') }}">
|
||||
{% endblock %}
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for("static", filename="img/apple-touch-icon.png") }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for("static", filename="img/favicon-32x32.png") }}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for("static", filename="img/favicon-16x16.png") }}">
|
||||
<link rel="manifest" href="{{ url_for("site_manifest") }}">
|
||||
<link rel="mask-icon" href="{{ url_for("static", filename="img/safari-pinned-tab.svg") }}" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#fbd308">
|
||||
<meta name="theme-color" content="#fbd308">
|
||||
</head>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{% block body %}
|
||||
<h1 id="dummy">Theme Demo</h1>
|
||||
<p>This page is to demonstrate the Snikket Web Portal theme and allow development. You should not see this during normal use.</p>
|
||||
<p><a id="disable-lines" href="#no-lines" class="button secondary">Disable rhythm lines</a><a id="enable-lines" href="#dummy" class="button secondary">Enable rhythm lines</a></p>
|
||||
<p style="height: 3rem"><a id="disable-lines" href="#no-lines" class="button secondary">Disable rhythm lines</a><a id="enable-lines" href="#dummy" class="button secondary">Enable rhythm lines</a></p>
|
||||
<h2>Headings</h2>
|
||||
<p>This subsection is responsible for demonstrating the heading sizes, with the relation between the different headings and also the relation between headings and text.</p>
|
||||
<div class="demo-columns"><div class="demo-column">
|
||||
@@ -145,14 +145,20 @@
|
||||
<input type="text" id="fex-f1" name="fex-f1">
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
<input type="checkbox" id="fex-f2" name="fex-f2"><label for="fex-f2">Enable fancy features</label>
|
||||
<input type="checkbox" id="fex-f3" name="fex-f3"><label for="fex-f3">Enable more features</label>
|
||||
<input type="checkbox" id="fex-f4" name="fex-f4"><label for="fex-f4">Also do that other thing</label>
|
||||
<label>Optional features</label>
|
||||
<ul id="check-features">
|
||||
<li><input type="checkbox" id="fex-f2" name="fex-f2"><label for="fex-f2">Enable fancy features</label></li>
|
||||
<li><input type="checkbox" id="fex-f3" name="fex-f3"><label for="fex-f3">Enable more features</label></li>
|
||||
<li><input type="checkbox" id="fex-f4" name="fex-f4"><label for="fex-f4">Also do that other thing</label></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
<input type="radio" id="fex-f5" name="fex-rg1"><label for="fex-f5">High difficulty</label>
|
||||
<input type="radio" id="fex-f6" name="fex-rg1"><label for="fex-f6">Medium difficulty</label>
|
||||
<input type="radio" id="fex-f7" name="fex-rg1"><label for="fex-f7">Low difficulty</label>
|
||||
<label>Level</label>
|
||||
<ul id="radio-difficulty">
|
||||
<li><input type="radio" id="fex-f5" name="fex-rg1"><label for="fex-f5">High difficulty</label></li>
|
||||
<li><input type="radio" id="fex-f6" name="fex-rg1"><label for="fex-f6">Medium difficulty</label></li>
|
||||
<li><input type="radio" id="fex-f7" name="fex-rg1"><label for="fex-f7">Low difficulty</label></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
<label for="fex-f8">Select dropdown:</label>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{% extends "invite.html" %}
|
||||
{% set body_id = "invite" %}
|
||||
{% block content %}
|
||||
<div class="elevated box el-3">
|
||||
<h1>{% trans site_name=config["SITE_NAME"] %}Invite to {{ site_name }}{% endtrans %}</h1>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo-text.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<div class="box alert">
|
||||
<header>{% trans %}Invite expired{% endtrans %}</header>
|
||||
<p>{% trans %}Sorry, it looks like this invite code has expired!{% endtrans %}</p>
|
||||
<p>{% trans %}Sorry, it looks like this invitation link has expired!{% endtrans %}</p>
|
||||
</div>
|
||||
<img alt="Sad person holding empty box" src="{{ url_for("static", filename="img/illus-empty.svg") }}" class="fullwidth">
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% block content %}
|
||||
<div class="elevated box el-3">
|
||||
<h1>{% trans site_name=config["SITE_NAME"] %}Register on {{ site_name }}{% endtrans %}</h1>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo-text.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<p>{% trans site_name=config["SITE_NAME"] %}{{ site_name }} is using Snikket - a secure, privacy-friendly chat app.{% endtrans %}</p>
|
||||
<h2>{% trans %}Create an account{% endtrans %}</h2>
|
||||
<p>{% trans %}Creating an account will allow to communicate with other people using the Snikket app or compatible software. If you already have the app installed, we recommend that you continue the account creation process inside the app by clicking on the button below:{% endtrans %}</p>
|
||||
|
||||
35
snikket_web/templates/invite_reset.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends "unauth.html" %}
|
||||
{% from "library.j2" import standard_button, render_errors %}
|
||||
{% block style %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for("static", filename="css/invite.css") }}">
|
||||
{% endblock %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
<title>{% trans %}Reset your password | Snikket{% endtrans %}</title>
|
||||
<script async type="text/javascript" src="{{ url_for("static", filename="js/qrcode.min.js") }}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<form method="POST"><div class="form layout-expanded">
|
||||
{{- form.csrf_token -}}
|
||||
<h1 class="form-title">{% trans %}Reset your password online{% endtrans %}</h1>
|
||||
<p class="form-desc weak">{% trans %}To reset your password online, fill out the fields below and confirm using the button.{% endtrans %}</p>
|
||||
{%- call render_errors(form) %}{% endcall -%}
|
||||
<div class="f-ebox">
|
||||
{{ form.password.label }}
|
||||
{{ form.password }}
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.password_confirm.label }}
|
||||
{{ form.password_confirm }}
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call form_button("passwd", form.action_reset, class="primary") -%}{%- endcall -%}
|
||||
</div>
|
||||
</div></form>
|
||||
<script type="text/javascript">
|
||||
var onload = function() {
|
||||
apply_qr_code(document.getElementById("qr-uri"));
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
14
snikket_web/templates/invite_reset_success.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% extends "unauth.html" %}
|
||||
{% from "library.j2" import standard_button %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
<title>{% trans %}Password reset successful | Snikket{% endtrans %}</title>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Password reset successful{% endtrans %}</h1>
|
||||
<div class="box success">
|
||||
<header>{% trans %}Your password has been changed{% endtrans %}</header>
|
||||
<p>{% trans %}You can now log in using your new password.{% endtrans %}</p>
|
||||
<p>{% trans %}You can now safely close this page.{% endtrans %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
37
snikket_web/templates/invite_reset_view.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends "unauth.html" %}
|
||||
{% from "library.j2" import standard_button %}
|
||||
{% block style %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for("static", filename="css/invite.css") }}">
|
||||
{% endblock %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
<title>{% trans %}Reset your password | Snikket{% endtrans %}</title>
|
||||
<script async type="text/javascript" src="{{ url_for("static", filename="js/invite-magic.js") }}"></script>
|
||||
<script async type="text/javascript" src="{{ url_for("static", filename="js/qrcode.min.js") }}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Reset your password{% endtrans %}</h1>
|
||||
<p>{% trans account_jid=account_jid %}This page allows you to reset the password of your account, <strong>{{ account_jid }}</strong>, once.{% endtrans %}</p>
|
||||
<div class="elevated el-2">
|
||||
<h2>{% trans %}Using the app{% endtrans %}</h2>
|
||||
<p>{% trans %}To reset your password using the Snikket App, tap the button below.{% endtrans %}</p>
|
||||
<div>
|
||||
{%- call standard_button("exit_to_app", invite.xmpp_uri, class="secondary") -%}
|
||||
{% trans %}Open the app{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</div>
|
||||
<img class="float-right" id="tutorial-scan" aria-hidden="true" alt="" src="{{ url_for("static", filename="img/tutorial-scan.png") }}">
|
||||
<p>{% trans %}Alternatively, you can scan the below code with the Snikket App using the Scan button at the top.{% endtrans %}</p>
|
||||
<p>{% trans %}Your camera will turn on. Point it at the square code below until it is within the highlighted square on your screen, and wait until the app recognises it.{% endtrans %}</p>
|
||||
<p>{% trans %}You will then be prompted to enter a new password for your account.{% endtrans %}</p>
|
||||
<div id="qr-uri" data-qrdata="{{ invite.xmpp_uri }}" class="qr"></div>
|
||||
<h2>{% trans %}Alternatives{% endtrans %}</h2>
|
||||
<p>{% trans reset_url=url_for(".reset", id_=invite_id) %}You can also <a href="{{ reset_url }}">reset your password online</a> if the above button or scanning the QR code does not work for you.{% endtrans %}</p>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var onload = function() {
|
||||
apply_qr_code(document.getElementById("qr-uri"));
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -8,13 +8,13 @@
|
||||
{% block content %}
|
||||
<div class="elevated box el-3 form layout-expanded">
|
||||
<h1>{% trans site_name=config["SITE_NAME"] %}Successfully registered on {{ site_name }}{% endtrans %}</h1>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo-text.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<p>{% trans site_name=config["SITE_NAME"], jid=jid %}Congratulations! You successfully registered on {{ site_name }} as {{ jid }}.{% endtrans %}</p>
|
||||
<input type="text" readonly="readonly" value="{{ jid }}">
|
||||
<label for="address" class="a11y-only">{% trans %}Your address{% endtrans %}</label><input type="text" readonly="readonly" value="{{ jid }}" id="address">
|
||||
{%- call clipboard_button(jid, show_label=True) -%}
|
||||
{% trans %}Copy address{% endtrans %}
|
||||
{%- endcall -%}
|
||||
<p>{% trans %}You can not set up your legacy XMPP client with the above address and the password you chose during registration.{% endtrans %}</p>
|
||||
<p>{% trans %}You can now set up your legacy XMPP client with the above address and the password you chose during registration.{% endtrans %}</p>
|
||||
<p>{% trans %}You can now safely close this page.{% endtrans %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -10,18 +10,24 @@
|
||||
{% block content %}
|
||||
<div class="elevated box el-3">
|
||||
<h1>{% trans site_name=config["SITE_NAME"] %}Invite to {{ site_name }}{% endtrans %}</h1>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
<div class="powered-by">{% trans logo_url=url_for("static", filename="img/snikket-logo-text.svg") %}Powered by <img src="{{ logo_url }}" alt="Snikket">{% endtrans %}</div>
|
||||
{%- if invite.inviter -%}
|
||||
<p>{% trans site_name=config["SITE_NAME"], inviter_name=invite.inviter %}You have been invited to chat with {{ inviter_name }} using Snikket, a secure, privacy-friendly chat app on {{ site_name }}.{% endtrans %}</p>
|
||||
{%- else -%}
|
||||
<p>{% trans site_name=config["SITE_NAME"] %}You have been invited to chat on {{ site_name }} using Snikket, a secure, privacy-friendly chat app.{% endtrans %}</p>
|
||||
{%- endif -%}
|
||||
<h2>{% trans %}Get started{% endtrans %}</h2>
|
||||
{%- if apple_store_url -%}
|
||||
<p>{% trans %}Install the Snikket App on your Android or iOS device.{% endtrans %}</p>
|
||||
{%- else -%}
|
||||
<p>{% trans ios_info_url="https://snikket.org/faq/#is-there-an-ios-app" %}Install the Snikket App on your Android device (<a href="{{ ios_info_url }}" rel="noopener noreferrer" target="_blank">iOS coming soon!</a>).{% endtrans %}</p>
|
||||
{%- endif -%}
|
||||
<div class="install-buttons">
|
||||
<ul>
|
||||
<li><a href="{{ play_store_url }}"><img alt='{% trans %}Get it on Google Play{% endtrans %}' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png' class="play"/></a></li>
|
||||
{%- if apple_store_url -%}
|
||||
<li><a href="{{ apple_store_url }}"><img alt='{% trans %}Download on the App Store{% endtrans %}' src="{{ apple_store_badge() }}" class="apple"></a></li>
|
||||
{%- endif -%}
|
||||
</ul>
|
||||
{%- call standard_button("qrcode", "#qr-modal", class="primary", onclick="open_modal(this); return false;") -%}
|
||||
{% trans %}Not on mobile?{% endtrans %}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
{%- endif -%}
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro showuri(uri, caller=None) %}
|
||||
{% macro showuri(uri, caller=None, id_=None) %}
|
||||
{%- if uri is none -%}
|
||||
<em>—</em>
|
||||
{%- else -%}
|
||||
<div><input type="text" readonly="readonly" value="{{ uri }}"></div>
|
||||
<div><input type="text" {% if id_ %}id="{{ id_ }}" {% endif %}readonly="readonly" value="{{ uri }}"></div>
|
||||
<div>{% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %}</div>
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
{% macro standard_button(icon_name, href, caller=None, class=None, onclick=None) -%}
|
||||
{%- set label = caller() -%}
|
||||
<a href="{{ href }}" class="button {% if class %}{{ class }}{% endif %}" aria-label="{{ a11y }}" title="{{ a11y }}"{% if onclick %} onclick="{{ onclick }}"{% endif %}>{% call icon(icon_name) %}{% endcall %}<span>{{ label }}</span></a>
|
||||
<a href="{{ href }}" class="button {% if class %}{{ class }}{% endif %}" {% if onclick %} onclick="{{ onclick }}"{% endif %}>{% call icon(icon_name) %}{% endcall %}<span>{{ label }}</span></a>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro form_button(icon_name, button_obj, caller=None, class=None) -%}
|
||||
@@ -60,6 +60,7 @@
|
||||
{% macro clipboard_button(data, show_label=False, caller=None, class=None) -%}
|
||||
{%- set label = caller() -%}
|
||||
<a class="button{% if class %} {{ class }}{% endif %}"
|
||||
href="#"
|
||||
{% if not show_label %}
|
||||
aria-label="{{ label }}"
|
||||
title="{{ label }}"
|
||||
@@ -107,3 +108,19 @@
|
||||
<em>{% trans %}deleted{% endtrans %}</em>
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
||||
{%- macro invite_type_name(invite_info, caller=None) -%}
|
||||
{%- if invite_info.reusable -%}
|
||||
{% trans %}Group{% endtrans %}
|
||||
{%- else -%}
|
||||
{% trans %}Individual{% endtrans %}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro invite_type_description(invite_info, caller=None) -%}
|
||||
{%- if invite_info.reusable -%}
|
||||
{% trans %}Can be used multiple times to create accounts on this Snikket service.{% endtrans %}
|
||||
{%- else -%}
|
||||
{% trans %}Can be used once to create an account on this Snikket service.{% endtrans %}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
@@ -1,24 +1,48 @@
|
||||
{% extends "app.html" %}
|
||||
{% from "library.j2" import clipboard_button, standard_button, avatar with context %}
|
||||
{% set body_id = "home" %}
|
||||
{% block head_lead %}
|
||||
{{ super() }}
|
||||
{% include "copy-snippet.html" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Welcome!{% endtrans %}</h1>
|
||||
<p>{% trans user_name=user_info.display_name %}Welcome home, {{ user_name }}.{% endtrans %}</p>
|
||||
<div class="welcome-cards">
|
||||
<a class="card" href="{{ url_for('.profile') }}">
|
||||
<h2>{% trans %}Update profile{% endtrans %}</h2>
|
||||
<p>{% trans %}Change display name, set avatar and configure visibility of your personal data to others.{% endtrans %}</p>
|
||||
</a>
|
||||
<a class="card" href="{{ url_for('.change_pw') }}">
|
||||
<h2>{% trans %}Change password{% endtrans %}</h2>
|
||||
</a>
|
||||
{% if user_info.is_admin %}
|
||||
<a class="card" href="{{ url_for('admin.index') }}">
|
||||
<h2>{% trans %}Admin dashboard{% endtrans %}</h2>
|
||||
<p>{% trans %}Manage users and invitations of this Snikket service.{% endtrans %}</p>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="card" href="{{ url_for('.logout') }}">
|
||||
<h2>{% trans %}Log out{% endtrans %}</h2>
|
||||
<p>{% trans %}Exit the Snikket Web Portal, without logging out your other devices.{% endtrans %}</p>
|
||||
</a>
|
||||
</div>
|
||||
<nav class="welcome">
|
||||
<ul>
|
||||
<li class="wide">
|
||||
<h2>{% trans %}Your account{% endtrans %}</h2>
|
||||
<div class="profile-card">
|
||||
<div class="picture" aria-label="Your profile picture">{% call avatar(user_info.address, user_info.avatar_hash ) %}{% endcall %}</div>
|
||||
<div class="details">
|
||||
<div class="display-name">{{ user_info.display_name | default(user_info.username) }}</div>
|
||||
<div class="address">
|
||||
<input value="{{ user_info.address }}" aria-label="{% trans %}Your XMPP address{% endtrans %}">
|
||||
{% call clipboard_button(user_info.address) %}{% trans %}Copy address{% endtrans %}{% endcall %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#- -#}
|
||||
{# <p>{% trans %}Change your display name, set a profile picture and control visibility of your personal data to others.{% endtrans %}</p> #}
|
||||
{#- -#}
|
||||
{# <img aria-hidden="true" src="{{ url_for("static", filename="img/illus-profile.svg") }}"> #}
|
||||
{#- -#}
|
||||
<div>
|
||||
<div>{% call standard_button("edit", url_for(".profile"), class="primary") %}{% trans %}Edit profile{% endtrans %}{% endcall %}</div>
|
||||
<div>{% call standard_button("passwd", url_for(".change_pw"), class="secondary") %}{% trans %}Change password{% endtrans %}{% endcall %}</div>
|
||||
</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
{% if user_info.is_admin %}
|
||||
<li>
|
||||
<h2>{% trans %}Your Snikket{% endtrans %}</h2>
|
||||
{#- -#}
|
||||
<p>{% trans %}Manage users, invitations and circles of your Snikket service.{% endtrans %}</p>
|
||||
{#- -#}
|
||||
<div>{% call standard_button("admin", url_for("admin.index"), class="primary") %}{% trans %}Admin panel{% endtrans %}{% endcall %}</div>
|
||||
{#- -#}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="form layout-expanded"><form method="POST">
|
||||
<h2 class="form-title">{% trans %}Change your password{% endtrans %}</h2>
|
||||
<h1 class="form-title">{% trans %}Change your password{% endtrans %}</h1>
|
||||
<p class="form-desc weak">{% trans %}To change your password, you need to provide the current password as well as the new one. To reduce the chance of typos, we ask for your new password twice.{% endtrans %}</p>
|
||||
{{ form.csrf_token }}
|
||||
{%- call render_errors(form) -%}
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call standard_button("back", url_for('.index'), class="secondary") %}{% trans %}Back{% endtrans %}{% endcall -%}
|
||||
{%- call custom_form_button("done", "", "", class="primary") -%}
|
||||
{%- call custom_form_button("passwd", "", "", class="primary") -%}
|
||||
{% trans %}Change password{% endtrans %}
|
||||
{%- endcall -%}
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
{% extends "app.html" %}
|
||||
{% from "library.j2" import standard_button, form_button %}
|
||||
{% from "library.j2" import standard_button, form_button, avatar with context %}
|
||||
{% block head_lead %}
|
||||
<title>Snikket Web Portal</title>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans %}Update your profile{% endtrans %}</h1>
|
||||
<div class="form layout-expanded"><form method="POST" enctype="multipart/form-data">
|
||||
<h2 class="form-title">{% trans %}Profile{% endtrans %}</h2>
|
||||
{{ form.csrf_token }}
|
||||
@@ -13,13 +14,18 @@
|
||||
</div>
|
||||
<div class="f-ebox">
|
||||
{{ form.avatar.label }}
|
||||
<div class="avatar-wrap">
|
||||
{%- call avatar(user_info.address, user_info.avatar_hash ) %}{% endcall -%}
|
||||
{{ form.avatar }}
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="form-title">{% trans %}Visibility{% endtrans %}</h3>
|
||||
<p class="form-descr weak">{% trans %}This section allows you to control who can see your profile information, like avatar and nickname.{% endtrans %}</p>
|
||||
<div class="f-ebox">
|
||||
{{ form.profile_access_model.label }}
|
||||
{{ form.profile_access_model }}
|
||||
<fieldset>{#- -#}
|
||||
<legend>{{ form.profile_access_model.label.text }}</legend>
|
||||
{{- form.profile_access_model -}}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="f-bbox">
|
||||
{%- call standard_button("back", url_for('.index'), class="secondary") %}{% trans %}Back{% endtrans %}{% endcall -%}
|
||||
|
||||
1145
snikket_web/translations/it/LC_MESSAGES/messages.po
Normal file
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-01-26 15:06+0100\n"
|
||||
"POT-Creation-Date: 2021-01-30 12:45+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -53,39 +53,47 @@ msgstr ""
|
||||
msgid "Four weeks"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:152
|
||||
msgid "Invite a group of people"
|
||||
#: snikket_web/admin.py:152 snikket_web/templates/admin_edit_invite.html:17
|
||||
msgid "Invitation type"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:156
|
||||
#: snikket_web/admin.py:154 snikket_web/templates/library.j2:116
|
||||
msgid "Individual"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:155 snikket_web/templates/library.j2:114
|
||||
msgid "Group"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:161
|
||||
msgid "New invitation link"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:218
|
||||
#: snikket_web/admin.py:223
|
||||
msgid "Revoke"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:274 snikket_web/admin.py:318
|
||||
#: snikket_web/admin.py:283 snikket_web/admin.py:327
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:279 snikket_web/templates/admin_circles.html:42
|
||||
#: snikket_web/admin.py:288 snikket_web/templates/admin_circles.html:47
|
||||
msgid "Create circle"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:323
|
||||
#: snikket_web/admin.py:332
|
||||
msgid "Select user"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:328 snikket_web/user.py:68
|
||||
msgid "Apply"
|
||||
#: snikket_web/admin.py:337
|
||||
msgid "Update circle"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:332
|
||||
#: snikket_web/admin.py:341
|
||||
msgid "Delete circle permanently"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/admin.py:338
|
||||
#: snikket_web/admin.py:347
|
||||
msgid "Add user"
|
||||
msgstr ""
|
||||
|
||||
@@ -93,36 +101,41 @@ msgstr ""
|
||||
msgid "Main"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:86
|
||||
#: snikket_web/invite.py:93
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:90 snikket_web/main.py:41
|
||||
#: snikket_web/invite.py:97 snikket_web/invite.py:164 snikket_web/main.py:41
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:94
|
||||
#: snikket_web/invite.py:101 snikket_web/invite.py:168
|
||||
msgid "Confirm password"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:98
|
||||
#: snikket_web/invite.py:105 snikket_web/invite.py:172
|
||||
msgid "The passwords must match"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:103
|
||||
#: snikket_web/invite.py:110
|
||||
msgid "Create account"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:123
|
||||
msgid "That user name is already taken"
|
||||
#: snikket_web/invite.py:137
|
||||
msgid "That username is already taken"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:127
|
||||
#: snikket_web/invite.py:141 snikket_web/invite.py:205
|
||||
msgid "Registration was declined for unknown reasons"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:131
|
||||
msgid "The user name was not valid"
|
||||
#: snikket_web/invite.py:145
|
||||
msgid "The username is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/invite.py:177 snikket_web/templates/user_home.html:32
|
||||
#: snikket_web/templates/user_passwd.html:32
|
||||
msgid "Change password"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/main.py:36
|
||||
@@ -134,7 +147,7 @@ msgid "Sign in"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/main.py:72
|
||||
msgid "Invalid user name or password."
|
||||
msgid "Invalid username or password."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/user.py:21
|
||||
@@ -170,7 +183,6 @@ msgid "Everyone"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:12
|
||||
#: snikket_web/templates/admin_delete_user.html:16
|
||||
#: snikket_web/templates/admin_users.html:11 snikket_web/user.py:55
|
||||
msgid "Display name"
|
||||
msgstr ""
|
||||
@@ -183,6 +195,10 @@ msgstr ""
|
||||
msgid "Profile visibility"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/user.py:68
|
||||
msgid "Update profile"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/user.py:93
|
||||
msgid "Incorrect password"
|
||||
msgstr ""
|
||||
@@ -253,45 +269,64 @@ msgid "Admin area"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:4
|
||||
#: snikket_web/templates/admin_home.html:11
|
||||
#: snikket_web/templates/admin_home.html:23
|
||||
msgid "Manage circles"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:11
|
||||
msgid "Circle name"
|
||||
#: snikket_web/templates/admin_circles.html:5
|
||||
msgid ""
|
||||
"<em>Circles</em> aim to help people who are in the same social circle "
|
||||
"find each other on your service."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:12
|
||||
msgid "Members"
|
||||
#: snikket_web/templates/admin_circles.html:6
|
||||
msgid ""
|
||||
"Users who are in the same circle will see each other in their contact "
|
||||
"list. In addition, each circle has a group chat where the circle members "
|
||||
"are included."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:13
|
||||
msgid "Circle name"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:14
|
||||
msgid "Members"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:15
|
||||
#: snikket_web/templates/admin_invites.html:24
|
||||
#: snikket_web/templates/admin_users.html:14
|
||||
#: snikket_web/templates/admin_users.html:12
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:23
|
||||
#: snikket_web/templates/admin_circles.html:25
|
||||
#, python-format
|
||||
msgid "Create invitation to circle %(circle_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:26
|
||||
#: snikket_web/templates/admin_circles.html:28
|
||||
#, python-format
|
||||
msgid "Show details of circle %(circle_name)s"
|
||||
msgid "Manage members of %(circle_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:35
|
||||
#: snikket_web/templates/admin_circles.html:31
|
||||
#: snikket_web/templates/admin_edit_circle.html:8
|
||||
#, python-format
|
||||
msgid "Edit circle %(circle_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:40
|
||||
msgid "No circles"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:36
|
||||
#: snikket_web/templates/admin_circles.html:41
|
||||
msgid ""
|
||||
"Currently, there are no circles on this service. Use the form below to "
|
||||
"create one."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_circles.html:39
|
||||
#: snikket_web/templates/admin_circles.html:44
|
||||
msgid "New circle"
|
||||
msgstr ""
|
||||
|
||||
@@ -332,13 +367,12 @@ msgid "Copy complete output"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:4
|
||||
#: snikket_web/templates/admin_users.html:26
|
||||
#: snikket_web/templates/admin_users.html:22
|
||||
#, python-format
|
||||
msgid "Delete user %(user_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:6
|
||||
#: snikket_web/templates/admin_edit_user.html:28
|
||||
msgid "Delete user"
|
||||
msgstr ""
|
||||
|
||||
@@ -351,75 +385,89 @@ msgstr ""
|
||||
msgid "Login name"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:14
|
||||
#: snikket_web/templates/admin_users.html:12
|
||||
msgid "Email address"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:19
|
||||
#: snikket_web/templates/admin_delete_user.html:15
|
||||
msgid "Danger"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:20
|
||||
#: snikket_web/templates/admin_delete_user.html:16
|
||||
msgid ""
|
||||
"The user and their data will be deleted irrevocably, permanently and "
|
||||
"immediately upon pushing the below button. <strong>There is no way "
|
||||
"back!</strong>"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_delete_user.html:23
|
||||
#: snikket_web/templates/admin_edit_circle.html:15
|
||||
#: snikket_web/templates/admin_edit_invite.html:45
|
||||
#: snikket_web/templates/admin_delete_user.html:19
|
||||
#: snikket_web/templates/admin_edit_circle.html:44
|
||||
#: snikket_web/templates/admin_edit_invite.html:49
|
||||
#: snikket_web/templates/admin_reset_user_password.html:25
|
||||
#: snikket_web/templates/user_logout.html:13
|
||||
#: snikket_web/templates/user_passwd.html:30
|
||||
#: snikket_web/templates/user_profile.html:25
|
||||
#: snikket_web/templates/user_profile.html:31
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:4
|
||||
#, python-format
|
||||
msgid "Edit circle %(circle_name)s"
|
||||
#: snikket_web/templates/admin_edit_circle.html:14
|
||||
msgid "This is your main circle"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:8
|
||||
msgid "Circle information"
|
||||
#: snikket_web/templates/admin_edit_circle.html:15
|
||||
msgid "This circle is managed automatically and cannot be removed or renamed."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:19
|
||||
msgid "Delete circle"
|
||||
#: snikket_web/templates/admin_edit_circle.html:17
|
||||
#: snikket_web/templates/admin_edit_circle.html:33
|
||||
msgid "Group chat address"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:20
|
||||
#: snikket_web/templates/admin_edit_circle.html:36
|
||||
#: snikket_web/templates/invite_success.html:15
|
||||
#: snikket_web/templates/user_home.html:21
|
||||
msgid "Copy address"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:26
|
||||
msgid "Circle information"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:39
|
||||
msgid "This circle has no group chat associated."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:48
|
||||
msgid "Delete circle"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:49
|
||||
msgid "Deleting a circle does not delete any users in the circle."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:25
|
||||
#: snikket_web/templates/admin_edit_circle.html:55
|
||||
msgid "Circle members"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:40
|
||||
#: snikket_web/templates/admin_edit_circle.html:70
|
||||
#, python-format
|
||||
msgid "Remove user %(username)s from circle"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:48
|
||||
#: snikket_web/templates/admin_edit_circle.html:78
|
||||
msgid "This circle currently has no members."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:50
|
||||
#: snikket_web/templates/admin_edit_circle.html:80
|
||||
msgid "Invite more members"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:53
|
||||
#: snikket_web/templates/admin_edit_circle.html:83
|
||||
msgid "Add existing user"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:64
|
||||
msgid "No users left"
|
||||
#: snikket_web/templates/admin_edit_circle.html:94
|
||||
msgid "All users added"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_circle.html:65
|
||||
#: snikket_web/templates/admin_edit_circle.html:95
|
||||
msgid "All users on this service are already in this circle."
|
||||
msgstr ""
|
||||
|
||||
@@ -438,21 +486,8 @@ msgstr ""
|
||||
msgid "Link"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:17
|
||||
msgid "Reusability"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:18
|
||||
msgid ""
|
||||
"This invitation link can be used arbitrarily often, until it expires, is "
|
||||
"revoked or a service-wide user limit is reached."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:18
|
||||
msgid "This invitation link can only be used once and is then depleted."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:22
|
||||
#: snikket_web/templates/admin_home.html:19
|
||||
msgid "Circles"
|
||||
msgstr ""
|
||||
|
||||
@@ -469,65 +504,64 @@ msgstr ""
|
||||
msgid "The user will not be added to any circle and will have no contacts."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:39
|
||||
#: snikket_web/templates/admin_edit_invite.html:40
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:41
|
||||
#, python-format
|
||||
msgid "The user will get added as contact of %(peer_jid)s."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_invite.html:43
|
||||
msgid "Created"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_user.html:3
|
||||
#, python-format
|
||||
msgid "Edit user %(user_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_user.html:5
|
||||
msgid "User information"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_user.html:25
|
||||
#: snikket_web/templates/admin_reset_user_password.html:8
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_edit_user.html:26
|
||||
msgid ""
|
||||
"If the user has forgotten their password, use the below button to create "
|
||||
"a password reset link. The password reset link can be used once to change"
|
||||
" the password of the account. Transmit the link to the user via a secure "
|
||||
"channel."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:3
|
||||
msgid "Welcome to the administration dashboard!"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:4
|
||||
msgid "Welcome to the admin panel!"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:5
|
||||
#, python-format
|
||||
msgid "At your service, %(user_name)s."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:7
|
||||
#: snikket_web/templates/admin_home.html:9
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:11
|
||||
msgid "Create password reset links or delete users."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:15
|
||||
#: snikket_web/templates/admin_users.html:4
|
||||
msgid "Manage users"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:8
|
||||
msgid "Modify administrative user information or delete users."
|
||||
#: snikket_web/templates/admin_home.html:21
|
||||
msgid "Create and manage social circles represented on your service."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:14
|
||||
#: snikket_web/templates/admin_home.html:27
|
||||
msgid "Invitations"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:29
|
||||
msgid "Create, revoke or copy invitations."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:31
|
||||
#: snikket_web/templates/admin_invites.html:8
|
||||
msgid "Manage invitations"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:15
|
||||
msgid "Create, revoke or view invitations."
|
||||
#: snikket_web/templates/admin_home.html:36
|
||||
msgid "Go back to your user's web portal page."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:18
|
||||
msgid "Back to the main view"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_home.html:19
|
||||
msgid "Go back to your user’s web portal page."
|
||||
#: snikket_web/templates/admin_home.html:38
|
||||
msgid "Exit admin panel"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:10
|
||||
@@ -535,33 +569,29 @@ msgid "Pending invitations"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:22
|
||||
msgid "Reusable"
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:31
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:31
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:44
|
||||
#: snikket_web/templates/admin_invites.html:43
|
||||
msgid "Show invite details"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:47
|
||||
#: snikket_web/templates/admin_invites.html:46
|
||||
msgid "Copy invite link to clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:50
|
||||
#: snikket_web/templates/admin_invites.html:49
|
||||
msgid "Delete invitation"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_invites.html:58
|
||||
#: snikket_web/templates/admin_invites.html:57
|
||||
msgid "Currently, there are no pending invitations."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_reset_user_password.html:8
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_reset_user_password.html:12
|
||||
#, python-format
|
||||
msgid "Password reset link for %(user_name)s"
|
||||
@@ -577,16 +607,12 @@ msgstr ""
|
||||
msgid "Destroy link"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_users.html:13
|
||||
msgid "Phone number"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_users.html:29
|
||||
#: snikket_web/templates/admin_users.html:25
|
||||
#, python-format
|
||||
msgid "Show debug information for %(user_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/admin_users.html:32
|
||||
#: snikket_web/templates/admin_users.html:28
|
||||
#, python-format
|
||||
msgid "Create password reset link for %(user_name)s"
|
||||
msgstr ""
|
||||
@@ -595,6 +621,10 @@ msgstr ""
|
||||
msgid "Snikket Web Portal"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/app.html:8
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/backend_error.html:3
|
||||
#: snikket_web/templates/exception.html:3
|
||||
#: snikket_web/templates/internal_error.html:3
|
||||
@@ -618,13 +648,13 @@ msgstr ""
|
||||
msgid "The web portal encountered an internal error."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:4
|
||||
#: snikket_web/templates/invite_invalid.html:5
|
||||
#: snikket_web/templates/invite_view.html:12
|
||||
#, python-format
|
||||
msgid "Invite to %(site_name)s"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:5
|
||||
#: snikket_web/templates/invite_invalid.html:6
|
||||
#: snikket_web/templates/invite_register.html:10
|
||||
#: snikket_web/templates/invite_success.html:11
|
||||
#: snikket_web/templates/invite_view.html:13
|
||||
@@ -632,12 +662,12 @@ msgstr ""
|
||||
msgid "Powered by <img src=\"%(logo_url)s\" alt=\"Snikket\">"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:7
|
||||
#: snikket_web/templates/invite_invalid.html:8
|
||||
msgid "Invite expired"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_invalid.html:8
|
||||
msgid "Sorry, it looks like this invite code has expired!"
|
||||
#: snikket_web/templates/invite_invalid.html:9
|
||||
msgid "Sorry, it looks like this invitation link has expired!"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_register.html:5
|
||||
@@ -668,17 +698,18 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_register.html:14
|
||||
#: snikket_web/templates/invite_view.html:31
|
||||
#: snikket_web/templates/invite_view.html:37
|
||||
msgid "App already installed?"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_register.html:16
|
||||
#: snikket_web/templates/invite_view.html:33
|
||||
#: snikket_web/templates/invite_reset_view.html:21
|
||||
#: snikket_web/templates/invite_view.html:39
|
||||
msgid "Open the app"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_register.html:18
|
||||
#: snikket_web/templates/invite_view.html:35
|
||||
#: snikket_web/templates/invite_view.html:41
|
||||
msgid "This button works only if you have the app installed already!"
|
||||
msgstr ""
|
||||
|
||||
@@ -702,6 +733,91 @@ msgstr ""
|
||||
msgid "Enter a secure password that you do not use anywhere else."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset.html:9
|
||||
#: snikket_web/templates/invite_reset_view.html:9
|
||||
msgid "Reset your password | Snikket"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset.html:15
|
||||
msgid "Reset your password online"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset.html:16
|
||||
msgid ""
|
||||
"To reset your password online, fill out the fields below and confirm "
|
||||
"using the button."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_success.html:5
|
||||
msgid "Password reset successful | Snikket"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_success.html:8
|
||||
msgid "Password reset successful"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_success.html:10
|
||||
msgid "Your password has been changed"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_success.html:11
|
||||
msgid "You can now log in using your new password."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_success.html:12
|
||||
#: snikket_web/templates/invite_success.html:18
|
||||
msgid "You can now safely close this page."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:14
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:15
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This page allows you to reset the password of your account, "
|
||||
"<strong>%(account_jid)s</strong>, once."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:17
|
||||
msgid "Using the app"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:18
|
||||
msgid "To reset your password using the Snikket App, tap the button below."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:25
|
||||
msgid ""
|
||||
"Alternatively, you can scan the below code with the Snikket App using the"
|
||||
" Scan button at the top."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:26
|
||||
#: snikket_web/templates/invite_view.html:75
|
||||
msgid ""
|
||||
"Your camera will turn on. Point it at the square code below until it is "
|
||||
"within the highlighted square on your screen, and wait until the app "
|
||||
"recognises it."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:27
|
||||
msgid "You will then be prompted to enter a new password for your account."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:29
|
||||
#: snikket_web/templates/invite_view.html:43
|
||||
msgid "Alternatives"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_reset_view.html:30
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You can also <a href=\"%(reset_url)s\">reset your password online</a> if "
|
||||
"the above button or scanning the QR code does not work for you."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_success.html:5
|
||||
#, python-format
|
||||
msgid "Successfully registered on %(site_name)s | Snikket"
|
||||
@@ -717,20 +833,16 @@ msgstr ""
|
||||
msgid "Congratulations! You successfully registered on %(site_name)s as %(jid)s."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_success.html:15
|
||||
msgid "Copy address"
|
||||
#: snikket_web/templates/invite_success.html:13
|
||||
msgid "Your address"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_success.html:17
|
||||
msgid ""
|
||||
"You can not set up your legacy XMPP client with the above address and the"
|
||||
"You can now set up your legacy XMPP client with the above address and the"
|
||||
" password you chose during registration."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_success.html:18
|
||||
msgid "You can now safely close this page."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:6
|
||||
#, python-format
|
||||
msgid "Invite to %(site_name)s | Snikket"
|
||||
@@ -754,33 +866,37 @@ msgstr ""
|
||||
msgid "Get started"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:20
|
||||
#: snikket_web/templates/invite_view.html:21
|
||||
msgid "Install the Snikket App on your Android or iOS device."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:23
|
||||
msgid "Get it on Google Play"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:24
|
||||
msgid "Download on the App Store"
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Install the Snikket App on your Android device (<a "
|
||||
"href=\"%(ios_info_url)s\" rel=\"noopener noreferrer\" "
|
||||
"target=\"_blank\">iOS coming soon!</a>)."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:27
|
||||
msgid "Get it on Google Play"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:29
|
||||
msgid "Download on the App Store"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:33
|
||||
msgid "Not on mobile?"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:30
|
||||
#: snikket_web/templates/invite_view.html:36
|
||||
msgid ""
|
||||
"After installation the app should automatically open and prompt you to "
|
||||
"create an account. If not, simply click the button below."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:37
|
||||
msgid "Alternatives"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:38
|
||||
#: snikket_web/templates/invite_view.html:44
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You can connect to Snikket using any XMPP-compatible software. If the "
|
||||
@@ -788,61 +904,62 @@ msgid ""
|
||||
"href=\"%(register_url)s\">register an account manually</a>."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:44
|
||||
#: snikket_web/templates/invite_view.html:50
|
||||
msgid "Scan invite code"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:47
|
||||
#: snikket_web/templates/invite_view.html:76
|
||||
#: snikket_web/templates/invite_view.html:53
|
||||
#: snikket_web/templates/invite_view.html:82
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:50
|
||||
#: snikket_web/templates/invite_view.html:56
|
||||
msgid ""
|
||||
"You can transfer this invite to your mobile device by scanning a code "
|
||||
"with your camera. You can use either a QR scanner app or the Snikket app "
|
||||
"itself."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:55
|
||||
#: snikket_web/templates/invite_view.html:61
|
||||
msgid "Using a QR code scanner"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:57
|
||||
#: snikket_web/templates/invite_view.html:63
|
||||
msgid "Using the Snikket app"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:62
|
||||
#: snikket_web/templates/invite_view.html:68
|
||||
msgid ""
|
||||
"Use a <em>QR code</em> scanner on your mobile device to scan the code "
|
||||
"below:"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:68
|
||||
#: snikket_web/templates/invite_view.html:74
|
||||
msgid ""
|
||||
"Install the Snikket app on your mobile device, open it, and tap the "
|
||||
"'Scan' button at the top."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/invite_view.html:69
|
||||
msgid ""
|
||||
"Your camera will turn on. Point it at the square code below until it is "
|
||||
"within the highlighted square on your screen, and wait until the app "
|
||||
"recognises it."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/library.j2:18
|
||||
msgid "Copy link"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/library.j2:80
|
||||
#: snikket_web/templates/library.j2:81
|
||||
msgid "Invalid input"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/library.j2:107
|
||||
#: snikket_web/templates/library.j2:108
|
||||
msgid "deleted"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/library.j2:122
|
||||
msgid "Can be used multiple times to create accounts on this Snikket service."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/library.j2:124
|
||||
msgid "Can be used once to create an account on this Snikket service."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/login.html:5
|
||||
msgid "Snikket Login"
|
||||
msgstr ""
|
||||
@@ -855,44 +972,37 @@ msgstr ""
|
||||
msgid "Login failed"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:3
|
||||
#: snikket_web/templates/user_home.html:9
|
||||
msgid "Welcome!"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:4
|
||||
#: snikket_web/templates/user_home.html:10
|
||||
#, python-format
|
||||
msgid "Welcome home, %(user_name)s."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:7
|
||||
msgid "Update profile"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:8
|
||||
msgid ""
|
||||
"Change display name, set avatar and configure visibility of your personal"
|
||||
" data to others."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:11
|
||||
#: snikket_web/templates/user_passwd.html:32
|
||||
msgid "Change password"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:15
|
||||
msgid "Admin dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:16
|
||||
msgid "Manage users and invitations of this Snikket service."
|
||||
#: snikket_web/templates/user_home.html:14
|
||||
msgid "Your account"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:20
|
||||
msgid "Log out"
|
||||
msgid "Your XMPP address"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:21
|
||||
msgid "Exit the Snikket Web Portal, without logging out your other devices."
|
||||
#: snikket_web/templates/user_home.html:31
|
||||
msgid "Edit profile"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:38
|
||||
msgid "Your Snikket"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:40
|
||||
msgid "Manage users, invitations and circles of your Snikket service."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_home.html:42
|
||||
msgid "Admin panel"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_logout.html:8
|
||||
@@ -922,15 +1032,19 @@ msgid ""
|
||||
"all of your devices."
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_profile.html:8
|
||||
#: snikket_web/templates/user_profile.html:7
|
||||
msgid "Update your profile"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_profile.html:9
|
||||
msgid "Profile"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_profile.html:18
|
||||
#: snikket_web/templates/user_profile.html:22
|
||||
msgid "Visibility"
|
||||
msgstr ""
|
||||
|
||||
#: snikket_web/templates/user_profile.html:19
|
||||
#: snikket_web/templates/user_profile.html:23
|
||||
msgid ""
|
||||
"This section allows you to control who can see your profile information, "
|
||||
"like avatar and nickname."
|
||||
|
||||
1251
snikket_web/translations/ru/LC_MESSAGES/messages.po
Normal file
@@ -65,7 +65,7 @@ class ProfileForm(flask_wtf.FlaskForm): # type:ignore
|
||||
)
|
||||
|
||||
action_save = wtforms.SubmitField(
|
||||
_l("Apply"),
|
||||
_l("Update profile"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
action/account_circle:profile
|
||||
action/bug_report:bug_report
|
||||
action/done:done
|
||||
action/delete:delete
|
||||
action/logout:logout
|
||||
action/login:login
|
||||
action/exit_to_app:exit_to_app
|
||||
@@ -8,7 +9,6 @@ communication/qr_code:qrcode
|
||||
communication/vpn_key:passwd
|
||||
content/add_circle_outline:add
|
||||
content/add_link:create_link
|
||||
content/create:edit
|
||||
content/remove_circle_outline:remove
|
||||
content/content_copy:copy
|
||||
content/link_off:remove_link
|
||||
@@ -17,5 +17,11 @@ navigation/arrow_forward:forward
|
||||
navigation/cancel:cancel
|
||||
navigation/more_vert:more
|
||||
social/groups:groups
|
||||
social/people:people
|
||||
social/group_add:create_group
|
||||
social/person_add:add_user
|
||||
social/person_remove:remove_user
|
||||
navigation/close:close
|
||||
image/edit:edit
|
||||
action/admin_panel_settings:admin
|
||||
content/link:link
|
||||
|
||||