mirror of
https://git.fightbot.fun/hxuanyu/BingPaper.git
synced 2026-02-15 14:39:31 +08:00
项目名调整,功能优化
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -50,6 +50,6 @@ desktop.ini
|
|||||||
/data/
|
/data/
|
||||||
/picture/
|
/picture/
|
||||||
/config.yaml
|
/config.yaml
|
||||||
/bing_daily_image.db
|
/bing_paper.db
|
||||||
/req.txt
|
/req.txt
|
||||||
/BingDailyImage
|
/BingPaper
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ COPY go.mod go.sum ./
|
|||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go build -o BingDailyImage .
|
RUN go build -o BingPaper .
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /app/BingDailyImage .
|
COPY --from=builder /app/BingPaper .
|
||||||
RUN mkdir -p data
|
RUN mkdir -p data
|
||||||
COPY --from=builder /app/config.example.yaml ./data/config.yaml
|
COPY --from=builder /app/config.example.yaml ./data/config.yaml
|
||||||
COPY --from=builder /app/web ./web
|
COPY --from=builder /app/web ./web
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ENTRYPOINT ["./BingDailyImage"]
|
ENTRYPOINT ["./BingPaper"]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# BingDailyImage
|
# BingPaper
|
||||||
|
|
||||||
必应每日一图抓取、存储、多分辨率管理与公共 API 服务。
|
必应每日一图抓取、存储、多分辨率管理与公共 API 服务。
|
||||||
|
|
||||||
@@ -71,10 +71,10 @@ go run .
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 构建二进制
|
# 构建二进制
|
||||||
go build -o BingDailyImage .
|
go build -o BingPaper .
|
||||||
|
|
||||||
# 构建 Docker 镜像
|
# 构建 Docker 镜像
|
||||||
docker build -t bing-daily-image .
|
docker build -t bing-paper .
|
||||||
```
|
```
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|||||||
47
config.example.yaml
Normal file
47
config.example.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
base_url: ""
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
api:
|
||||||
|
mode: local # local | redirect
|
||||||
|
|
||||||
|
cron:
|
||||||
|
enabled: true
|
||||||
|
daily_spec: "0 10 * * *"
|
||||||
|
|
||||||
|
retention:
|
||||||
|
days: 30
|
||||||
|
|
||||||
|
db:
|
||||||
|
type: sqlite # sqlite | mysql | postgres
|
||||||
|
dsn: data/bing_paper.db
|
||||||
|
|
||||||
|
storage:
|
||||||
|
type: local # local | s3 | webdav
|
||||||
|
local:
|
||||||
|
root: data/picture
|
||||||
|
s3:
|
||||||
|
endpoint: ""
|
||||||
|
region: ""
|
||||||
|
bucket: ""
|
||||||
|
access_key: ""
|
||||||
|
secret_key: ""
|
||||||
|
public_url_prefix: ""
|
||||||
|
force_path_style: false
|
||||||
|
webdav:
|
||||||
|
url: ""
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
public_url_prefix: ""
|
||||||
|
|
||||||
|
admin:
|
||||||
|
password_bcrypt: "$2a$10$fYHPeWHmwObephJvtlyH1O8DIgaLk5TINbi9BOezo2M8cSjmJchka" # 默认密码: admin123
|
||||||
|
|
||||||
|
token:
|
||||||
|
default_ttl: 168h
|
||||||
|
|
||||||
|
feature:
|
||||||
|
write_daily_files: true
|
||||||
77
docs/docs.go
77
docs/docs.go
@@ -189,6 +189,66 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/admin/password": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "验证旧密码并设置新密码,自动更新配置文件",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "修改管理员密码",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "修改密码请求",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.ChangePasswordRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/admin/tokens": {
|
"/admin/tokens": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -747,6 +807,21 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.ChangePasswordRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"new_password",
|
||||||
|
"old_password"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"new_password": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"old_password": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.CreateTokenRequest": {
|
"handlers.CreateTokenRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -835,7 +910,7 @@ var SwaggerInfo = &swag.Spec{
|
|||||||
Host: "localhost:8080",
|
Host: "localhost:8080",
|
||||||
BasePath: "/api/v1",
|
BasePath: "/api/v1",
|
||||||
Schemes: []string{},
|
Schemes: []string{},
|
||||||
Title: "BingDailyImage API",
|
Title: "BingPaper API",
|
||||||
Description: "必应每日一图抓取、存储、管理与公共 API 服务。",
|
Description: "必应每日一图抓取、存储、管理与公共 API 服务。",
|
||||||
InfoInstanceName: "swagger",
|
InfoInstanceName: "swagger",
|
||||||
SwaggerTemplate: docTemplate,
|
SwaggerTemplate: docTemplate,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"description": "必应每日一图抓取、存储、管理与公共 API 服务。",
|
"description": "必应每日一图抓取、存储、管理与公共 API 服务。",
|
||||||
"title": "BingDailyImage API",
|
"title": "BingPaper API",
|
||||||
"contact": {},
|
"contact": {},
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
@@ -183,6 +183,66 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/admin/password": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "验证旧密码并设置新密码,自动更新配置文件",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"summary": "修改管理员密码",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "修改密码请求",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.ChangePasswordRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/admin/tokens": {
|
"/admin/tokens": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -741,6 +801,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.ChangePasswordRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"new_password",
|
||||||
|
"old_password"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"new_password": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"old_password": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.CreateTokenRequest": {
|
"handlers.CreateTokenRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -121,6 +121,16 @@ definitions:
|
|||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
handlers.ChangePasswordRequest:
|
||||||
|
properties:
|
||||||
|
new_password:
|
||||||
|
type: string
|
||||||
|
old_password:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- new_password
|
||||||
|
- old_password
|
||||||
|
type: object
|
||||||
handlers.CreateTokenRequest:
|
handlers.CreateTokenRequest:
|
||||||
properties:
|
properties:
|
||||||
expires_at:
|
expires_at:
|
||||||
@@ -172,7 +182,7 @@ host: localhost:8080
|
|||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
description: 必应每日一图抓取、存储、管理与公共 API 服务。
|
description: 必应每日一图抓取、存储、管理与公共 API 服务。
|
||||||
title: BingDailyImage API
|
title: BingPaper API
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
paths:
|
paths:
|
||||||
/admin/cleanup:
|
/admin/cleanup:
|
||||||
@@ -283,6 +293,44 @@ paths:
|
|||||||
summary: 管理员登录
|
summary: 管理员登录
|
||||||
tags:
|
tags:
|
||||||
- admin
|
- admin
|
||||||
|
/admin/password:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 验证旧密码并设置新密码,自动更新配置文件
|
||||||
|
parameters:
|
||||||
|
- description: 修改密码请求
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handlers.ChangePasswordRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: 修改管理员密码
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
/admin/tokens:
|
/admin/tokens:
|
||||||
get:
|
get:
|
||||||
description: 获取所有已创建的 API Token 列表
|
description: 获取所有已创建的 API Token 列表
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -1,4 +1,4 @@
|
|||||||
module BingDailyImage
|
module BingPaper
|
||||||
|
|
||||||
go 1.25.5
|
go 1.25.5
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ require (
|
|||||||
github.com/chai2010/webp v1.4.0 // indirect
|
github.com/chai2010/webp v1.4.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/disintegration/imaging v1.6.2 // indirect
|
github.com/disintegration/imaging v1.6.2 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
@@ -46,6 +47,7 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
github.com/quic-go/quic-go v0.54.0 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
@@ -57,6 +59,7 @@ require (
|
|||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/spf13/viper v1.21.0 // indirect
|
github.com/spf13/viper v1.21.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
github.com/studio-b12/gowebdav v0.12.0 // indirect
|
github.com/studio-b12/gowebdav v0.12.0 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/swaggo/files v1.0.1 // indirect
|
github.com/swaggo/files v1.0.1 // indirect
|
||||||
@@ -80,6 +83,7 @@ require (
|
|||||||
golang.org/x/tools v0.40.0 // indirect
|
golang.org/x/tools v0.40.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/protobuf v1.36.9 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gorm.io/driver/mysql v1.6.0 // indirect
|
gorm.io/driver/mysql v1.6.0 // indirect
|
||||||
gorm.io/driver/postgres v1.6.0 // indirect
|
gorm.io/driver/postgres v1.6.0 // indirect
|
||||||
gorm.io/driver/sqlite v1.6.0 // indirect
|
gorm.io/driver/sqlite v1.6.0 // indirect
|
||||||
|
|||||||
5
go.sum
5
go.sum
@@ -21,6 +21,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSY
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
@@ -101,6 +102,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
|||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
@@ -133,6 +135,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/studio-b12/gowebdav v0.12.0 h1:kFRtQECt8jmVAvA6RHBz3geXUGJHUZA6/IKpOVUs5kM=
|
github.com/studio-b12/gowebdav v0.12.0 h1:kFRtQECt8jmVAvA6RHBz3geXUGJHUZA6/IKpOVUs5kM=
|
||||||
github.com/studio-b12/gowebdav v0.12.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
github.com/studio-b12/gowebdav v0.12.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
@@ -220,6 +224,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
||||||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/cron"
|
"BingPaper/internal/cron"
|
||||||
"BingDailyImage/internal/http"
|
"BingPaper/internal/http"
|
||||||
"BingDailyImage/internal/repo"
|
"BingPaper/internal/repo"
|
||||||
"BingDailyImage/internal/service/fetcher"
|
"BingPaper/internal/service/fetcher"
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
"BingDailyImage/internal/storage/local"
|
"BingPaper/internal/storage/local"
|
||||||
"BingDailyImage/internal/storage/s3"
|
"BingPaper/internal/storage/s3"
|
||||||
"BingDailyImage/internal/storage/webdav"
|
"BingPaper/internal/storage/webdav"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -93,7 +93,7 @@ func LogWelcomeInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("\n---------------------------------------------------------")
|
fmt.Println("\n---------------------------------------------------------")
|
||||||
fmt.Println(" BingDailyImage 服务已启动!")
|
fmt.Println(" BingPaper 服务已启动!")
|
||||||
fmt.Printf(" - 首页地址: %s/\n", baseURL)
|
fmt.Printf(" - 首页地址: %s/\n", baseURL)
|
||||||
fmt.Printf(" - 管理后台: %s/admin\n", baseURL)
|
fmt.Printf(" - 管理后台: %s/admin\n", baseURL)
|
||||||
fmt.Printf(" - API 文档: %s/swagger/index.html\n", baseURL)
|
fmt.Printf(" - API 文档: %s/swagger/index.html\n", baseURL)
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func Init(configPath string) error {
|
|||||||
v.SetDefault("cron.daily_spec", "0 10 * * *")
|
v.SetDefault("cron.daily_spec", "0 10 * * *")
|
||||||
v.SetDefault("retention.days", 30)
|
v.SetDefault("retention.days", 30)
|
||||||
v.SetDefault("db.type", "sqlite")
|
v.SetDefault("db.type", "sqlite")
|
||||||
v.SetDefault("db.dsn", "data/bing_daily_image.db")
|
v.SetDefault("db.dsn", "data/bing_paper.db")
|
||||||
v.SetDefault("storage.type", "local")
|
v.SetDefault("storage.type", "local")
|
||||||
v.SetDefault("storage.local.root", "data/picture")
|
v.SetDefault("storage.local.root", "data/picture")
|
||||||
v.SetDefault("token.default_ttl", "168h")
|
v.SetDefault("token.default_ttl", "168h")
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package cron
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/service/fetcher"
|
"BingPaper/internal/service/fetcher"
|
||||||
"BingDailyImage/internal/service/image"
|
"BingPaper/internal/service/image"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/service/fetcher"
|
"BingPaper/internal/service/fetcher"
|
||||||
"BingDailyImage/internal/service/image"
|
"BingPaper/internal/service/image"
|
||||||
"BingDailyImage/internal/service/token"
|
"BingPaper/internal/service/token"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginRequest struct {
|
type LoginRequest struct {
|
||||||
@@ -109,6 +110,55 @@ type UpdateTokenRequest struct {
|
|||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChangePasswordRequest struct {
|
||||||
|
OldPassword string `json:"old_password" binding:"required"`
|
||||||
|
NewPassword string `json:"new_password" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePassword 修改管理员密码
|
||||||
|
// @Summary 修改管理员密码
|
||||||
|
// @Description 验证旧密码并设置新密码,自动更新配置文件
|
||||||
|
// @Tags admin
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body ChangePasswordRequest true "修改密码请求"
|
||||||
|
// @Success 200 {object} map[string]string
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 401 {object} map[string]string
|
||||||
|
// @Router /admin/password [post]
|
||||||
|
func ChangePassword(c *gin.Context) {
|
||||||
|
var req ChangePasswordRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.GetConfig()
|
||||||
|
// 验证旧密码
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(cfg.Admin.PasswordBcrypt), []byte(req.OldPassword))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid old password"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成新密码 Hash
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to hash password"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新配置
|
||||||
|
cfg.Admin.PasswordBcrypt = string(hash)
|
||||||
|
if err := config.SaveConfig(cfg); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save config"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "ok", "message": "password updated successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateToken 更新 Token 状态
|
// UpdateToken 更新 Token 状态
|
||||||
// @Summary 更新 Token 状态
|
// @Summary 更新 Token 状态
|
||||||
// @Description 启用或禁用指定的 API Token
|
// @Description 启用或禁用指定的 API Token
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/model"
|
"BingPaper/internal/model"
|
||||||
"BingDailyImage/internal/service/image"
|
"BingPaper/internal/service/image"
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"BingDailyImage/internal/service/token"
|
"BingPaper/internal/service/token"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "BingDailyImage/docs"
|
_ "BingPaper/docs"
|
||||||
"BingDailyImage/internal/http/handlers"
|
"BingPaper/internal/http/handlers"
|
||||||
"BingDailyImage/internal/http/middleware"
|
"BingPaper/internal/http/middleware"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
@@ -50,6 +50,8 @@ func SetupRouter() *gin.Engine {
|
|||||||
authorized.PATCH("/tokens/:id", handlers.UpdateToken)
|
authorized.PATCH("/tokens/:id", handlers.UpdateToken)
|
||||||
authorized.DELETE("/tokens/:id", handlers.DeleteToken)
|
authorized.DELETE("/tokens/:id", handlers.DeleteToken)
|
||||||
|
|
||||||
|
authorized.POST("/password", handlers.ChangePassword)
|
||||||
|
|
||||||
authorized.GET("/config", handlers.GetConfig)
|
authorized.GET("/config", handlers.GetConfig)
|
||||||
authorized.PUT("/config", handlers.UpdateConfig)
|
authorized.PUT("/config", handlers.UpdateConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/model"
|
"BingPaper/internal/model"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/model"
|
"BingPaper/internal/model"
|
||||||
"BingDailyImage/internal/repo"
|
"BingPaper/internal/repo"
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
|
|
||||||
"github.com/chai2010/webp"
|
"github.com/chai2010/webp"
|
||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/model"
|
"BingPaper/internal/model"
|
||||||
"BingDailyImage/internal/repo"
|
"BingPaper/internal/repo"
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/model"
|
"BingPaper/internal/model"
|
||||||
"BingDailyImage/internal/repo"
|
"BingPaper/internal/repo"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@@ -51,7 +51,21 @@ func Login(password string) (*model.Token, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ttl := config.GetTokenTTL()
|
ttl := config.GetTokenTTL()
|
||||||
return CreateToken("login-token", time.Now().Add(ttl))
|
expiresAt := time.Now().Add(ttl)
|
||||||
|
name := "login-token"
|
||||||
|
|
||||||
|
// 如果已存在同名 token,则刷新时间并返回
|
||||||
|
var t model.Token
|
||||||
|
if err := repo.DB.Where("name = ?", name).First(&t).Error; err == nil {
|
||||||
|
t.ExpiresAt = expiresAt
|
||||||
|
t.Disabled = false
|
||||||
|
if err := repo.DB.Save(&t).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateToken(name, expiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListTokens() ([]model.Token, error) {
|
func ListTokens() ([]model.Token, error) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LocalStorage struct {
|
type LocalStorage struct {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"BingDailyImage/internal/storage"
|
"BingPaper/internal/storage"
|
||||||
|
|
||||||
"github.com/studio-b12/gowebdav"
|
"github.com/studio-b12/gowebdav"
|
||||||
)
|
)
|
||||||
|
|||||||
8
main.go
8
main.go
@@ -3,14 +3,14 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"BingDailyImage/internal/bootstrap"
|
"BingPaper/internal/bootstrap"
|
||||||
"BingDailyImage/internal/config"
|
"BingPaper/internal/config"
|
||||||
"BingDailyImage/internal/util"
|
"BingPaper/internal/util"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title BingDailyImage API
|
// @title BingPaper API
|
||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @description 必应每日一图抓取、存储、管理与公共 API 服务。
|
// @description 必应每日一图抓取、存储、管理与公共 API 服务。
|
||||||
// @host localhost:8080
|
// @host localhost:8080
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>BingDailyImage - 必应每日一图</title>
|
<title>BingPaper - 必应每日一图</title>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #007bff;
|
--primary-color: #007bff;
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/" class="logo">BingDailyImage</a>
|
<a href="/" class="logo">BingPaper</a>
|
||||||
<div>
|
<div>
|
||||||
<a href="/">首页</a>
|
<a href="/">首页</a>
|
||||||
<a href="/admin">管理</a>
|
<a href="/admin">管理</a>
|
||||||
@@ -139,6 +139,13 @@
|
|||||||
<button class="secondary" onclick="triggerCleanup()" style="margin-bottom: 10px;">手动清理旧图</button>
|
<button class="secondary" onclick="triggerCleanup()" style="margin-bottom: 10px;">手动清理旧图</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="admin-card">
|
||||||
|
<h3>修改密码</h3>
|
||||||
|
<input type="password" id="old-password" placeholder="旧密码" style="margin-bottom: 10px;">
|
||||||
|
<input type="password" id="new-password" placeholder="新密码" style="margin-bottom: 10px;">
|
||||||
|
<button onclick="changePassword()">提交修改</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<h3>今日图预览</h3>
|
<h3>今日图预览</h3>
|
||||||
<div id="today-preview" style="text-align: center;">
|
<div id="today-preview" style="text-align: center;">
|
||||||
@@ -354,6 +361,26 @@
|
|||||||
alert('清理任务已启动');
|
alert('清理任务已启动');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function changePassword() {
|
||||||
|
const oldPassword = document.getElementById('old-password').value;
|
||||||
|
const newPassword = document.getElementById('new-password').value;
|
||||||
|
if (!oldPassword || !newPassword) return alert('请输入完整信息');
|
||||||
|
|
||||||
|
const resp = await fetch('/api/v1/admin/password', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ old_password: oldPassword, new_password: newPassword })
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await resp.json();
|
||||||
|
if (resp.ok) {
|
||||||
|
alert('密码修改成功,请重新登录');
|
||||||
|
logout();
|
||||||
|
} else {
|
||||||
|
alert('修改失败: ' + (data.error || '未知错误'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
router();
|
router();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user