diff --git a/.dockerignore b/.dockerignore
index 9fa61698..96152818 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,6 +2,8 @@ node_modules/
.next/
uploads/
.git/
+!.git/refs
+!.git/HEAD
.yarn/*
!.yarn/releases
!.yarn/plugins
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index c74680f4..8b807db8 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -13,7 +13,7 @@ on:
jobs:
push:
- name: Push Image
+ name: Push Commit Image
runs-on: ubuntu-latest
steps:
- name: Check out the repo
@@ -22,7 +22,7 @@ jobs:
- name: Get version
id: version
run: |
- echo "zipline_version=$(jq .version package.json -r)" >> $GITHUB_OUTPUT
+ echo "zipline_commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
@@ -51,8 +51,8 @@ jobs:
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/diced/zipline:v3-trunk
- ghcr.io/diced/zipline:v3-trunk-${{ steps.version.outputs.zipline_version }}
+ ghcr.io/diced/zipline:v3-trunk-${{ steps.version.outputs.zipline_commit }}
${{ secrets.DOCKERHUB_USERNAME }}/zipline:v3-trunk
- ${{ secrets.DOCKERHUB_USERNAME }}/zipline:v3-trunk-${{ steps.version.outputs.zipline_version }}
+ ${{ secrets.DOCKERHUB_USERNAME }}/zipline:v3-trunk-${{ steps.version.outputs.zipline_commit }}
cache-from: type=gha
cache-to: type=gha,mode=max
diff --git a/Dockerfile b/Dockerfile
index 9bb49b58..1ada53bf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -53,6 +53,9 @@ ENV PRISMA_QUERY_ENGINE_BINARY=/prisma-engines/query-engine \
ZIPLINE_DOCKER_BUILD=true \
NEXT_TELEMETRY_DISABLED=1
+COPY .git/refs ./.git/refs
+COPY .git/HEAD ./.git/HEAD
+
# Copy only the necessary files from the previous stage
COPY --from=builder /zipline/dist ./dist
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
index dc841847..3988d2a9 100644
--- a/src/components/Layout.tsx
+++ b/src/components/Layout.tsx
@@ -316,7 +316,9 @@ export default function Layout({ children, props }) {
variant='dot'
color={version.data.update ? 'red' : 'primary'}
>
- {version.data.versions.current}
+ {version.data.isUpstream
+ ? version.data.versions.current.slice(0, 7)
+ : version.data.versions.current}
diff --git a/src/components/pages/Manage/ClearStorage.tsx b/src/components/pages/Manage/ClearStorage.tsx
index 05a21329..d3afc5fd 100644
--- a/src/components/pages/Manage/ClearStorage.tsx
+++ b/src/components/pages/Manage/ClearStorage.tsx
@@ -7,7 +7,7 @@ import { useState } from 'react';
export default function ClearStorage({ open, setOpen }) {
const [check, setCheck] = useState(false);
- const handleDelete = async (datasource: boolean, orphaned?: boolean) => {
+ const handleDelete = async (orphaned?: boolean) => {
showNotification({
id: 'clear-uploads',
title: 'Clearing...',
@@ -16,7 +16,7 @@ export default function ClearStorage({ open, setOpen }) {
autoClose: false,
});
- const res = await useFetch('/api/admin/clear', 'POST', { datasource, orphaned });
+ const res = await useFetch('/api/admin/clear', 'POST', { orphaned });
if (res.error) {
updateNotification({
@@ -65,21 +65,13 @@ export default function ClearStorage({ open, setOpen }) {
onClick={() => {
setOpen(false);
openConfirmModal({
- title: 'Do you want to clear storage too?',
- labels: { confirm: 'Yes', cancel: check ? 'Ok' : 'No' },
- children: check && (
-
- Due to clearing orphaned files, storage clearing will be unavailable.
-
- ),
- confirmProps: { disabled: check },
+ title: 'Are you sure?',
+ confirmProps: { color: 'red' },
+ children: This action is destructive and irreversible.,
+ labels: { confirm: 'Yes', cancel: 'No' },
onConfirm: () => {
closeAllModals();
- handleDelete(true);
- },
- onCancel: () => {
- closeAllModals();
- handleDelete(false, check);
+ handleDelete(check);
},
onClose: () => setCheck(false),
});
diff --git a/src/pages/api/admin/clear.ts b/src/pages/api/admin/clear.ts
index cfd82314..e1439893 100644
--- a/src/pages/api/admin/clear.ts
+++ b/src/pages/api/admin/clear.ts
@@ -8,21 +8,23 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
try {
const { orphaned } = req.body;
if (orphaned) {
+ const files = await prisma.file.findMany({
+ where: {
+ userId: null,
+ },
+ });
const { count } = await prisma.file.deleteMany({
where: {
userId: null,
},
});
+ for (const file of files) await datasource.delete(file.name);
logger.info(`User ${user.username} (${user.id}) cleared the database of ${count} orphaned files`);
return res.json({ message: 'cleared storage (orphaned only)' });
}
const { count } = await prisma.file.deleteMany({});
+ await datasource.clear();
logger.info(`User ${user.username} (${user.id}) cleared the database of ${count} files`);
-
- if (req.body.datasource) {
- await datasource.clear();
- logger.info(`User ${user.username} (${user.id}) cleared storage`);
- }
} catch (e) {
logger.error(`User ${user.username} (${user.id}) failed to clear the database or storage`);
logger.error(e);
diff --git a/src/pages/api/admin/export.ts b/src/pages/api/admin/export.ts
index 6cb3c7a7..1f533804 100644
--- a/src/pages/api/admin/export.ts
+++ b/src/pages/api/admin/export.ts
@@ -283,14 +283,6 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) {
};
}
- const stats = await prisma.stats.findMany();
- for (const stat of stats) {
- exportData.stats.push({
- created_at: stat.createdAt.toISOString(),
- data: stat.data,
- });
- }
-
exportData.request.user = exportData.user_map[user.id];
for (const folder of folders) {
diff --git a/src/pages/api/users.ts b/src/pages/api/users.ts
index 7478058a..da87727a 100644
--- a/src/pages/api/users.ts
+++ b/src/pages/api/users.ts
@@ -3,7 +3,10 @@ import { NextApiReq, NextApiRes, withZipline } from 'middleware/withZipline';
async function handler(_: NextApiReq, res: NextApiRes) {
const users = await prisma.user.findMany();
- for (let i = 0; i !== users.length; ++i) delete users[i].password;
+ for (let i = 0; i !== users.length; ++i) {
+ delete users[i].password;
+ delete users[i].uuid;
+ }
return res.json(users);
}
diff --git a/src/pages/api/version.ts b/src/pages/api/version.ts
index deea84ea..bebd6b73 100644
--- a/src/pages/api/version.ts
+++ b/src/pages/api/version.ts
@@ -5,24 +5,29 @@ import { NextApiReq, NextApiRes, withZipline } from 'middleware/withZipline';
async function handler(_: NextApiReq, res: NextApiRes) {
if (!config.website.show_version) return res.forbidden('version hidden');
- const pkg = JSON.parse(await readFile('package.json', 'utf8'));
+ const pRev = await (async function () {
+ try {
+ return await readFile('.git/HEAD', 'utf8');
+ } catch (e) {
+ return JSON.parse(await readFile('package.json', 'utf8')).version;
+ }
+ })();
+ const { groups } = new RegExp(/^ref: (?[(\w+\/?)*)/).exec(pRev) || { groups: null };
+ let rev: string;
- const re = await fetch('https://zipline.diced.sh/api/version?c=' + pkg.version);
+ if (!groups) rev = pRev;
+ else rev = await readFile(`.git/${groups.ref}`, 'utf8');
+
+ const re = await fetch(`https://v3.zipline.diced.sh/api/version?c=?c=${rev}`);
const json = await re.json();
+ if (!re.ok) return res.badRequest(json.error);
let updateToType = 'stable';
-
- if (json.isUpstream) {
- updateToType = 'upstream';
-
- if (json.update?.stable) {
- updateToType = 'stable';
- }
- }
+ if (json.isUpstream) updateToType = 'upstream';
return res.json({
- isUpstream: true,
- update: json.update?.stable || json.update?.upstream,
+ isUpstream: json.isUpstream,
+ update: json.isUpstream ? json.update?.upstream : json.update?.stable,
updateToType,
versions: {
stable: json.git.stable,
]