diff --git a/.gitignore b/.gitignore index 28b53d6..258f0e4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ *.db *.bin /release/ -application/statics/assets.zip master_v4 slave_v4 __debug* @@ -39,4 +38,7 @@ tmp/ cloudreve .DS_Store assets/ +frontend-temp/ +_zipstage/ +*.mjs.tmp diff --git a/Dockerfile.ci b/Dockerfile.ci index 1a9cddb..4c1c681 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,38 +1,9 @@ # syntax=docker/dockerfile:1.6 -ARG FRONTEND_MIRROR=https://gitclone.com/github.com/cloudreve/frontend.git ARG GO_PROXY=https://goproxy.cn,direct -ARG NPM_REGISTRY=https://registry.npmmirror.com # ======================================== -# Stage 1: Frontend build -# ======================================== -FROM node:20-alpine AS frontend-build -ARG FRONTEND_MIRROR -ARG NPM_REGISTRY - -WORKDIR /build -RUN apk add --no-cache git zip tzdata - -RUN --mount=type=cache,target=/tmp/git-cache \ - git clone --depth 1 ${FRONTEND_MIRROR} assets - -WORKDIR /build/assets -RUN npm config set registry ${NPM_REGISTRY} && \ - yarn config set registry ${NPM_REGISTRY} - -RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \ - --mount=type=cache,target=/build/assets/node_modules \ - yarn install --network-timeout 1000000 --frozen-lockfile || yarn install --network-timeout 1000000 - -RUN export NODE_OPTIONS="--max-old-space-size=8192" && yarn run build - -WORKDIR /build -RUN mkdir -p application/statics && \ - cd assets/build && zip -r - . > /build/application/statics/assets.zip - -# ======================================== -# Stage 2: Backend build +# Stage 1: Backend build (frontend pre-built locally -> application/statics/assets.zip) # ======================================== FROM golang:1.23-alpine AS backend-build ARG GO_PROXY @@ -50,7 +21,6 @@ RUN --mount=type=cache,target=/go/pkg/mod \ go mod download COPY . . -COPY --from=frontend-build /build/application/statics/assets.zip ./application/statics/assets.zip RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ @@ -61,7 +31,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ go build -trimpath -ldflags "-s -w -X 'github.com/cloudreve/Cloudreve/v4/pkg/conf.BackendVersion=byw-${BUILD_DATE:-dev}'" -o /cloudreve . # ======================================== -# Stage 3: Runtime image +# Stage 2: Runtime image # ======================================== FROM alpine:latest AS runtime diff --git a/application/statics/assets.zip b/application/statics/assets.zip new file mode 100644 index 0000000..ff2f64d Binary files /dev/null and b/application/statics/assets.zip differ diff --git a/inventory/loginaudit.go b/inventory/loginaudit.go index 8c29ba3..07bad35 100644 --- a/inventory/loginaudit.go +++ b/inventory/loginaudit.go @@ -167,6 +167,7 @@ func (c *loginAuditClient) List(ctx context.Context, args *LoginAuditListArgs) ( items, err := q. Order(ent.Desc(loginaudit.FieldCreatedAt)). + WithUser(). Limit(pageSize). Offset((page - 1) * pageSize). All(ctx) diff --git a/scripts/gitea_actions.mjs b/scripts/gitea_actions.mjs new file mode 100644 index 0000000..90a9fc1 --- /dev/null +++ b/scripts/gitea_actions.mjs @@ -0,0 +1,87 @@ +import https from "node:https"; +import process from "node:process"; + +const token = process.env.GITEA_TOKEN; +const owner = "Henry_Du"; +const repo = "BYWCloudreve"; +const apiBase = "https://gitea.fse-media.group/api/v1"; + +const agent = new https.Agent({ rejectUnauthorized: false }); + +function request(method, path, body) { + return new Promise((resolve, reject) => { + const url = new URL(apiBase + path); + const data = body ? JSON.stringify(body) : null; + const req = https.request( + { + method, + hostname: url.hostname, + port: url.port || 443, + path: url.pathname + url.search, + headers: { + Authorization: `token ${token}`, + Accept: "application/json", + "Content-Type": "application/json", + ...(data ? { "Content-Length": Buffer.byteLength(data) } : {}), + }, + agent, + }, + (res) => { + let chunks = ""; + res.setEncoding("utf8"); + res.on("data", (c) => (chunks += c)); + res.on("end", () => { + const ok = res.statusCode >= 200 && res.statusCode < 300; + let parsed = chunks; + try { + parsed = JSON.parse(chunks); + } catch { + /* noop */ + } + if (ok) resolve(parsed); + else reject(new Error(`HTTP ${res.statusCode}: ${typeof parsed === "string" ? parsed : JSON.stringify(parsed)}`)); + }); + } + ); + req.on("error", reject); + if (data) req.write(data); + req.end(); + }); +} + +async function main() { + if (!token) { + console.error("GITEA_TOKEN is missing"); + process.exit(2); + } + const action = process.argv[2] || "status"; + if (action === "status") { + const runs = await request("GET", `/repos/${owner}/${repo}/actions/runs?limit=5`); + console.log(JSON.stringify(runs, null, 2)); + return; + } + if (action === "dispatch") { + const workflows = await request("GET", `/repos/${owner}/${repo}/actions/workflows`); + const wf = (workflows.workflows || []).find((w) => /build-deploy/.test(w.path) || /build/.test(w.name.toLowerCase())); + if (!wf) { + console.error("No workflow found, workflows available:", workflows.workflows?.map((w) => w.path)); + process.exit(3); + } + console.log("Dispatching workflow:", wf.path, "id:", wf.id); + await request("POST", `/repos/${owner}/${repo}/actions/workflows/${wf.id}/dispatches`, { + ref: "main", + inputs: { logLevel: "info" }, + }); + console.log("Dispatched OK"); + const runs = await request("GET", `/repos/${owner}/${repo}/actions/runs?limit=3`); + console.log(JSON.stringify(runs, null, 2)); + return; + } + console.error("Unknown action:", action); + process.exit(1); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +});