From 5f8c7be5acaac67da0867f79dd775d0e25b0ac28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E9=97=BB=E9=A3=8E?= Date: Tue, 23 Jun 2026 10:45:37 +0800 Subject: [PATCH] up --- README.md | 227 +++++++++++++++++++++++++++++++++-------------- install_linux.sh | 88 ++++++++++++++++++ 2 files changed, 250 insertions(+), 65 deletions(-) create mode 100755 install_linux.sh diff --git a/README.md b/README.md index e13fad7..bbf4158 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,50 @@ # Go Blog -A simple, fast blog engine built with Go, Gin, and Tailwind CSS. Supports SQLite and MySQL, with automatic first-run setup. +一个简洁、快速的博客引擎,使用 Go + Gin + Tailwind CSS 构建。支持 SQLite 和 MySQL,首次运行自动完成配置。 -## Features +## 功能特性 -- **Multi-language** — 中文 / English, auto-detected or manually switched -- **OS-aware config** — Linux `/etc/blog_go/`, Windows `./win/etc/blog_go/` -- **First-run setup** — auto-creates config, database, and admin user -- **Avatar + Profile** — upload avatar, edit personal info, change password -- **Role system** — admin sees management panel; authors see profile only -- **Responsive UI** — Tailwind CSS, works on desktop and mobile +- **文章管理** — 文章的创建、编辑、删除,支持标签分类、自定义发布时间和更新时间 +- **评论系统** — 文章评论功能,后台可审核(通过/拒绝/删除),支持评论设置 +- **用户系统** — 用户注册、登录,角色分为管理员(admin)和作者(author) +- **角色权限** — 管理员可访问后台管理面板;作者可管理自己的文章 +- **个人中心** — 上传头像(支持裁剪)、编辑个人信息、修改密码 +- **站点设置** — 自定义站点标题、副标题、favicon 图标 +- **导航管理** — 自定义首页导航链接,支持图标 +- **瀑布流布局** — 首页文章以瀑布流展示,支持无限滚动加载 +- **阅读统计** — 文章阅读量统计,带机器人流量检测 +- **附件上传** — 文章支持上传附件,基于内容寻址自动去重 +- **RSS 订阅** — 自动生成 RSS Feed(`/rss`、`/feed`) +- **搜索功能** — 文章全文搜索 +- **多语言** — 支持中文 / English,自动检测浏览器语言或手动切换 +- **自适应界面** — Tailwind CSS,桌面端和移动端均可正常使用 +- **开箱即用** — 首次运行自动创建配置文件、数据库和管理员账号 -## Tech Stack +## 技术栈 -| Layer | Library | +| 层级 | 库/工具 | |---|---| -| Router | [gin](https://github.com/gin-gonic/gin) | +| 路由 | [gin](https://github.com/gin-gonic/gin) | | ORM | [gorm](https://gorm.io) | -| SQLite | [glebarez/sqlite](https://github.com/glebarez/sqlite) (pure Go, no CGO) | -| Sessions | [gin-contrib/sessions](https://github.com/gin-contrib/sessions) | -| Config | [gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) | -| Passwords | [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto/bcrypt) | -| CSS | [Tailwind CSS](https://tailwindcss.com) (CDN) | +| SQLite | [glebarez/sqlite](https://github.com/glebarez/sqlite)(纯 Go,无需 CGO) | +| Session | [gin-contrib/sessions](https://github.com/gin-contrib/sessions) | +| 配置 | [gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) | +| 密码 | [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto/bcrypt) | +| CSS | [Tailwind CSS](https://tailwindcss.com)(CDN) | -## Quick Start +## 快速开始 ```bash go run . ``` -Open http://localhost:8080 and log in with **admin** / **admin**. +打开 ,使用 **admin** / **admin** 登录。 -## Configuration +## 配置 -On first run, a config file is created automatically: +首次运行时,配置文件会自动生成: -| Platform | Config Path | Storage Path | +| 平台 | 配置文件路径 | 数据存储路径 | |---|---|---| | Linux | `/etc/blog_go/config.yaml` | `/srv/blog_go/` | | Windows | `./win/etc/blog_go/config.yaml` | `./win/srv/blog_go/` | @@ -43,16 +52,16 @@ On first run, a config file is created automatically: ```yaml # config.yaml database: - type: sqlite # sqlite (default) or mysql - dsn: "" # MySQL DSN, ignored for sqlite -port: "8080" # web server port -path: ./win/srv/blog_go # storage path (db, uploads) -secret: # session encryption key + type: sqlite # sqlite(默认)或 mysql + dsn: "" # MySQL 连接串,sqlite 模式下忽略 +port: "8080" # Web 服务端口 +path: ./win/srv/blog_go # 数据存储路径(数据库、上传文件) +secret: <自动生成> # Session 加密密钥 ``` -### MySQL +### 使用 MySQL -Edit `config.yaml`: +编辑 `config.yaml`: ```yaml database: @@ -61,41 +70,82 @@ database: port: "8080" ``` -Create the database first: +先创建数据库: ```sql CREATE DATABASE blog_go CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` -## Project Structure +## 项目结构 ``` go_blog/ -├── main.go # Entry point, routes, middleware wiring +├── main.go # 入口,路由注册,中间件装配 ├── config/ -│ └── config.go # OS-aware config load / auto-create +│ └── config.go # 配置加载 / 自动创建(区分操作系统) ├── models/ -│ ├── user.go # User model + bcrypt -│ └── db.go # GORM init, migration, seed +│ ├── user.go # 用户模型 + bcrypt +│ ├── article.go # 文章模型 +│ ├── article_tag.go # 文章-标签关联 +│ ├── article_view.go # 文章阅读统计 +│ ├── attachment.go # 附件模型 +│ ├── bot_detector.go # 机器人流量检测 +│ ├── comment.go # 评论模型 +│ ├── comment_config.go # 评论配置 +│ ├── config_cache.go # 平台配置缓存 +│ ├── db.go # GORM 初始化、自动迁移 +│ ├── nav_link.go # 导航链接模型 +│ ├── seed.go # 初始数据填充 +│ ├── site_setting.go # 站点设置模型 +│ ├── tag.go # 标签模型 +│ └── upload_config.go # 上传配置 ├── middleware/ -│ └── auth.go # Auth guard, language detection +│ └── auth.go # 登录验证、角色鉴权、语言检测 ├── handlers/ -│ ├── helpers.go # DefaultData + getTr utilities -│ ├── home.go # GET / -│ ├── auth.go # GET/POST /login, POST /logout -│ ├── admin.go # GET /admin (protected) -│ └── profile.go # GET/POST /profile (protected) +│ ├── helpers.go # 公共工具函数 +│ ├── home.go # 首页 +│ ├── article.go # 文章详情、文章列表 API +│ ├── auth.go # 登录 +│ ├── admin.go # 管理后台首页 +│ ├── admin_comment.go # 评论管理 +│ ├── admin_user.go # 用户管理 +│ ├── admin_analytics.go # 阅读统计 +│ ├── attachment.go # 附件上传/删除 +│ ├── comment.go # 评论提交 +│ ├── my_articles.go # 用户文章管理 +│ ├── profile.go # 个人中心 +│ ├── rss.go # RSS Feed +│ ├── settings.go # 站点/导航/上传/评论设置 +│ └── upload_validator.go # 上传文件校验 ├── i18n/ -│ └── i18n.go # EN/ZH translation maps + Accept-Language +│ └── i18n.go # 中英文翻译映射 + Accept-Language 检测 ├── templates/ -│ ├── layouts/base.html # Header (nav + avatar dropdown) + footer +│ ├── layouts/base.html # 公共布局(导航栏 + 头像下拉菜单 + 页脚) │ ├── pages/ -│ │ ├── home.html # Public home page -│ │ ├── login.html # Login form -│ │ └── profile.html # Edit profile page -│ └── admin/ -│ └── dashboard.html # Admin dashboard -└── win/ # Auto-created runtime data (Windows) +│ │ ├── home.html # 首页(瀑布流 + 无限滚动) +│ │ ├── article.html # 文章详情页 +│ │ ├── login.html # 登录页 +│ │ ├── register.html # 注册页 +│ │ ├── profile.html # 个人中心 +│ │ ├── search.html # 搜索页 +│ │ └── 404.html # 404 页面 +│ ├── admin/ +│ │ ├── dashboard.html # 管理后台首页 +│ │ ├── article_list.html # 文章列表 +│ │ ├── article_create.html# 文章编辑 +│ │ ├── comment_list.html # 评论审核 +│ │ ├── user_list.html # 用户列表 +│ │ ├── user_form.html # 用户表单 +│ │ ├── analytics_views.html # 阅读统计 +│ │ ├── settings_site.html # 站点设置 +│ │ ├── settings_navlinks.html # 导航链接设置 +│ │ ├── settings_upload.html # 上传设置 +│ │ ├── settings_download.html # 下载设置 +│ │ └── settings_comment.html # 评论设置 +│ └── user/ +│ ├── my_articles.html # 我的文章列表 +│ └── my_article_form.html # 我的文章编辑 +└── win/ # 运行时数据目录(Windows,自动创建) ├── etc/blog_go/ │ └── config.yaml └── srv/blog_go/ @@ -103,26 +153,73 @@ go_blog/ └── avatars/ ``` -## Routes +## 路由 -| Method | Path | Auth | Description | -|---|---|---|---| -| GET | `/` | No | Home page | -| GET | `/login` | No | Login form | -| POST | `/login` | No | Submit login | -| POST | `/logout` | No | Clear session | -| GET | `/profile` | Yes | Edit profile | -| POST | `/profile` | Yes | Save profile | -| GET | `/admin` | Yes | Admin dashboard (admin only) | -| GET | `/uploads/*` | No | Static files (avatars, etc.) | +### 公开路由 -## User Roles - -| Role | Profile | Admin Dashboard | +| 方法 | 路径 | 说明 | |---|---|---| -| `admin` | ✓ | ✓ | -| `author` | ✓ | ✗ | +| GET | `/` | 首页 | +| GET | `/search` | 搜索页 | +| GET | `/api/articles` | 文章列表 API(无限滚动) | +| GET | `/rss`、`/feed` | RSS 订阅 | +| GET | `/article/:slug` | 文章详情 | +| POST | `/article/:slug/comments` | 发表评论 | +| GET | `/login` | 登录页 | +| POST | `/login` | 提交登录 | +| GET | `/register` | 注册页 | +| POST | `/register` | 提交注册 | +| POST | `/logout` | 退出登录 | +| GET | `/uploads/*` | 静态文件(头像、附件等) | -## License +### 管理后台(需管理员权限) + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/admin` | 管理后台首页 | +| GET | `/admin/articles` | 文章列表 | +| GET/POST | `/admin/articles/new` | 新建文章 | +| GET/POST | `/admin/articles/:id/edit` | 编辑文章 | +| POST | `/admin/articles/:id/delete` | 删除文章 | +| POST | `/admin/articles/attachments` | 上传附件 | +| POST | `/admin/articles/attachments/:id/delete` | 删除附件 | +| GET | `/admin/articles/:id/attachments` | 附件列表 | +| GET | `/admin/comments` | 评论管理 | +| POST | `/admin/comments/:id/approve` | 通过评论 | +| POST | `/admin/comments/:id/reject` | 拒绝评论 | +| POST | `/admin/comments/:id/delete` | 删除评论 | +| GET | `/admin/users` | 用户列表 | +| GET/POST | `/admin/users/new` | 新建用户 | +| GET/POST | `/admin/users/:id/edit` | 编辑用户 | +| POST | `/admin/users/:id/delete` | 删除用户 | +| GET | `/admin/analytics/views` | 阅读统计 | +| GET/POST | `/admin/settings/site` | 站点设置 | +| GET/POST | `/admin/settings/navlinks` | 导航链接设置 | +| GET/POST | `/admin/settings/upload` | 上传设置 | +| GET/POST | `/admin/settings/download` | 下载设置 | +| GET/POST | `/admin/settings/comments` | 评论设置 | + +### 个人中心(需登录) + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET/POST | `/profile` | 编辑个人信息 | +| POST | `/profile/avatar` | 上传头像 | +| GET | `/my/articles` | 我的文章列表 | +| GET/POST | `/my/articles/new` | 新建文章 | +| GET/POST | `/my/articles/:id/edit` | 编辑文章 | +| POST | `/my/articles/:id/delete` | 删除文章 | +| POST | `/my/articles/attachments` | 上传附件 | +| POST | `/my/articles/attachments/:id/delete` | 删除附件 | +| GET | `/my/articles/:id/attachments` | 附件列表 | + +## 用户角色 + +| 角色 | 个人中心 | 我的文章 | 管理后台 | +| --- | --- | --- | --- | +| `admin` | ✓ | ✓ | ✓ | +| `author` | ✓ | ✓ | ✗ | + +## 许可证 MIT diff --git a/install_linux.sh b/install_linux.sh new file mode 100755 index 0000000..3464852 --- /dev/null +++ b/install_linux.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +set -euo pipefail + +SERVICE_NAME="blog_go" +SERVICE_USER="blog_go" +CONFIG_DIR="/etc/${SERVICE_NAME}" +DATA_DIR="/srv/${SERVICE_NAME}" +INSTALL_DIR="/opt/${SERVICE_NAME}" +BINARY_NAME="${SERVICE_NAME}" +SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" + +if [[ "${EUID}" -ne 0 ]]; then + echo "请使用 root 权限运行: sudo $0" >&2 + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "${SCRIPT_DIR}" + +echo "拉取最新代码..." +git pull + +echo "编译 Go 程序..." +go build -o "${BINARY_NAME}" . + +echo "检查系统用户..." +if ! id -u "${SERVICE_USER}" >/dev/null 2>&1; then + useradd --system --home-dir "${DATA_DIR}" --shell /usr/sbin/nologin "${SERVICE_USER}" +fi + +echo "创建目录..." +install -d -m 0750 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${CONFIG_DIR}" "${DATA_DIR}" +install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${INSTALL_DIR}" + +echo "安装程序和模板文件..." +install -m 0755 -o root -g root "${SCRIPT_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" +rm -rf "${INSTALL_DIR}/templates" +cp -a "${SCRIPT_DIR}/templates" "${INSTALL_DIR}/templates" +chown -R root:root "${INSTALL_DIR}/templates" +chown "${SERVICE_USER}:${SERVICE_USER}" "${INSTALL_DIR}" +chmod 0755 "${INSTALL_DIR}" +find "${INSTALL_DIR}/templates" -type d -exec chmod 0755 {} \; +find "${INSTALL_DIR}/templates" -type f -exec chmod 0644 {} \; + +if [[ ! -f "${CONFIG_DIR}/config.yaml" ]]; then + SECRET=$(openssl rand -hex 32) + cat > "${CONFIG_DIR}/config.yaml" < "${SERVICE_FILE}" <