Compare commits
16 Commits
v0.13.1
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f01229602 | ||
|
|
06a7cbb0f1 | ||
|
|
24e0ff0129 | ||
|
|
45fafc3507 | ||
|
|
9e0c92d703 | ||
|
|
03f8cbfe7b | ||
|
|
120ea02fde | ||
|
|
cc16271683 | ||
|
|
78a47e3a74 | ||
|
|
b4c2ebc0bb | ||
|
|
55112fac88 | ||
|
|
4f2bf7a64e | ||
|
|
dfcbea56b8 | ||
|
|
f87c2c9d50 | ||
|
|
4cc2dd4b54 | ||
|
|
f1a0de2090 |
38
.github/workflows/build-docker-edge.yml
vendored
38
.github/workflows/build-docker-edge.yml
vendored
@@ -9,40 +9,50 @@ jobs:
|
||||
publish_to_docker_hub:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create Docker Metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
milesmcc/shynet
|
||||
ghcr.io/milesmcc/shynet
|
||||
tags:
|
||||
type=edge
|
||||
|
||||
- name: Set swap space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 5
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare tags
|
||||
id: prep
|
||||
run: |
|
||||
DOCKER_IMAGE=milesmcc/shynet
|
||||
TAGS="${DOCKER_IMAGE}:edge"
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push advanced image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
|
||||
38
.github/workflows/build-docker-manual.yml
vendored
38
.github/workflows/build-docker-manual.yml
vendored
@@ -9,40 +9,50 @@ jobs:
|
||||
publish_to_docker_hub:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create Docker Metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
milesmcc/shynet
|
||||
ghcr.io/milesmcc/shynet
|
||||
tags:
|
||||
type=raw,value=${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Set swap space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 5
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare tags
|
||||
id: prep
|
||||
run: |
|
||||
DOCKER_IMAGE=milesmcc/shynet
|
||||
TAGS="${DOCKER_IMAGE}:${{ github.event.inputs.tag }}"
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push advanced image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
|
||||
41
.github/workflows/build-docker-release.yml
vendored
41
.github/workflows/build-docker-release.yml
vendored
@@ -9,41 +9,52 @@ jobs:
|
||||
publish_to_docker_hub:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# https://github.com/docker/metadata-action/tree/v4/#typeref
|
||||
- name: Create Docker Metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
milesmcc/shynet
|
||||
ghcr.io/milesmcc/shynet
|
||||
tags:
|
||||
type=raw,value=latest
|
||||
type=ref,event=tag
|
||||
|
||||
- name: Set swap space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 5
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare tags
|
||||
id: prep
|
||||
run: |
|
||||
DOCKER_IMAGE=milesmcc/shynet
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest"
|
||||
echo ::set-output name=tags::${TAGS}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push advanced image
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.prep.outputs.tags }}
|
||||
tags: ${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
33
Dockerfile
33
Dockerfile
@@ -7,37 +7,34 @@ WORKDIR /usr/src/shynet
|
||||
ARG GF_UID="500"
|
||||
ARG GF_GID="500"
|
||||
RUN apk update && \
|
||||
apk add gettext curl bash npm libffi-dev rust cargo
|
||||
apk add --no-cache gettext bash npm postgresql-libs && \
|
||||
test "$(arch)" != "x86_64" && apk add libffi-dev rust cargo || echo "amd64 build, skipping Rust installation"
|
||||
# libffi-dev and rust are used for the cryptography package,
|
||||
# which we indirectly rely on. Necessary for aarch64 support.
|
||||
|
||||
# Collect GeoIP Database
|
||||
RUN curl -m 180 "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN&license_key=kKG1ebhL3iWVd0iv&suffix=tar.gz" | tar -xvz -C /tmp && \
|
||||
curl -m 180 "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=kKG1ebhL3iWVd0iv&suffix=tar.gz" | tar -xvz -C /tmp && \
|
||||
RUN apk add --no-cache curl && \
|
||||
curl -m 180 "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN&license_key=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&suffix=tar.gz" | tar -xvz -C /tmp && \
|
||||
curl -m 180 "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=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&suffix=tar.gz" | tar -xvz -C /tmp && \
|
||||
mv /tmp/GeoLite2*/*.mmdb /etc && \
|
||||
apk del curl
|
||||
apk --purge del curl
|
||||
|
||||
# Move dependency files
|
||||
COPY poetry.lock pyproject.toml ./
|
||||
COPY package.json package-lock.json ../
|
||||
# Django expects node_modules to be in its parent directory.
|
||||
|
||||
# Install more dependencies
|
||||
RUN apk add --no-cache postgresql-libs && \
|
||||
apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev libressl-dev libffi-dev && \
|
||||
# Install more dependencies and cleanup build dependencies afterwards
|
||||
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev libressl-dev libffi-dev && \
|
||||
npm i -P --prefix .. && \
|
||||
pip install poetry==1.2.2
|
||||
pip install poetry==1.2.2 && \
|
||||
poetry config virtualenvs.create false && \
|
||||
poetry run pip install "Cython<3.0" "pyyaml==5.4.1" --no-build-isolation && \
|
||||
poetry install --no-dev --no-interaction --no-ansi && \
|
||||
apk --purge del .build-deps
|
||||
|
||||
# Install Python dependencies
|
||||
RUN poetry config virtualenvs.create false && \
|
||||
poetry run pip install "Cython<3.0" "pyyaml==5.4.1" --no-build-isolation && \
|
||||
poetry install --no-dev --no-interaction --no-ansi
|
||||
|
||||
# Cleanup dependencies & setup user group
|
||||
RUN apk --purge del .build-deps && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
rm /var/cache/apk/* && \
|
||||
addgroup --system -g $GF_GID appgroup && \
|
||||
# Setup user group
|
||||
RUN addgroup --system -g $GF_GID appgroup && \
|
||||
adduser appuser --system --uid $GF_UID -G appgroup && \
|
||||
mkdir -p /var/local/shynet/db/ && \
|
||||
chown -R appuser:appgroup /var/local/shynet
|
||||
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -673,9 +673,9 @@
|
||||
"integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -1243,9 +1243,9 @@
|
||||
"integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
|
||||
221
poetry.lock
generated
221
poetry.lock
generated
@@ -1,91 +1,106 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.8.1"
|
||||
version = "3.8.6"
|
||||
description = "Async http client/server framework (asyncio)"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"},
|
||||
{file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"},
|
||||
{file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"},
|
||||
{file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"},
|
||||
{file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"},
|
||||
{file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"},
|
||||
{file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-win32.whl", hash = "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2"},
|
||||
{file = "aiohttp-3.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-win32.whl", hash = "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb"},
|
||||
{file = "aiohttp-3.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d25036d161c4fe2225d1abff2bd52c34ed0b1099f02c208cd34d8c05729882f0"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d791245a894be071d5ab04bbb4850534261a7d4fd363b094a7b9963e8cdbd31"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0cccd1de239afa866e4ce5c789b3032442f19c261c7d8a01183fd956b1935349"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f13f60d78224f0dace220d8ab4ef1dbc37115eeeab8c06804fec11bec2bbd07"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a9b5a0606faca4f6cc0d338359d6fa137104c337f489cd135bb7fbdbccb1e39"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:13da35c9ceb847732bf5c6c5781dcf4780e14392e5d3b3c689f6d22f8e15ae31"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:4d4cbe4ffa9d05f46a28252efc5941e0462792930caa370a6efaf491f412bc66"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:229852e147f44da0241954fc6cb910ba074e597f06789c867cb7fb0621e0ba7a"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:713103a8bdde61d13490adf47171a1039fd880113981e55401a0f7b42c37d071"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:45ad816b2c8e3b60b510f30dbd37fe74fd4a772248a52bb021f6fd65dff809b6"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-win32.whl", hash = "sha256:2b8d4e166e600dcfbff51919c7a3789ff6ca8b3ecce16e1d9c96d95dd569eb4c"},
|
||||
{file = "aiohttp-3.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:0912ed87fee967940aacc5306d3aa8ba3a459fcd12add0b407081fbefc931e53"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e2a988a0c673c2e12084f5e6ba3392d76c75ddb8ebc6c7e9ead68248101cd446"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf3fd9f141700b510d4b190094db0ce37ac6361a6806c153c161dc6c041ccda"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3161ce82ab85acd267c8f4b14aa226047a6bee1e4e6adb74b798bd42c6ae1f80"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95fc1bf33a9a81469aa760617b5971331cdd74370d1214f0b3109272c0e1e3c"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c43ecfef7deaf0617cee936836518e7424ee12cb709883f2c9a1adda63cc460"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca80e1b90a05a4f476547f904992ae81eda5c2c85c66ee4195bb8f9c5fb47f28"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:90c72ebb7cb3a08a7f40061079817133f502a160561d0675b0a6adf231382c92"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bb54c54510e47a8c7c8e63454a6acc817519337b2b78606c4e840871a3e15349"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:de6a1c9f6803b90e20869e6b99c2c18cef5cc691363954c93cb9adeb26d9f3ae"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:a3628b6c7b880b181a3ae0a0683698513874df63783fd89de99b7b7539e3e8a8"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-win32.whl", hash = "sha256:f8ef51e459eb2ad8e7a66c1d6440c808485840ad55ecc3cafefadea47d1b1ba2"},
|
||||
{file = "aiohttp-3.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b2fe42e523be344124c6c8ef32a011444e869dc5f883c591ed87f84339de5976"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e2ee0ac5a1f5c7dd3197de309adfb99ac4617ff02b0603fd1e65b07dc772e4b"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01770d8c04bd8db568abb636c1fdd4f7140b284b8b3e0b4584f070180c1e5c62"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3c68330a59506254b556b99a91857428cab98b2f84061260a67865f7f52899f5"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89341b2c19fb5eac30c341133ae2cc3544d40d9b1892749cdd25892bbc6ac951"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71783b0b6455ac8f34b5ec99d83e686892c50498d5d00b8e56d47f41b38fbe04"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f628dbf3c91e12f4d6c8b3f092069567d8eb17814aebba3d7d60c149391aee3a"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04691bc6601ef47c88f0255043df6f570ada1a9ebef99c34bd0b72866c217ae"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee912f7e78287516df155f69da575a0ba33b02dd7c1d6614dbc9463f43066e3"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9c19b26acdd08dd239e0d3669a3dddafd600902e37881f13fbd8a53943079dbc"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:99c5ac4ad492b4a19fc132306cd57075c28446ec2ed970973bbf036bcda1bcc6"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f0f03211fd14a6a0aed2997d4b1c013d49fb7b50eeb9ffdf5e51f23cfe2c77fa"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:8d399dade330c53b4106160f75f55407e9ae7505263ea86f2ccca6bfcbdb4921"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec4fd86658c6a8964d75426517dc01cbf840bbf32d055ce64a9e63a40fd7b771"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-win32.whl", hash = "sha256:33164093be11fcef3ce2571a0dccd9041c9a93fa3bde86569d7b03120d276c6f"},
|
||||
{file = "aiohttp-3.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:bdf70bfe5a1414ba9afb9d49f0c912dc524cf60141102f3a11143ba3d291870f"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d52d5dc7c6682b720280f9d9db41d36ebe4791622c842e258c9206232251ab2b"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ac39027011414dbd3d87f7edb31680e1f430834c8cef029f11c66dad0670aa5"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3f5c7ce535a1d2429a634310e308fb7d718905487257060e5d4598e29dc17f0b"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b30e963f9e0d52c28f284d554a9469af073030030cef8693106d918b2ca92f54"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:918810ef188f84152af6b938254911055a72e0f935b5fbc4c1a4ed0b0584aed1"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:002f23e6ea8d3dd8d149e569fd580c999232b5fbc601c48d55398fbc2e582e8c"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fcf3eabd3fd1a5e6092d1242295fa37d0354b2eb2077e6eb670accad78e40e1"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:255ba9d6d5ff1a382bb9a578cd563605aa69bec845680e21c44afc2670607a95"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d67f8baed00870aa390ea2590798766256f31dc5ed3ecc737debb6e97e2ede78"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:86f20cee0f0a317c76573b627b954c412ea766d6ada1a9fcf1b805763ae7feeb"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:39a312d0e991690ccc1a61f1e9e42daa519dcc34ad03eb6f826d94c1190190dd"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e827d48cf802de06d9c935088c2924e3c7e7533377d66b6f31ed175c1620e05e"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd111d7fc5591ddf377a408ed9067045259ff2770f37e2d94e6478d0f3fc0c17"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-win32.whl", hash = "sha256:caf486ac1e689dda3502567eb89ffe02876546599bbf915ec94b1fa424eeffd4"},
|
||||
{file = "aiohttp-3.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:3f0e27e5b733803333bb2371249f41cf42bae8884863e8e8965ec69bebe53132"},
|
||||
{file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiosignal = ">=1.1.2"
|
||||
async-timeout = ">=4.0.0a3,<5.0"
|
||||
attrs = ">=17.3.0"
|
||||
charset-normalizer = ">=2.0,<3.0"
|
||||
charset-normalizer = ">=2.0,<4.0"
|
||||
frozenlist = ">=1.1.1"
|
||||
multidict = ">=4.5,<7.0"
|
||||
yarl = ">=1.0,<2.0"
|
||||
@@ -258,13 +273,13 @@ zstd = ["zstandard"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.12.7"
|
||||
version = "2023.7.22"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
|
||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||
{file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
|
||||
{file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -493,30 +508,34 @@ toml = ["tomli"]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "41.0.0"
|
||||
version = "41.0.4"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-41.0.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c5ef25d060c80d6d9f7f9892e1d41bb1c79b78ce74805b8cb4aa373cb7d5ec8"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8362565b3835ceacf4dc8f3b56471a2289cf51ac80946f9087e66dc283a810e0"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3680248309d340fda9611498a5319b0193a8dbdb73586a1acf8109d06f25b92d"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84a165379cb9d411d58ed739e4af3396e544eac190805a54ba2e0322feb55c46"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab14d567f7bbe7f1cdff1c53d5324ed4d3fc8bd17c481b395db224fb405c237"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9f65e842cb02550fac96536edb1d17f24c0a338fd84eaf582be25926e993dde4"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7f2f5c525a642cecad24ee8670443ba27ac1fab81bba4cc24c7b6b41f2d0c75"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d92f0248d38faa411d17f4107fc0bce0c42cae0b0ba5415505df72d751bf62d"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-win32.whl", hash = "sha256:34d405ea69a8b34566ba3dfb0521379b210ea5d560fafedf9f800a9a94a41928"},
|
||||
{file = "cryptography-41.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:344c6de9f8bda3c425b3a41b319522ba3208551b70c2ae00099c205f0d9fd3be"},
|
||||
{file = "cryptography-41.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:88ff107f211ea696455ea8d911389f6d2b276aabf3231bf72c8853d22db755c5"},
|
||||
{file = "cryptography-41.0.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b846d59a8d5a9ba87e2c3d757ca019fa576793e8758174d3868aecb88d6fc8eb"},
|
||||
{file = "cryptography-41.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5d0bf9b252f30a31664b6f64432b4730bb7038339bd18b1fafe129cfc2be9be"},
|
||||
{file = "cryptography-41.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5c1f7293c31ebc72163a9a0df246f890d65f66b4a40d9ec80081969ba8c78cc9"},
|
||||
{file = "cryptography-41.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf8fc66012ca857d62f6a347007e166ed59c0bc150cefa49f28376ebe7d992a2"},
|
||||
{file = "cryptography-41.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a4fc68d1c5b951cfb72dfd54702afdbbf0fb7acdc9b7dc4301bbf2225a27714d"},
|
||||
{file = "cryptography-41.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14754bcdae909d66ff24b7b5f166d69340ccc6cb15731670435efd5719294895"},
|
||||
{file = "cryptography-41.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0ddaee209d1cf1f180f1efa338a68c4621154de0afaef92b89486f5f96047c55"},
|
||||
{file = "cryptography-41.0.0.tar.gz", hash = "sha256:6b71f64beeea341c9b4f963b48ee3b62d62d57ba93eb120e1196b31dc1025e78"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"},
|
||||
{file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"},
|
||||
{file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"},
|
||||
{file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"},
|
||||
{file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"},
|
||||
{file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"},
|
||||
{file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"},
|
||||
{file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"},
|
||||
{file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"},
|
||||
{file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"},
|
||||
{file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"},
|
||||
{file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"},
|
||||
{file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"},
|
||||
{file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"},
|
||||
{file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -545,13 +564,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "4.1.10"
|
||||
version = "4.1.13"
|
||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Django-4.1.10-py3-none-any.whl", hash = "sha256:26d0260c2fb8121009e62ffc548b2398dea2522b6454208a852fb0ef264c206c"},
|
||||
{file = "Django-4.1.10.tar.gz", hash = "sha256:56343019a9fd839e2e5bf203daf45f25af79d5bffa4c71d56eae4f4404d82ade"},
|
||||
{file = "Django-4.1.13-py3-none-any.whl", hash = "sha256:04ab3f6f46d084a0bba5a2c9a93a3a2eb3fe81589512367a75f79ee8acf790ce"},
|
||||
{file = "Django-4.1.13.tar.gz", hash = "sha256:94a3f471e833c8f124ee7a2de11e92f633991d975e3fa5bdd91e8abd66426318"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
||||
29
shynet/a17t/locale/zh_TW/LC_MESSAGES/django.po
Normal file
29
shynet/a17t/locale/zh_TW/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,29 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-24 13:20+0200\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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: a17t/templates/a17t/includes/pagination.html:5
|
||||
#: a17t/templates/a17t/includes/pagination.html:7
|
||||
msgid "Previous"
|
||||
msgstr "上一頁"
|
||||
|
||||
#: a17t/templates/a17t/includes/pagination.html:10
|
||||
#: a17t/templates/a17t/includes/pagination.html:12
|
||||
msgid "Next"
|
||||
msgstr "下一頁"
|
||||
118
shynet/analytics/locale/zh_TW/LC_MESSAGES/django.po
Normal file
118
shynet/analytics/locale/zh_TW/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,118 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-24 13:20+0200\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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: analytics/models.py:18
|
||||
msgid "Service"
|
||||
msgstr "服務"
|
||||
|
||||
#: analytics/models.py:24
|
||||
msgid "Identifier"
|
||||
msgstr "識別碼"
|
||||
|
||||
#: analytics/models.py:29
|
||||
msgid "Start time"
|
||||
msgstr "開始時間"
|
||||
|
||||
#: analytics/models.py:32
|
||||
msgid "Last seen"
|
||||
msgstr "最後瀏覽"
|
||||
|
||||
#: analytics/models.py:36
|
||||
msgid "User agent"
|
||||
msgstr "使用者代理程式"
|
||||
|
||||
#: analytics/models.py:37
|
||||
msgid "Browser"
|
||||
msgstr "瀏覽器"
|
||||
|
||||
#: analytics/models.py:38
|
||||
msgid "Device"
|
||||
msgstr "裝置"
|
||||
|
||||
#: analytics/models.py:42
|
||||
msgid "Phone"
|
||||
msgstr "手機"
|
||||
|
||||
#: analytics/models.py:43
|
||||
msgid "Tablet"
|
||||
msgstr "平板"
|
||||
|
||||
#: analytics/models.py:44
|
||||
msgid "Desktop"
|
||||
msgstr "桌上型電腦"
|
||||
|
||||
#: analytics/models.py:45
|
||||
msgid "Robot"
|
||||
msgstr "機器人"
|
||||
|
||||
#: analytics/models.py:46
|
||||
msgid "Other"
|
||||
msgstr "其他"
|
||||
|
||||
#: analytics/models.py:49
|
||||
msgid "Device type"
|
||||
msgstr "裝置類型"
|
||||
|
||||
#: analytics/models.py:51
|
||||
msgid "OS"
|
||||
msgstr "作業系統"
|
||||
|
||||
#: analytics/models.py:52
|
||||
msgid "IP"
|
||||
msgstr "IP"
|
||||
|
||||
#: analytics/models.py:55
|
||||
msgid "Asn"
|
||||
msgstr "ASN"
|
||||
|
||||
#: analytics/models.py:56
|
||||
msgid "Country"
|
||||
msgstr "國家"
|
||||
|
||||
#: analytics/models.py:57
|
||||
msgid "Longitude"
|
||||
msgstr "經度"
|
||||
|
||||
#: analytics/models.py:58
|
||||
msgid "Latitude"
|
||||
msgstr "緯度"
|
||||
|
||||
#: analytics/models.py:59
|
||||
msgid "Time zone"
|
||||
msgstr "時區"
|
||||
|
||||
#: analytics/models.py:61
|
||||
msgid "Is bounce"
|
||||
msgstr "是否為跳出"
|
||||
|
||||
#: analytics/models.py:64 analytics/models.py:100
|
||||
msgid "Session"
|
||||
msgstr "工作階段"
|
||||
|
||||
#: analytics/models.py:65
|
||||
msgid "Sessions"
|
||||
msgstr "工作階段次數"
|
||||
|
||||
#: analytics/models.py:122
|
||||
msgid "Hit"
|
||||
msgstr "點選"
|
||||
|
||||
#: analytics/models.py:123
|
||||
msgid "Hits"
|
||||
msgstr "點選次數"
|
||||
@@ -1,7 +1,10 @@
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from http import HTTPStatus
|
||||
|
||||
from core.models import User
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.http import JsonResponse
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class ApiTokenRequiredMixin:
|
||||
@@ -11,13 +14,13 @@ class ApiTokenRequiredMixin:
|
||||
return AnonymousUser()
|
||||
|
||||
token = token.split(" ")[1]
|
||||
user = User.objects.filter(api_token=token).first()
|
||||
|
||||
return user if user else AnonymousUser()
|
||||
user: User = User.objects.filter(api_token=token).first()
|
||||
return user or AnonymousUser()
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
request.user = self._get_user_by_token(request)
|
||||
if not request.user.is_authenticated:
|
||||
return JsonResponse(data={}, status=403)
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
return (
|
||||
super().dispatch(request, *args, **kwargs)
|
||||
if request.user.is_authenticated
|
||||
else JsonResponse(data={}, status=HTTPStatus.FORBIDDEN)
|
||||
)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
0
shynet/api/tests/__init__.py
Normal file
0
shynet/api/tests/__init__.py
Normal file
77
shynet/api/tests/test_mixins.py
Normal file
77
shynet/api/tests/test_mixins.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from http import HTTPStatus
|
||||
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.views import View
|
||||
|
||||
from api.mixins import ApiTokenRequiredMixin
|
||||
from core.factories import UserFactory
|
||||
from core.models import _default_api_token, Service
|
||||
|
||||
|
||||
class TestApiTokenRequiredMixin(TestCase):
|
||||
class DummyView(ApiTokenRequiredMixin, View):
|
||||
model = Service
|
||||
template_name = "dashboard/pages/service.html"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = UserFactory()
|
||||
self.request = RequestFactory().get("/fake-path")
|
||||
|
||||
# Setup request and view.
|
||||
self.factory = RequestFactory()
|
||||
self.view = self.DummyView()
|
||||
|
||||
def test_get_user_by_token_without_authorization_token(self):
|
||||
"""
|
||||
GIVEN: A request without Authorization header
|
||||
WHEN: get_user_by_token is called
|
||||
THEN: It should return AnonymousUser
|
||||
"""
|
||||
user = self.view._get_user_by_token(self.request)
|
||||
|
||||
self.assertEqual(user.is_anonymous, True)
|
||||
|
||||
def test_get_user_by_token_with_invalid_authorization_token(self):
|
||||
"""
|
||||
GIVEN: A request with invalid Authorization header
|
||||
WHEN: get_user_by_token is called
|
||||
THEN: It should return AnonymousUser
|
||||
"""
|
||||
self.request.META["HTTP_AUTHORIZATION"] = "Bearer invalid-token"
|
||||
user = self.view._get_user_by_token(self.request)
|
||||
|
||||
self.assertEqual(user.is_anonymous, True)
|
||||
|
||||
def test_get_user_by_token_with_invalid_token(self):
|
||||
"""
|
||||
GIVEN: A request with invalid token
|
||||
WHEN: get_user_by_token is called
|
||||
THEN: It should return AnonymousUser
|
||||
"""
|
||||
self.request.META["HTTP_AUTHORIZATION"] = f"Token {_default_api_token()}"
|
||||
user = self.view._get_user_by_token(self.request)
|
||||
|
||||
self.assertEqual(user.is_anonymous, True)
|
||||
|
||||
def test_get_user_by_token_with_valid_token(self):
|
||||
"""
|
||||
GIVEN: A request with valid token
|
||||
WHEN: get_user_by_token is called
|
||||
THEN: It should return the user
|
||||
"""
|
||||
self.request.META["HTTP_AUTHORIZATION"] = f"Token {self.user.api_token}"
|
||||
user = self.view._get_user_by_token(self.request)
|
||||
|
||||
self.assertEqual(user, self.user)
|
||||
|
||||
def test_dispatch_with_unauthenticated_user(self):
|
||||
"""
|
||||
GIVEN: A request with unauthenticated user
|
||||
WHEN: dispatch is called
|
||||
THEN: It should return 403
|
||||
"""
|
||||
self.request.META["HTTP_AUTHORIZATION"] = f"Token {_default_api_token()}"
|
||||
response = self.view.dispatch(self.request)
|
||||
|
||||
self.assertEqual(response.status_code, HTTPStatus.FORBIDDEN)
|
||||
79
shynet/api/tests/test_views.py
Normal file
79
shynet/api/tests/test_views.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.urls import reverse
|
||||
|
||||
from api.views import DashboardApiView
|
||||
from core.factories import UserFactory, ServiceFactory
|
||||
from core.models import Service
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class TestDashboardApiView(TestCase):
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
self.user: User = UserFactory()
|
||||
self.service_1: Service = ServiceFactory(owner=self.user)
|
||||
self.service_2: Service = ServiceFactory(owner=self.user)
|
||||
self.url = reverse("api:services")
|
||||
self.factory = RequestFactory()
|
||||
|
||||
def test_get_with_unauthenticated_user(self):
|
||||
"""
|
||||
GIVEN: An unauthenticated user
|
||||
WHEN: The user makes a GET request to the dashboard API view
|
||||
THEN: It should return 403
|
||||
"""
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, HTTPStatus.FORBIDDEN)
|
||||
|
||||
def test_get_returns_400(self):
|
||||
"""
|
||||
GIVEN: An authenticated user
|
||||
WHEN: The user makes a GET request to the dashboard API view with an invalid date format
|
||||
THEN: It should return 400
|
||||
"""
|
||||
request = self.factory.get(self.url, {"startDate": "01/01/2000"})
|
||||
request.META["HTTP_AUTHORIZATION"] = f"Token {self.user.api_token}"
|
||||
|
||||
response = DashboardApiView.as_view()(request)
|
||||
self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST)
|
||||
|
||||
data = json.loads(response.content)
|
||||
self.assertEqual(data["error"], "Invalid date format. Use YYYY-MM-DD.")
|
||||
|
||||
def test_get_with_authenticated_user(self):
|
||||
"""
|
||||
GIVEN: An authenticated user
|
||||
WHEN: The user makes a GET request to the dashboard API view
|
||||
THEN: It should return 200
|
||||
"""
|
||||
request = self.factory.get(self.url)
|
||||
request.META["HTTP_AUTHORIZATION"] = f"Token {self.user.api_token}"
|
||||
|
||||
response = DashboardApiView.as_view()(request)
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
|
||||
data = json.loads(response.content)
|
||||
self.assertEqual(len(data["services"]), 2)
|
||||
|
||||
def test_get_with_service_uuid(self):
|
||||
"""
|
||||
GIVEN: An authenticated user
|
||||
WHEN: The user makes a GET request to the dashboard API view with a service UUID
|
||||
THEN: It should return 200 and a single service
|
||||
"""
|
||||
request = self.factory.get(self.url, {"uuid": str(self.service_1.uuid)})
|
||||
request.META["HTTP_AUTHORIZATION"] = f"Token {self.user.api_token}"
|
||||
|
||||
response = DashboardApiView.as_view()(request)
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
|
||||
data = json.loads(response.content)
|
||||
self.assertEqual(len(data["services"]), 1)
|
||||
self.assertEqual(data["services"][0]["uuid"], str(self.service_1.uuid))
|
||||
self.assertEqual(data["services"][0]["name"], str(self.service_1.name))
|
||||
|
||||
@@ -1,54 +1,46 @@
|
||||
import uuid
|
||||
from django.http import JsonResponse
|
||||
from http import HTTPStatus
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import JsonResponse
|
||||
from django.views.generic import View
|
||||
|
||||
from dashboard.mixins import DateRangeMixin
|
||||
from core.models import Service
|
||||
|
||||
from core.utils import is_valid_uuid
|
||||
from dashboard.mixins import DateRangeMixin
|
||||
from .mixins import ApiTokenRequiredMixin
|
||||
|
||||
|
||||
def is_valid_uuid(value):
|
||||
try:
|
||||
uuid.UUID(value)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
class DashboardApiView(ApiTokenRequiredMixin, DateRangeMixin, View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
services = Service.objects.filter(
|
||||
Q(owner=request.user) | Q(collaborators__in=[request.user])
|
||||
).distinct()
|
||||
services = Service.objects.filter(Q(owner=request.user) | Q(collaborators__in=[request.user])).distinct()
|
||||
|
||||
uuid = request.GET.get("uuid")
|
||||
if uuid and is_valid_uuid(uuid):
|
||||
services = services.filter(uuid=uuid)
|
||||
uuid_ = request.GET.get("uuid")
|
||||
if uuid_ and is_valid_uuid(uuid_):
|
||||
services = services.filter(uuid=uuid_)
|
||||
|
||||
try:
|
||||
start = self.get_start_date()
|
||||
end = self.get_end_date()
|
||||
except ValueError:
|
||||
return JsonResponse(status=400, data={"error": "Invalid date format"})
|
||||
return JsonResponse(status=HTTPStatus.BAD_REQUEST, data={"error": "Invalid date format. Use YYYY-MM-DD."})
|
||||
|
||||
service: Service
|
||||
services_data = [
|
||||
{
|
||||
"name": s.name,
|
||||
"uuid": s.uuid,
|
||||
"link": s.link,
|
||||
"stats": s.get_core_stats(start, end),
|
||||
"name": service.name,
|
||||
"uuid": service.uuid,
|
||||
"link": service.link,
|
||||
"stats": service.get_core_stats(start, end),
|
||||
}
|
||||
for s in services
|
||||
for service in services
|
||||
]
|
||||
|
||||
services_data = self._convert_querysets_to_lists(services_data)
|
||||
|
||||
return JsonResponse(data={"services": services_data})
|
||||
|
||||
def _convert_querysets_to_lists(self, services_data):
|
||||
def _convert_querysets_to_lists(self, services_data: list[dict]) -> list[dict]:
|
||||
for service_data in services_data:
|
||||
for key, value in service_data["stats"].items():
|
||||
if isinstance(value, QuerySet):
|
||||
|
||||
87
shynet/core/locale/zh_TW/LC_MESSAGES/django.po
Normal file
87
shynet/core/locale/zh_TW/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,87 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-24 13:20+0200\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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: core/models.py:58
|
||||
msgid "Active"
|
||||
msgstr "啟用"
|
||||
|
||||
#: core/models.py:58
|
||||
msgid "Archived"
|
||||
msgstr "已封存"
|
||||
|
||||
#: core/models.py:61
|
||||
msgid "Name"
|
||||
msgstr "名稱"
|
||||
|
||||
#: core/models.py:63
|
||||
msgid "Owner"
|
||||
msgstr "擁有者"
|
||||
|
||||
#: core/models.py:67
|
||||
msgid "Collaborators"
|
||||
msgstr "協作者"
|
||||
|
||||
#: core/models.py:70
|
||||
msgid "created"
|
||||
msgstr "已建立"
|
||||
|
||||
#: core/models.py:71
|
||||
msgid "link"
|
||||
msgstr "連結"
|
||||
|
||||
#: core/models.py:72
|
||||
msgid "origins"
|
||||
msgstr "來源"
|
||||
|
||||
#: core/models.py:75
|
||||
msgid "status"
|
||||
msgstr "狀態"
|
||||
|
||||
#: core/models.py:77
|
||||
msgid "Respect dnt"
|
||||
msgstr "尊重停止追蹤 (Do Not Track) 設定"
|
||||
|
||||
#: core/models.py:78
|
||||
msgid "Ignore robots"
|
||||
msgstr "忽略機器人"
|
||||
|
||||
#: core/models.py:79
|
||||
msgid "Collect ips"
|
||||
msgstr "收集 IP"
|
||||
|
||||
#: core/models.py:82
|
||||
msgid "Igored ips"
|
||||
msgstr "忽略的 IP"
|
||||
|
||||
#: core/models.py:86
|
||||
msgid "Hide referrer regex"
|
||||
msgstr "隱藏來源參照正規表達式"
|
||||
|
||||
#: core/models.py:88
|
||||
msgid "Script inject"
|
||||
msgstr "插入指令碼"
|
||||
|
||||
#: core/models.py:91
|
||||
msgid "Service"
|
||||
msgstr "服務"
|
||||
|
||||
#: core/models.py:92
|
||||
msgid "Services"
|
||||
msgstr "服務"
|
||||
10
shynet/core/utils.py
Normal file
10
shynet/core/utils.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import uuid
|
||||
|
||||
|
||||
def is_valid_uuid(value: str) -> bool:
|
||||
"""Check if a string is a valid UUID."""
|
||||
try:
|
||||
uuid.UUID(value)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
659
shynet/dashboard/locale/zh_TW/LC_MESSAGES/django.po
Normal file
659
shynet/dashboard/locale/zh_TW/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,659 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-24 13:43+0200\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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: forms.py:28 forms.py:29 forms.py:30 forms.py:59
|
||||
msgid "Yes"
|
||||
msgstr "是"
|
||||
|
||||
#: forms.py:28 forms.py:29 forms.py:30 forms.py:59
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
|
||||
#: forms.py:35
|
||||
msgid "Allowed origins"
|
||||
msgstr "允許的來源"
|
||||
|
||||
#: forms.py:36
|
||||
msgid "Respect DNT"
|
||||
msgstr "尊重停止追蹤 (Do Not Track) 設定"
|
||||
|
||||
#: forms.py:37
|
||||
msgid "Ignored IP addresses"
|
||||
msgstr "忽略的 IP"
|
||||
|
||||
#: forms.py:38
|
||||
msgid "Ignore robots"
|
||||
msgstr "忽略機器人"
|
||||
|
||||
#: forms.py:39
|
||||
msgid "Hide specific referrers"
|
||||
msgstr "隱藏特定的參照來源"
|
||||
|
||||
#: forms.py:40
|
||||
msgid "Additional injected JS"
|
||||
msgstr "額外插入的 JS"
|
||||
|
||||
#: forms.py:43
|
||||
msgid "What should the service be called?"
|
||||
msgstr "這項服務應該被稱為什麼?"
|
||||
|
||||
#: forms.py:44
|
||||
msgid "What's the service's primary URL?"
|
||||
msgstr "服務的主要 URL 是什麼?"
|
||||
|
||||
#: forms.py:46
|
||||
msgid ""
|
||||
"At what origins does the service operate? Use commas to separate multiple "
|
||||
"values. This sets CORS headers, so use '*' if you're not sure (or don't "
|
||||
"care)."
|
||||
msgstr ""
|
||||
"服務在哪些來源運作?使用逗號分隔多個值。這設定了 CORS 標頭,所以如果你不確定(或不在乎),請使用 '*'。"
|
||||
|
||||
#: forms.py:48
|
||||
msgid ""
|
||||
"Should visitors who have enabled <a href='https://en.wikipedia.org/wiki/"
|
||||
"Do_Not_Track'>Do Not Track</a> be excluded from all data?"
|
||||
msgstr ""
|
||||
"是否應排除已啟用 <a href='https://en.wikipedia.org/wiki/Do_Not_Track'>停止追蹤 (Do Not Track)</a> 的訪客的所有資料?"
|
||||
|
||||
#: forms.py:49
|
||||
msgid ""
|
||||
"A comma-separated list of IP addresses or IP ranges (IPv4 and IPv6) to "
|
||||
"exclude from tracking (e.g., '192.168.0.2, 127.0.0.1/32')."
|
||||
msgstr ""
|
||||
"要從追蹤中排除的 IP 位址或 IP 範圍(IPv4 和 IPv6)的逗號分隔列表(例如,'192.168.0.2, 127.0.0.1/32')。"
|
||||
|
||||
#: forms.py:50
|
||||
msgid "Should sessions generated by bots be excluded from tracking?"
|
||||
msgstr "是否應排除由機器人產生的工作階段從追蹤中?"
|
||||
|
||||
#: forms.py:51
|
||||
msgid ""
|
||||
"Any referrers that match this <a href='https://regexr.com/'>RegEx</a> will "
|
||||
"not be listed in the referrer summary. Sessions will still be tracked "
|
||||
"normally. No effect if left blank."
|
||||
msgstr ""
|
||||
"任何符合此 <a href='https://regexr.com/'>RegEx</a> 的參照來源將不會在參照來源摘要中列出。工作階段仍將正常追蹤。如果留空則無效果。"
|
||||
|
||||
#: forms.py:52
|
||||
msgid ""
|
||||
"Optional additional JavaScript to inject at the end of the Shynet script. "
|
||||
"This code will be injected on every page where this service is installed."
|
||||
msgstr ""
|
||||
"選擇性的額外 JavaScript,插入到 Shynet 指令碼的末端。此程式碼將插入到安裝此服務的每個頁面上。"
|
||||
|
||||
#: forms.py:56
|
||||
msgid "IP address collection is disabled globally by your administrator."
|
||||
msgstr "您的管理員已全域停用 IP 收集。"
|
||||
|
||||
#: forms.py:58
|
||||
msgid ""
|
||||
"Should individual IP addresses be collected? IP metadata (location, host, "
|
||||
"etc) will still be collected."
|
||||
msgstr "是否應收集個別 IP ?仍將收集 IP 中繼資料(位置、主機等)。"
|
||||
|
||||
#: forms.py:71
|
||||
msgid ""
|
||||
"Which users on this Shynet instance should have read-only access to this "
|
||||
"service? (Comma separated list of emails.)"
|
||||
msgstr ""
|
||||
"此 Shynet 服務上的哪些使用者應具有對此服務的唯讀存取權限?(電子郵件的逗號分隔列表。)"
|
||||
|
||||
#: templates/account/account_inactive.html:5
|
||||
#: templates/account/account_inactive.html:6
|
||||
msgid "Account Inactive"
|
||||
msgstr "帳戶不活躍"
|
||||
|
||||
#: templates/account/account_inactive.html:9
|
||||
msgid "This account is inactive."
|
||||
msgstr "此帳戶不活躍。"
|
||||
|
||||
#: templates/account/email.html:5 templates/account/email.html:6
|
||||
msgid "Email Addresses"
|
||||
msgstr "電子郵件地址"
|
||||
|
||||
#: templates/account/email.html:12
|
||||
msgid "These are your known email addresses:"
|
||||
msgstr "這些是您的已知電子郵件地址:"
|
||||
|
||||
#: templates/account/email.html:26
|
||||
msgid "Verified"
|
||||
msgstr "已驗證"
|
||||
|
||||
#: templates/account/email.html:28
|
||||
msgid "Unverified"
|
||||
msgstr "未驗證"
|
||||
|
||||
#: templates/account/email.html:30
|
||||
msgid "Primary"
|
||||
msgstr "主要"
|
||||
|
||||
#: templates/account/email.html:36
|
||||
msgid "Make Primary"
|
||||
msgstr "設為預設"
|
||||
|
||||
#: templates/account/email.html:37
|
||||
msgid "Resend Verification"
|
||||
msgstr "重新傳送驗證"
|
||||
|
||||
#: templates/account/email.html:38
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
||||
|
||||
#: templates/account/email.html:46
|
||||
msgid ""
|
||||
"You currently do not have an email address associated with your account. "
|
||||
"Without one, you won't be able to reset your password, receive "
|
||||
"notifications, etc."
|
||||
msgstr ""
|
||||
"您目前的帳戶沒有關聯的電子郵件地址。沒有它,您將無法重設密碼、接收通知等。"
|
||||
|
||||
#: templates/account/email.html:57
|
||||
msgid "Add Address"
|
||||
msgstr "新增地址"
|
||||
|
||||
#: templates/account/email.html:66
|
||||
msgid "Do you really want to remove the selected email address?"
|
||||
msgstr "您真的要移除選定的電子郵件地址嗎?"
|
||||
|
||||
#: templates/account/email/email_confirmation_message.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Hi there,\n"
|
||||
"\n"
|
||||
"You're receiving this email because %(user_display)s has listed this email "
|
||||
"as a valid contact address for their account.\n"
|
||||
"\n"
|
||||
"To confirm this is correct, go to %(activate_url)s\n"
|
||||
msgstr ""
|
||||
"您好,\n"
|
||||
"\n"
|
||||
"您收到此電子郵件是因為 %(user_display)s 已將此電子郵件列為其帳戶的有效聯絡地址。\n"
|
||||
"\n"
|
||||
"要確認這是正確的,請前往 %(activate_url)s\n"
|
||||
|
||||
#: templates/account/email/email_confirmation_message.txt:7
|
||||
#: templates/account/email/password_reset_key_message.txt:9
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Thank you,\n"
|
||||
"%(site_name)s\n"
|
||||
msgstr ""
|
||||
"謝謝您,\n"
|
||||
"%(site_name)s\n"
|
||||
|
||||
#: templates/account/email/email_confirmation_subject.txt:3
|
||||
#: templates/account/email_confirm.html:6
|
||||
#: templates/account/email_confirm.html:7
|
||||
msgid "Confirm Email Address"
|
||||
msgstr "確認電子郵件地址"
|
||||
|
||||
#: templates/account/email/password_reset_key_message.txt:1
|
||||
msgid ""
|
||||
"Hi there,\n"
|
||||
"\n"
|
||||
"You're receiving this email because you or someone else has requested a "
|
||||
"password for your account.\n"
|
||||
"\n"
|
||||
"This message can be safely ignored if you did not request a password reset. "
|
||||
"Click the link below to reset your password."
|
||||
msgstr ""
|
||||
"您好,\n"
|
||||
"\n"
|
||||
"您收到此電子郵件是因為您或其他人已為您的帳戶請求密碼。\n"
|
||||
"\n"
|
||||
"如果您未請求重設密碼,則可以安全地忽略此訊息。點選下面的連結來重設您的密碼。"
|
||||
|
||||
#: templates/account/email/password_reset_key_subject.txt:3
|
||||
msgid "Password Reset Email"
|
||||
msgstr "密碼重設電子郵件"
|
||||
|
||||
#: templates/account/email_confirm.html:15
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please confirm that <a\n"
|
||||
" href=\"mailto:%(email)s\">%(email)s</a> is a valid email where we "
|
||||
"can reach you."
|
||||
msgstr ""
|
||||
"請確認 <a\n"
|
||||
" href=\"mailto:%(email)s\">%(email)s</a> 是我們可以聯絡您的有效電子郵件。"
|
||||
|
||||
#: templates/account/email_confirm.html:21
|
||||
msgid "Confirm"
|
||||
msgstr "確認"
|
||||
|
||||
#: templates/account/email_confirm.html:28
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This email confirmation link expired or is invalid. Please <a href="
|
||||
"\"%(email_url)s\">issue a new\n"
|
||||
" email confirmation request</a>."
|
||||
msgstr ""
|
||||
"此電子郵件確認連結已過期或無效。請<a href=\"%(email_url)s\">發出新的電子郵件確認請求</a>。"
|
||||
|
||||
#: templates/account/login.html:6 templates/account/login.html:7
|
||||
#: templates/account/login.html:19
|
||||
msgid "Sign In"
|
||||
msgstr "登入"
|
||||
|
||||
#: templates/account/login.html:20 templates/account/password_reset.html:21
|
||||
msgid "Reset Password"
|
||||
msgstr "重設密碼"
|
||||
|
||||
#: templates/account/logout.html:5 templates/account/logout.html:6
|
||||
#: templates/account/logout.html:16
|
||||
msgid "Sign Out"
|
||||
msgstr "登出"
|
||||
|
||||
#: templates/account/logout.html:9
|
||||
msgid "Are you sure you want to sign out?"
|
||||
msgstr "您確定要登出嗎?"
|
||||
|
||||
#: templates/account/messages/cannot_delete_primary_email.txt:2
|
||||
#, python-format
|
||||
msgid "You cannot remove your primary email address (%(email)s)."
|
||||
msgstr "您不能移除您的主要電子郵件地址 (%(email)s)。"
|
||||
|
||||
#: templates/account/messages/email_confirmation_sent.txt:2
|
||||
#, python-format
|
||||
msgid "Confirmation email sent to %(email)s."
|
||||
msgstr "確認電子郵件已傳送到 %(email)s。"
|
||||
|
||||
#: templates/account/messages/email_confirmed.txt:2
|
||||
#, python-format
|
||||
msgid "Confirmed %(email)s."
|
||||
msgstr "已確認 %(email)s。"
|
||||
|
||||
#: templates/account/messages/email_deleted.txt:2
|
||||
#, python-format
|
||||
msgid "Removed email address %(email)s."
|
||||
msgstr "已移除電子郵件地址 %(email)s。"
|
||||
|
||||
#: templates/account/messages/logged_in.txt:4
|
||||
#, python-format
|
||||
msgid "Successfully signed in as %(name)s."
|
||||
msgstr "成功以 %(name)s 的身份登入。"
|
||||
|
||||
#: templates/account/messages/logged_out.txt:2
|
||||
msgid "You have signed out."
|
||||
msgstr "您已登出。"
|
||||
|
||||
#: templates/account/messages/password_changed.txt:2
|
||||
msgid "Password successfully changed."
|
||||
msgstr "密碼已成功更改。"
|
||||
|
||||
#: templates/account/messages/password_set.txt:2
|
||||
msgid "Password successfully set."
|
||||
msgstr "密碼已成功設定。"
|
||||
|
||||
#: templates/account/messages/primary_email_set.txt:2
|
||||
msgid "New primary email address set."
|
||||
msgstr "已設定新的主要電子郵件地址。"
|
||||
|
||||
#: templates/account/messages/unverified_primary_email.txt:2
|
||||
msgid "Your primary email address must be verified."
|
||||
msgstr "您的主要電子郵件地址必須經過驗證。"
|
||||
|
||||
#: templates/account/password_change.html:5
|
||||
#: templates/account/password_change.html:6
|
||||
#: templates/account/password_change.html:12
|
||||
#: templates/account/password_reset_from_key.html:4
|
||||
#: templates/account/password_reset_from_key.html:5
|
||||
#: templates/account/password_reset_from_key.html:16
|
||||
#: templates/account/password_reset_from_key_done.html:4
|
||||
#: templates/account/password_reset_from_key_done.html:5
|
||||
msgid "Change Password"
|
||||
msgstr "更改密碼"
|
||||
|
||||
#: templates/account/password_reset.html:6
|
||||
#: templates/account/password_reset.html:7
|
||||
#: templates/account/password_reset_done.html:6
|
||||
#: templates/account/password_reset_done.html:7
|
||||
msgid "Password Reset"
|
||||
msgstr "密碼重設"
|
||||
|
||||
#: templates/account/password_reset.html:15
|
||||
msgid ""
|
||||
"Forgotten your password? Enter your email address below, and we'll send you "
|
||||
"an email to reset it."
|
||||
msgstr ""
|
||||
"忘記了您的密碼?在下面輸入您的電子郵件地址,我們將向您傳送電子郵件以重設它。"
|
||||
|
||||
#: templates/account/password_reset_done.html:14
|
||||
msgid ""
|
||||
"We have sent you an email with a password reset link. Please try again if "
|
||||
"you do not receive it within a few minutes."
|
||||
msgstr ""
|
||||
"我們已向您發送了一封帶有密碼重設連結的電子郵件。如果您在幾分鐘內未收到,請再試一次。"
|
||||
|
||||
#: templates/account/password_reset_from_key.html:10
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The password reset link was invalid, possibly because it has already been "
|
||||
"used. Please request a <a href=\"%(passwd_reset_url)s\">new password reset</"
|
||||
"a>."
|
||||
msgstr ""
|
||||
"密碼重設連結無效,可能是因為它已被使用。請請求<a href=\"%(passwd_reset_url)s\">新的密碼重設</a>。"
|
||||
|
||||
#: templates/account/password_reset_from_key.html:19
|
||||
#: templates/account/password_reset_from_key_done.html:8
|
||||
msgid "Your password is now changed."
|
||||
msgstr "您的密碼現在已更改。"
|
||||
|
||||
#: templates/account/password_set.html:5 templates/account/password_set.html:6
|
||||
#: templates/account/password_set.html:12
|
||||
msgid "Set Password"
|
||||
msgstr "設定密碼"
|
||||
|
||||
#: templates/account/signup.html:5 templates/account/signup.html:6
|
||||
#: templates/account/signup.html:17
|
||||
msgid "Sign Up"
|
||||
msgstr "註冊"
|
||||
|
||||
#: templates/account/signup.html:9
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Already have an account? Then please <a href=\"%(login_url)s\">sign in</a> "
|
||||
"instead."
|
||||
msgstr ""
|
||||
"已經有帳戶了嗎?那麼請<a href=\"%(login_url)s\">登入</a>。"
|
||||
|
||||
#: templates/account/signup_closed.html:5
|
||||
#: templates/account/signup_closed.html:6
|
||||
msgid "Sign Up Closed"
|
||||
msgstr "註冊已關閉"
|
||||
|
||||
#: templates/account/signup_closed.html:9
|
||||
msgid "Public sign-ups are not allowed at this time."
|
||||
msgstr "目前不允許公開註冊。"
|
||||
|
||||
#: templates/account/snippets/already_logged_in.html:6
|
||||
msgid "Note"
|
||||
msgstr "注意"
|
||||
|
||||
#: templates/account/snippets/already_logged_in.html:6
|
||||
#, python-format
|
||||
msgid "you are already logged in as %(user_display)s."
|
||||
msgstr "您已經以 %(user_display)s 的身份登入。"
|
||||
|
||||
#: templates/account/verification_sent.html:5
|
||||
#: templates/account/verification_sent.html:6
|
||||
#: templates/account/verified_email_required.html:5
|
||||
#: templates/account/verified_email_required.html:6
|
||||
msgid "Verify Email Address"
|
||||
msgstr "驗證電子郵件地址"
|
||||
|
||||
#: templates/account/verification_sent.html:9
|
||||
msgid ""
|
||||
"We have sent an email to you for verification. Follow the link provided to "
|
||||
"finalize the signup process. Please try to log in again if you do not "
|
||||
"receive it within a few minutes."
|
||||
msgstr ""
|
||||
"我們已向您發送了一封驗證電子郵件。按照提供的連結完成註冊過程。如果您在幾分鐘內未收到,請再試一次登入。"
|
||||
|
||||
#: templates/account/verified_email_required.html:11
|
||||
msgid ""
|
||||
"This part of the site requires us to verify that\n"
|
||||
"you are who you claim to be. For this purpose, we require that you\n"
|
||||
"verify ownership of your email address. "
|
||||
msgstr ""
|
||||
"該網站的這一部分要求我們驗證\n"
|
||||
"您是您聲稱的人。為此,我們要求您\n"
|
||||
"驗證您的電子郵件地址的所有權。"
|
||||
|
||||
#: templates/account/verified_email_required.html:15
|
||||
msgid ""
|
||||
"We have sent an email to you for\n"
|
||||
"verification. Please click on the link inside this email. Please\n"
|
||||
"try again if you do not receive it within a few minutes."
|
||||
msgstr ""
|
||||
"我們已向您發送了一封驗證電子郵件。\n"
|
||||
"請點選此電子郵件內的連結。請\n"
|
||||
"如果您在幾分鐘內未收到,請再試一次。"
|
||||
|
||||
#: templates/account/verified_email_required.html:19
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<strong>Note:</strong> you can still <a href=\"%(email_url)s\">change your "
|
||||
"email address</a>."
|
||||
msgstr ""
|
||||
"<strong>注意:</strong>您仍然可以<a href=\"%(email_url)s\">更改您的電子郵件地址</a>。"
|
||||
|
||||
#: templates/base.html:47
|
||||
msgid "Services"
|
||||
msgstr "服務"
|
||||
|
||||
#: templates/base.html:60
|
||||
msgid "+ Create"
|
||||
msgstr "+ 建立"
|
||||
|
||||
#: templates/base.html:69
|
||||
msgid "Collaborations"
|
||||
msgstr "合作"
|
||||
|
||||
#: templates/base.html:81
|
||||
msgid "Account"
|
||||
msgstr "帳戶"
|
||||
|
||||
#: templates/dashboard/includes/service_form.html:8
|
||||
msgid "Advanced settings"
|
||||
msgstr "進階設定"
|
||||
|
||||
#: templates/dashboard/includes/service_overview.html:15
|
||||
#: templates/dashboard/pages/service_session_list.html:5
|
||||
msgid "Sessions"
|
||||
msgstr "工作階段"
|
||||
|
||||
#: templates/dashboard/includes/service_overview.html:22
|
||||
#: templates/dashboard/includes/session_list.html:9
|
||||
#: templates/dashboard/pages/service.html:38
|
||||
#: templates/dashboard/pages/service.html:110
|
||||
msgid "Hits"
|
||||
msgstr "點選次數"
|
||||
|
||||
#: templates/dashboard/includes/service_overview.html:29
|
||||
#: templates/dashboard/pages/service.html:60
|
||||
msgid "Bounce Rate"
|
||||
msgstr "跳出率"
|
||||
|
||||
#: templates/dashboard/includes/service_overview.html:40
|
||||
msgid "Avg. Duration"
|
||||
msgstr "平均持續時間"
|
||||
|
||||
#: templates/dashboard/includes/session_list.html:5
|
||||
msgid "Session Start"
|
||||
msgstr "工作階段開始"
|
||||
|
||||
#: templates/dashboard/includes/session_list.html:6
|
||||
msgid "Identity"
|
||||
msgstr "身份"
|
||||
|
||||
#: templates/dashboard/includes/session_list.html:7
|
||||
#: templates/dashboard/pages/service.html:73
|
||||
#: templates/dashboard/pages/service_session.html:81
|
||||
msgid "Duration"
|
||||
msgstr "持續時間"
|
||||
|
||||
#: templates/dashboard/includes/session_list.html:36
|
||||
msgid "No data yet"
|
||||
msgstr "尚無資料"
|
||||
|
||||
#: templates/dashboard/pages/dashboard.html:16
|
||||
msgid "New Service"
|
||||
msgstr "新服務"
|
||||
|
||||
#: templates/dashboard/pages/index.html:6
|
||||
#: templates/dashboard/pages/service_session_list.html:9
|
||||
msgid "Analytics"
|
||||
msgstr "分析"
|
||||
|
||||
#: templates/dashboard/pages/index.html:8
|
||||
msgid "Log In"
|
||||
msgstr "登入"
|
||||
|
||||
#: templates/dashboard/pages/service.html:9
|
||||
msgid "Manage"
|
||||
msgstr "管理"
|
||||
|
||||
#: templates/dashboard/pages/service.html:17
|
||||
msgid ""
|
||||
"This service hasn't collected any data yet. To get started, place the "
|
||||
"following code snippet at the end of the <code><body></code> tag on "
|
||||
"any page you'd like to track."
|
||||
msgstr ""
|
||||
"此服務尚未收集任何資料。要開始,請將以下程式碼片段放在您想要追蹤的任何頁面的 <code><body></code> 標籤的末端。"
|
||||
|
||||
#: templates/dashboard/pages/service.html:29
|
||||
#: templates/dashboard/pages/service.html:158
|
||||
#: templates/dashboard/pages/service.html:192
|
||||
#: templates/dashboard/pages/service.html:226
|
||||
#: templates/dashboard/pages/service.html:260
|
||||
#: templates/dashboard/pages/service.html:295
|
||||
msgid "sessions"
|
||||
msgstr "工作階段"
|
||||
|
||||
#: templates/dashboard/pages/service.html:47
|
||||
msgid "Load Time"
|
||||
msgstr "載入時間"
|
||||
|
||||
#: templates/dashboard/pages/service.html:86
|
||||
msgid "Hits/Session"
|
||||
msgstr "每次工作階段點選次數"
|
||||
|
||||
#: templates/dashboard/pages/service.html:109
|
||||
#: templates/dashboard/pages/service_session.html:51
|
||||
msgid "Location"
|
||||
msgstr "位置"
|
||||
|
||||
#: templates/dashboard/pages/service.html:133
|
||||
msgid "No data yet..."
|
||||
msgstr "尚無資料..."
|
||||
|
||||
#: templates/dashboard/pages/service.html:141
|
||||
msgid "Sessions by Geography"
|
||||
msgstr "工作階段依地理位置"
|
||||
|
||||
#: templates/dashboard/pages/service.html:143
|
||||
msgid "view table"
|
||||
msgstr "檢視表格"
|
||||
|
||||
#: templates/dashboard/pages/service.html:153
|
||||
#: templates/dashboard/pages/service_session.html:47
|
||||
msgid "Country"
|
||||
msgstr "國家"
|
||||
|
||||
#: templates/dashboard/pages/service.html:191
|
||||
msgid "Referrer"
|
||||
msgstr "參照來源"
|
||||
|
||||
#: templates/dashboard/pages/service.html:225
|
||||
msgid "Operating System"
|
||||
msgstr "作業系統"
|
||||
|
||||
#: templates/dashboard/pages/service.html:259
|
||||
#: templates/dashboard/pages/service_session.html:27
|
||||
msgid "Browser"
|
||||
msgstr "瀏覽器"
|
||||
|
||||
#: templates/dashboard/pages/service.html:294
|
||||
#: templates/dashboard/pages/service_session.html:35
|
||||
msgid "Device Type"
|
||||
msgstr "裝置類型"
|
||||
|
||||
#: templates/dashboard/pages/service.html:329
|
||||
msgid "View more sessions"
|
||||
msgstr "檢視更多工作階段"
|
||||
|
||||
#: templates/dashboard/pages/service_create.html:5
|
||||
#: templates/dashboard/pages/service_create.html:8
|
||||
msgid "Create Service"
|
||||
msgstr "建立服務"
|
||||
|
||||
#: templates/dashboard/pages/service_create.html:16
|
||||
msgid "Create"
|
||||
msgstr "建立"
|
||||
|
||||
#: templates/dashboard/pages/service_create.html:17
|
||||
#: templates/dashboard/pages/service_update.html:30
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: templates/dashboard/pages/service_delete.html:5
|
||||
#: templates/dashboard/pages/service_update.html:33
|
||||
msgid "Delete"
|
||||
msgstr "刪除"
|
||||
|
||||
#: templates/dashboard/pages/service_delete.html:12
|
||||
msgid ""
|
||||
"Are you sure you want to delete this service? All of its analytics and "
|
||||
"associated data will be permanently deleted."
|
||||
msgstr ""
|
||||
"您確定要刪除此服務嗎?其所有分析和相關資料將被永久刪除。"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:31
|
||||
msgid "Device"
|
||||
msgstr "裝置"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:39
|
||||
msgid "OS"
|
||||
msgstr "作業系統"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:54
|
||||
msgid "Open in Maps"
|
||||
msgstr "在地圖中開啟"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:56
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:85
|
||||
msgid "Load"
|
||||
msgstr "載入"
|
||||
|
||||
#: templates/dashboard/pages/service_session.html:89
|
||||
msgid "Tracker"
|
||||
msgstr "追蹤器"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:5
|
||||
msgid "Management"
|
||||
msgstr "管理"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:8
|
||||
msgid "View"
|
||||
msgstr "檢視"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:13
|
||||
msgid "Installation"
|
||||
msgstr "安裝"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:15
|
||||
msgid ""
|
||||
"Place the following snippet at the end of the <code><body></code> tag "
|
||||
"on any page you'd like to track."
|
||||
msgstr ""
|
||||
"將以下片段放在您想要追蹤的任何頁面的 <code><body></code> 標籤的末端。"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:21
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
#: templates/dashboard/pages/service_update.html:29
|
||||
msgid "Save"
|
||||
msgstr "儲存"
|
||||
@@ -24,7 +24,8 @@
|
||||
<script>
|
||||
function getLocaleDateString(locale) {
|
||||
const formats = {
|
||||
'de': "DD. MMM YY"
|
||||
'de': "DD. MMM YY",
|
||||
'zh_TW': "YYYY 年 MM 月 DD 日"
|
||||
}
|
||||
return formats[locale] || "MMM DD 'YY";
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ def iconify(text):
|
||||
"firefox mobile": "firefox.com",
|
||||
"edge mobile": "microsoft.com",
|
||||
"chromium": "chromium.org",
|
||||
"duckduckgo mobile": "duckduckgo.com",
|
||||
}
|
||||
|
||||
domain = None
|
||||
|
||||
Reference in New Issue
Block a user