chore: import upstream snapshot with attribution
Go / Build (push) Failing after 1s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:21 +08:00
commit a21fa4e11b
927 changed files with 832358 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"contributorsPerLine": 7,
"contributorsSortAlphabetically": false,
"skipCi": true,
"contributors": [
{
"login": "phachon",
"name": "phachon",
"avatar_url": "https://avatars3.githubusercontent.com/u/19726268?v=4",
"profile": "https://phachon.com",
"contributions": [
"code"
]
},
{
"login": "cxgreat2014",
"name": "cxgreat2014",
"avatar_url": "https://avatars2.githubusercontent.com/u/15062548?v=4",
"profile": "https://github.com/cxgreat2014",
"contributions": [
"code"
]
},
{
"login": "cifaz",
"name": "ccz",
"avatar_url": "https://avatars0.githubusercontent.com/u/4531158?v=4",
"profile": "https://github.com/cifaz",
"contributions": [
"code"
]
},
{
"login": "ruoranw",
"name": "Ruoran Wang",
"avatar_url": "https://avatars3.githubusercontent.com/u/25990237?v=4",
"profile": "https://www.linkedin.com/in/wangruoran/",
"contributions": [
"doc"
]
},
{
"login": "eahomliu",
"name": "eahomliu",
"avatar_url": "https://avatars3.githubusercontent.com/u/50134691?v=4",
"profile": "https://github.com/eahomliu",
"contributions": [
"doc",
"code"
]
}
],
"projectName": "mm-wiki",
"projectOwner": "phachon",
"repoType": "github",
"repoHost": "https://github.com"
}
+3
View File
@@ -0,0 +1,3 @@
*.js linguist-language=go
*.css linguist-language=go
*.html linguist-language=go
+25
View File
@@ -0,0 +1,25 @@
---
name: Issue 模版
about: 请尽量按照模版去创建 Issue
title: ''
labels: ''
assignees: ''
---
xxxxx这里是问题描述xxxx
1. 当前使用的版本号
vx.x.x
2. 是否已经升级到新版本
xxx
3. 当前遇到的问题
xxx
4. 错误日志或截图
xxx
5. 希望增加的功能
xxx
+28
View File
@@ -0,0 +1,28 @@
name: Go
on: [push]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
- name: Build
run: go build -v .
+21
View File
@@ -0,0 +1,21 @@
logs/*.log
.DS_Store
!.gitignore
.gitignore___jb_tmp___
*.exe
*.exe~
mm-wiki
*.session/
.mmwiki.sessions/
conf/mm-wiki.conf
mm-wiki.conf
release/
release-*
data/
install/install
install/install.exe
install.lock
.idea/
node_modules/
+273
View File
@@ -0,0 +1,273 @@
# 更新日志:
## v0.2.12020-09
### Fix Bug & Add Feature
#### 修复bug
1. 暂时去掉全文搜索功能
#### 新增功能
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.2.0-linux-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
4. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.2.02020-06
### Fix Bug & Add Feature
#### 修复bug
1. 修改文档时,文档日志不更新 #215
2. 全文搜索重构,优化性能 #197
3. markdown语法不规范导致保存后文字丢失 #176
4. 修改文档备注可不填写 #184
#### 新增功能
1. 系统联系人可选择现有用户和添加新用户 #80
2. 增加 ldap 登录
3. 允许配置系统的名称 #183
4. 系统文案可配置 #175
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.2.0-linux-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
4. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.92020-04
### Fix Bug & Add Feature
#### 修复bug
1. 修复markdown序号问题
#### 新增功能
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.9-linux-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.82020-04
### Fix Bug & Add Feature
#### 修复bug
1. 修复版本号问题
2. 首页和登录页面自适应
#### 新增功能
1. 增加在线部署网站
2. 增加文档移动排序支持
3. 增加目录大纲显示
4. 首页最近文档过滤掉无权限的空间文档
5. 一些样式调整
6. 增加 docker 支持
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.8-linux-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
### 感谢
特别感谢 [@eahomliu](https://github.com/eahomliu) [@cifaz](https://github.com/cifaz) [@cxgreat2014](https://github.com/cxgreat2014) 几位贡献 PR
## v0.1.72020-02
### Fix Bug & Add Feature
#### 修复bug
1. 修复发送邮件路径不存在
#### 新增功能
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.7-linux-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.62020-02
### Fix Bug & Add Feature
#### 修复bug
1. 修复新安装版本号不存在问题
#### 新增功能
1. 完善 pack 打包脚本
2. 修复 Windows 下 build 脚本编译问题
3. 搜索支持全文搜索功能
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.5-mac-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
4. 配置文件新增搜索相关配置(增加到自己的配置文件中)
```
# 搜索配置
[search]
interval_time=30
```
## v0.1.52019-12
### Fix Bug & Add Feature
#### 修复bug
1. 修复空间修改报错
2. 修复用户管理修改用户bug
#### 新增功能
1. 超级管理员可以重置用户密码
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.5-mac-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.42019-11
### Fix Bug & Add Feature
#### 修复bug
1. 邮箱配置发送测试失败问题
2. 去掉手机号验证
3. 修复版本号不存在问题
4. 修复空间修改bug
#### 新增功能
1. 项目改成 go mod 部署
2. 代码优化
3. linux 下增加启动脚本 run.sh
### 升级(Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压 (tar -zxvf mm-wiki-v0.1.4-mac-amd64.tar.gz)
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.32019-05
### Fix Bug & Add Feature
#### 修复bug
1. 修复启动命令不支持绝对路径问题
2. 安装向导页面优化
3. 修复首页快捷链接没有按排序号排序问题
4. 代码 go fmt
5. 更新 copyright
6. 修改系统权限 #55
7. 修复私有文档未授权访问漏洞 #55
8. 修复文档导出漏洞 #66
9. 新建文档可回车提交 #43
10. 修复文档编辑窗口过短问题 #46
11. 安装的最小环境限制 #45
11. 空间名修改后没有更新 #53
#### 新增功能
1. 新增附件上传,附件列表查看,附件删除功能
2. 图片上传分目录存储,可查看图片列表并删除
3. 分页增加每一页数量控制功能
4. 导出文件同时导出附件和图片
5. 下载文件同时下载所有的图片和附件
### Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.2 2018-11
### Fix Bug & Add Feature
1. 修复 #16 账号密码回车不能登录问题
2. 修复 #22 微信分享标题问题
3. 优化 js
4. 修复文档内容 a 标签跳转问题
5. 修复搜索框回车键不能搜索问题
6. 增加邮件测试发送功能
7. 修复邮件通知错误日志不能输出到数据库问题
8. 修复邮件通知多个发送人失败问题
9. 增加新版本自动升级命令 --upgrade
10. 增加文档本地保存,意外退出后可恢复本地文档
### Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压
3. 执行升级命令
```
./mm-wiki --conf conf/mm-wiki.conf --upgrade
```
3. 重新启动
```
./mm-wiki --conf conf/mm-wiki.conf
```
## v0.1.12018-08-08
### Fix Bug & Add Feature
1. 添加角色不能删除 #3
2. 权限删除问题
3. 空间不能删除问题 #12
4. js 优化
### Upgrade
1. 下载新版本到部署该项目的根目录
2. 覆盖解压
3. 重新启动
## v0.1 2018-07-22
### 预览版发布
+31
View File
@@ -0,0 +1,31 @@
FROM alpine/git
ENV TZ=Asia/Shanghai
WORKDIR /app
RUN git clone https://github.com/phachon/mm-wiki.git
FROM golang:1.14.1-alpine
COPY --from=0 /app/mm-wiki /app/mm-wiki
WORKDIR /app/mm-wiki
# 如果国内网络不好,可添加以下环境
# RUN go env -w GO111MODULE=on
# RUN go env -w GOPROXY=https://goproxy.cn,direct
# RUN export GO111MODULE=on
# RUN export GOPROXY=https://goproxy.cn
RUN mkdir /opt/mm-wiki && ls /app/mm-wiki
RUN go build -o /opt/mm-wiki/mm-wiki ./ \
&& cp -r ./conf/ /opt/mm-wiki \
&& cp -r ./install/ /opt/mm-wiki\
&& cp ./scripts/run.sh /opt/mm-wiki\
&& cp -r ./static/ /opt/mm-wiki\
&& cp -r ./views/ /opt/mm-wiki\
&& cp -r ./logs/ /opt/mm-wiki\
&& cp -r ./docs/ /opt/mm-wiki
CMD ["/opt/mm-wiki/mm-wiki", "--conf", "/opt/mm-wiki/conf/mm-wiki.conf"]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 phachon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+207
View File
@@ -0,0 +1,207 @@
<h2 align="center">
![brand](./static/images/logo_sm.png)
</h2>
> 首先非常感谢大家的使用,每次看到大家的留言,感到很惭愧,最近几年没有太多精力维护,另外当初在新功能迭代的时候发现 UI 和技术栈都需要彻底的重构,所以就保持在了当前版本未继续更新。后续我决定开始计划全新版本的开发,也希望大家共同参与起来。我在5年前做这个 wiki 的初衷也是期望成为国内免费开源的最好用的wiki系统,期望可以做成和 confluence 一样伟大的产品吧。
<div align="center">
MM-Wiki 是一个轻量级的企业知识分享与团队协同软件,可用于快速构建企业 Wiki 和团队知识分享平台。部署方便,使用简单,帮助团队构建一个信息共享、文档管理的协作环境。
</br>
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/phachon/mm-wiki/)
[![build](https://img.shields.io/shippable/5444c5ecb904a4b21567b0ff.svg)](https://travis-ci.org/phachon/mm-wiki)
[![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/phachon/mm-wiki/master/LICENSE)
[![platforms](https://img.shields.io/badge/platform-All-yellow.svg?style=flat)]()
[![download_count](https://img.shields.io/github/downloads/phachon/mm-wiki/total.svg?style=plastic)](https://github.com/phachon/mm-wiki/releases)
[![release](https://img.shields.io/github/release/phachon/mm-wiki.svg?style=flat)](https://github.com/phachon/mm-wiki/releases)
</div>
# 特点
- 部署方便,基于 golang 编写,只需要下载对于平台下二进制文件执行即可。
- 快速安装程序, 提供方便的安装界面程序,无需任何手动操作。
- 独立的空间,空间是一组文档的集合,一般为公司部门或者团队,空间下的文档相互独立。空间可根据需求设置空间访问级别。
- 支持 markdown 语法写作,支持附件上传。
- 完善的系统权限管理,系统可以自定义角色,并为不同角色授予不同的权限。
- 集成统一登录,本系统支持通过外部系统认证用户, 比如与公司的 LDAP 登录融合。具体请看登录认证功能。
- 邮件通知功能,当开启邮件通知,文档更改会通知所有关注该文档的用户。
- 文档具有分享和下载功能,目前只支持下载 MarkDown 源文件。
- 支持文档全文搜索
# 在线快速了解
- [mm-wiki企业知识分享与团队协同软件](http://wiki.cifaz.com/), 用户名:admin, 密码:mmwiki, 点击不了请复制http://wiki.cifaz.com/
# 安装
## 1. 自助安装
打开 https://github.com/phachon/mm-wiki/releases 找到对应平台的版本下载编译好的压缩包
- Linux 平台
```
# 创建目录
$ mkdir mm_wiki
$ cd mm_wiki
# 以 linux amd64 为例,下载最新版本压缩包
# https://github.com/phachon/mm-wiki/releases 自行下载 wget http://
# 解压到当前目录
$ tar -zxvf mm-wiki-linux-amd64.tar.gz
# 进入程序安装目录
$ cd install
# 执行安装程序,默认端口为 8090,指定其他端口加参数 --port=8087
$ ./install
# 浏览器访问 http://ip:8090 进入安装界面,完成安装配置
# Ctrl + C 停止 install 程序, 启动 MM-Wiki 系统
$ cd ..
$ ./mm-wiki --conf conf/mm-wiki.conf
# 浏览器访问你监听的 ip 和端口
# 开始 MM-Wiki 的使用之旅吧!
```
- Windows 平台
```
# 以 windows amd64 为例,下载最新版本压缩包
# https://github.com/phachon/mm-wiki/releases 自行下载
# 手动解压到当前目录
# 进入 install 目录
# 双击点开 install.exe 文件
# 浏览器访问 http://ip:8090 进入安装界面,完成安装配置
# 关闭刚刚点开的 install 窗口
# 使用 windows 命令行工具(cmd.exe)进入程序根目录
$ 执行 mm-wiki.exe --conf conf/mm-wiki.conf
# 浏览器访问你监听的 ip 和端口
# 开始 MM-Wiki 的使用之旅吧!
```
- Docker 部署
```
# 数据库准备
# 导入docs/databases/data.sql和docs/databases/table.sql(注:需取消注释data.sql中第一条管理用户插入语句)
# 两种部署方式可用
# DockerHub(推荐)
# 从DockerHub下载v0.1.7版本
# 新增配置文件,数据存放目录以及Mysql数据库配置在mm-wiki.conf配置文件中设置
# 挂载配置文件及数据存放目录,启动端口为8080
# docker run -d -p 8080:8081 -v /data/mm-wiki/conf/:/opt/mm-wiki/conf/ -v /data/mm-wiki/data:/data/mm-wiki/data/ --name mm-wiki eahom/mm-wiki:v0.1.7
# 本地构建最新代码
# 构建项目镜像
# docker build -t mm-wiki-image .
# 新增配置文件,数据存放目录以及Mysql数据库配置在mm-wiki.conf配置文件中设置
# 挂载配置文件及数据存放目录,启动端口为8080
# docker run -d -p 8080:8081 -v /data/mm-wiki/conf/:/opt/mm-wiki/conf/ -v /data/mm-wiki/data/:/data/mm-wiki/data/ --name mm-wiki mm-wiki-image
```
## 2. 如果需要,可用 nginx 配置反向代理
```
upstream frontends {
server 127.0.0.1:8088; # MM-Wiki 监听的ip:port
}
server {
listen 80;
server_name wiki.intra.xxxxx.com www.wiki.intra.xxxxx.com;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://frontends;
}
# 静态资源交由nginx管理
location /static {
root /www/mm-wiki; # MM-Wiki 的根目录
expires 1d;
add_header Cache-Control public;
access_log off;
}
}
```
# 系统预览
### 1 安装
![install](./static/images/preview/install.png)
### 2 登录
![login](./static/images/preview/login.png)
### 3 系统
![system](./static/images/preview/system.png)
### 4 空间文档
![space](./static/images/preview/space.png)
### 5 编辑文档
![edit](./static/images/preview/edit.png)
### 6 文档分享
![share](./static/images/preview/share.png)
# 使用的一些插件
MM-Wiki 是站在巨人的肩膀上开发的一款软件,是因为系统中使用了非常多优秀的插件,非常感谢这些插件的作者们:
- [bootstrap](https://github.com/twbs/bootstrap)
- [awesome-bootstrap-checkbox](https://github.com/flatlogic/awesome-bootstrap-checkbox)
- [bootstrap-iconpicker](https://victor-valencia.github.com/bootstrap-iconpicker)
- [bootstrap-select](http://silviomoreto.github.io/bootstrap-select)
- [bootstrap-switch](https://bttstrp.github.io/bootstrap-switch)
- [bootstrap-tagsinput](https://github.com/bootstrap-tagsinput/bootstrap-tagsinput)
- [editor.md](https://github.com/pandao/editor.md)
- [layout](http://jquery-dev.com)
- [layer](http://layer.layui.com/)
- [metisMenu](https://github.com/onokumus/metisMenu)
- [morris](http://morrisjs.github.com/morris.js/)
- [popover](https://github.com/sandywalker/webui-popover)
- [scrollup](http://markgoodyear.com/labs/scrollup/)
- [zTreev3](http://treejs.cn/)
# 二次开发
环境要求:go 1.8
```
$ git clone https://github.com/phachon/mm-wiki.git
$ cd mm-wiki
$ go build ./
```
>如果你想为 mm-wiki 贡献代码,请加开发者交流群:922827699
## 贡献者列表
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://phachon.com"><img src="https://avatars3.githubusercontent.com/u/19726268?v=4" width="100px;" alt=""/><br /><sub><b>phachon</b></sub></a><br /><a href="https://github.com/phachon/mm-wiki/commits?author=phachon" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/cxgreat2014"><img src="https://avatars2.githubusercontent.com/u/15062548?v=4" width="100px;" alt=""/><br /><sub><b>cxgreat2014</b></sub></a><br /><a href="https://github.com/phachon/mm-wiki/commits?author=cxgreat2014" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/cifaz"><img src="https://avatars0.githubusercontent.com/u/4531158?v=4" width="100px;" alt=""/><br /><sub><b>ccz</b></sub></a><br /><a href="https://github.com/phachon/mm-wiki/commits?author=cifaz" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/wangruoran/"><img src="https://avatars3.githubusercontent.com/u/25990237?v=4" width="100px;" alt=""/><br /><sub><b>Ruoran Wang</b></sub></a><br /><a href="https://github.com/phachon/mm-wiki/commits?author=ruoranw" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/eahomliu"><img src="https://avatars3.githubusercontent.com/u/50134691?v=4" width="100px;" alt=""/><br /><sub><b>eahomliu</b></sub></a><br /><a href="https://github.com/phachon/mm-wiki/commits?author=eahomliu" title="Documentation">📖</a> <a href="https://github.com/phachon/mm-wiki/commits?author=eahomliu" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
## 支持
请作者喝杯茶吧!
## 反馈
- 官方 QQ 交流群:853467682
- 如果您喜欢该项目,请 [Star](https://github.com/phachon/mm-wiki/stargazers).
- 如果在使用过程中有任何问题, 请提交 [Issue](https://github.com/phachon/mm-wiki/issues).
- 如果您发现并解决了bug,请提交 [Pull Request](https://github.com/phachon/mm-wiki/pulls).
- 如果您想二次开发,欢迎 [Fork](https://github.com/phachon/mm-wiki/network/members).
- 如果你想交个朋友,欢迎发邮件给 [phachon@163.com](mailto:phachon@163.com).
## License
MIT
谢谢
---
Create By phachon
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`phachon/mm-wiki`
- 原始仓库:https://github.com/phachon/mm-wiki
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+152
View File
@@ -0,0 +1,152 @@
![brand](./static/images/logo_sm.png)
MM-Wiki is a light software that enables companies for internal knowledge sharing and for better collaboration. It serves as a platform for information sharing and wiki creating within as well as among teams.
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/phachon/mm-wiki/)
[![build](https://img.shields.io/shippable/5444c5ecb904a4b21567b0ff.svg)](https://travis-ci.org/phachon/mm-wiki)
[![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/phachon/mm-wiki/master/LICENSE)
[![platforms](https://img.shields.io/badge/platform-All-yellow.svg?style=flat)]()
[![download_count](https://img.shields.io/github/downloads/phachon/mm-wiki/total.svg?style=plastic)](https://github.com/phachon/mm-wiki/releases)
[![release](https://img.shields.io/github/release/phachon/mm-wiki.svg?style=flat)](https://github.com/phachon/mm-wiki/releases)
# Features
- Easy deployment. Its built with [Go](https://golang.org/doc/). You only need to download the package based on your system and execute the binary file.
- Quick installation. It has a clean and concise installing interface that guides you through the process.
- Private space for each team and department. By setting permissions, other teams/departments can read, edit files.
- Flexible system administration setting. Each user has different roles with various aspects of permissions accordingly.
- This app allows users to log in through certified external system such as the companys LDAP log in system.
- Stay synced with your team. Youll receive email notifications when the file you're following is updated.
- Share and download the file. For now you can only download files in the form of Markdown plain text.
- Support full text search.
# Introduction
- [mm-wiki](http://wiki.cifaz.com/), userName:admin, password:mmwiki; If cannot click it, Copy the URL: http://wiki.cifaz.com/
# Installation
## Install by downloading it.
- Linux
```
# Make a directory.
$ mkdir mm_wiki
$ cd mm_wiki
# Take linux amd64 as an example: download the latest release of the software.
# Downloading address: https://github.com/phachon/mm-wiki/releases
# Unzip the file to the directory you just created.
$ tar -zxvf mm-wiki-linux-amd64.tar.gz
# Enter into the installation directory
$ cd install
# Execute the file. The default port is 8090. Set another port using: --port=8087
$ ./install
# Visit http://ip:8090 in a browser. Now you should see the installation interface. Follow the instruction to finish settings.
# Ctrl + C to stop installation. Turn on MM-Wiki.
$ cd ..
$ ./mm-wiki --conf conf/mm-wiki.conf
# Now you can visit the ip address with the port the system is listening.
# Enjoy using MM-wiki!
```
- Windows
1.Take linux amd64 as an example: [download](https://github.com/phachon/mm-wiki/releases) the latest release of the software.<br />
2.Unzip the file to a directory that you set before.<br />
3.Click into the install directory.<br />
4.Double click install.exe. <br />
5.Visit http://ip:8090 in a browser and now you should see the installation interface. Follow instructions to finish installations.<br />
6.Close the installation window.<br />
7.Use command linecmd.exeto enter into the root directory.<br />
`$ execute mm-wiki.exe --conf conf/mm-wiki.conf`<br />
8.Now you can visit the ip address with the port the system is listening. Enjoy using MM-wiki!<br />
**Note**: If the there's 502 error in the browser when you should see the installation guide instead, change a browser and try it again.<br />
## Install with Nginx reverse proxy
```
upstream frontends {
server 127.0.0.1:8088; # MM-Wiki listening ip:port
}
server {
listen 80;
server_name wiki.intra.xxxxx.com www.wiki.intra.xxxxx.com;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://frontends;
}
# static resources managed by nginx
location /static {
root /www/mm-wiki; # MM-Wiki root directory
expires 1d;
add_header Cache-Control public;
access_log off;
}
}
```
# A quick look
### 1 Installing
![install](./static/images/preview/install.png)
### 2 Log in
![login](./static/images/preview/login.png)
### 3 The system
![system](./static/images/preview/system.png)
### 4 The interface
![space](./static/images/preview/space.png)
### 5 Files editing
![edit](./static/images/preview/edit.png)
### 6 Files sharing
![share](./static/images/preview/share.png)
# Plugins that are used in this app
MM-Wiki is built with many great plugins. Many thanks to developers of these plugins:
- [bootstrap](https://github.com/twbs/bootstrap)
- [awesome-bootstrap-checkbox](https://github.com/flatlogic/awesome-bootstrap-checkbox)
- [bootstrap-iconpicker](https://victor-valencia.github.com/bootstrap-iconpicker)
- [bootstrap-select](http://silviomoreto.github.io/bootstrap-select)
- [bootstrap-switch](https://bttstrp.github.io/bootstrap-switch)
- [bootstrap-tagsinput](https://github.com/bootstrap-tagsinput/bootstrap-tagsinput)
- [editor.md](https://github.com/pandao/editor.md)
- [layout](http://jquery-dev.com)
- [layer](http://layer.layui.com/)
- [metisMenu](https://github.com/onokumus/metisMenu)
- [morris](http://morrisjs.github.com/morris.js/)
- [popover](https://github.com/sandywalker/webui-popover)
- [scrollup](http://markgoodyear.com/labs/scrollup/)
- [zTreev3](http://treejs.cn/)
# Contributing
Requirementgo 1.8
```
$ git clone https://github.com/phachon/mm-wiki.git
$ cd mm-wiki
$ go build ./
```
## Supporting
If you want to buy me a coffee :)
![wechat](./static/images/preview/wechat_1.png)
![alipay](./static/images/preview/alipay_2.png)
## Feedback
- Official QQ group number853467682
- If you like this app, please [Star](https://github.com/phachon/mm-wiki/stargazers) it.
- If there're issues while you're using it, submit a [issue](https://github.com/phachon/mm-wiki/issues).
- If you find a bug and solve it, make a [pull request](https://github.com/phachon/mm-wiki/pulls).
- If you want to contribute to it, please [fork](https://github.com/phachon/mm-wiki/network/members) it.
- If you want to make friends with me,shoot me an email at [phachon@163.com](mailto:phachon@163.com).
## License
MIT
Many thanks!
---
Created By [phachon](https://github.com/phachon)
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-architect
+271
View File
@@ -0,0 +1,271 @@
package app
import (
"flag"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/fatih/color"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/phachon/mm-wiki/app/work"
"github.com/phachon/mm-wiki/global"
"github.com/snail007/go-activerecord/mysql"
"log"
"os"
"path"
"path/filepath"
"time"
)
var (
defaultConf = "conf/mm-wiki.conf"
confPath = flag.String("conf", "", "please set mm-wiki conf path")
version = flag.Bool("version", false, "mm-wiki version")
upgrade = flag.Bool("upgrade", false, "mm-wiki upgrade")
Version = global.SYSTEM_VERSION
CopyRight = beego.Str2html(global.SYSTEM_COPYRIGHT)
StartTime = int64(0)
RootDir = ""
DocumentAbsDir = ""
MarkdownAbsDir = ""
ImageAbsDir = ""
AttachmentAbsDir = ""
SearchIndexAbsDir = ""
)
func init() {
initFlag()
poster()
initConfig()
initDB()
checkUpgrade()
initDocumentDir()
//initSearch()
//initWork()
StartTime = time.Now().Unix()
}
// init flag
func initFlag() {
flag.Parse()
// --version
if *version == true {
fmt.Printf(Version)
os.Exit(0)
}
}
// poster logo
func poster() {
fg := color.New(color.FgBlue)
logo := `
_ _ _
_ __ ___ _ __ ___ __ __ (_) | | __ (_)
| '_ ' _ \ | '_ ' _ \ _____ \ \ /\ / / | | | |/ / | |
| | | | | | | | | | | | |_____| \ V V / | | | < | |
|_| |_| |_| |_| |_| |_| \_/\_/ |_| |_|\_\ |_|
` +
"Author: phachon\r\n" +
"Version: " + Version + "\r\n" +
"Link: https://github.com/phachon/mm-wiki"
fg.Println(logo)
}
// init beego config
func initConfig() {
RootDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Println("init config error: " + err.Error())
os.Exit(1)
}
confFile := *confPath
if *confPath == "" {
confFile = filepath.Join(RootDir, defaultConf)
}
ok, _ := utils.NewFile().PathIsExists(confFile)
if ok == false {
log.Println("conf file " + confFile + " not exists!")
os.Exit(1)
}
// init config file
beego.LoadAppConfig("ini", confFile)
// init name
beego.AppConfig.Set("sys.name", "mm-wiki")
beego.BConfig.AppName = beego.AppConfig.String("sys.name")
beego.BConfig.ServerName = beego.AppConfig.String("sys.name")
// set static path
beego.SetStaticPath("/static/", filepath.Join(RootDir, "./static"))
// views path
beego.BConfig.WebConfig.ViewsPath = filepath.Join(RootDir, "./views/")
// session
//beego.BConfig.WebConfig.Session.SessionProvider = "memory"
//beego.BConfig.WebConfig.Session.SessionProviderConfig = ".session"
//beego.BConfig.WebConfig.Session.SessionName = "mmwikissid"
//beego.BConfig.WebConfig.Session.SessionOn = true
// log
logConfigs, err := beego.AppConfig.GetSection("log")
if err != nil {
log.Println(err.Error())
os.Exit(1)
}
for adapter, config := range logConfigs {
logs.SetLogger(adapter, config)
}
logs.SetLogFuncCall(true)
}
//init db
func initDB() {
host := beego.AppConfig.String("db::host")
port, _ := beego.AppConfig.Int("db::port")
user := beego.AppConfig.String("db::user")
pass := beego.AppConfig.String("db::pass")
dbname := beego.AppConfig.String("db::name")
dbTablePrefix := beego.AppConfig.String("db::table_prefix")
maxIdle, _ := beego.AppConfig.Int("db::conn_max_idle")
maxConn, _ := beego.AppConfig.Int("db::conn_max_connection")
models.G = mysql.NewDBGroup("default")
cfg := mysql.NewDBConfigWith(host, port, dbname, user, pass)
cfg.SetMaxIdleConns = maxIdle
cfg.SetMaxOpenConns = maxConn
cfg.TablePrefix = dbTablePrefix
cfg.TablePrefixSqlIdentifier = "__PREFIX__"
err := models.G.Regist("default", cfg)
if err != nil {
logs.Error(fmt.Errorf("database error:%s,with config : %v", err, cfg))
os.Exit(1)
}
}
// init document dir
func initDocumentDir() {
docRootDir := beego.AppConfig.String("document::root_dir")
if docRootDir == "" {
logs.Error("document root dir " + docRootDir + " is not empty!")
os.Exit(1)
}
ok, _ := utils.File.PathIsExists(docRootDir)
if !ok {
logs.Error("document root dir " + docRootDir + " is not exists!")
os.Exit(1)
}
documentAbsDir, err := filepath.Abs(docRootDir)
if err != nil {
logs.Error("document root dir " + docRootDir + " is error!")
os.Exit(1)
}
DocumentAbsDir = documentAbsDir
// markdown save dir
markDownAbsDir := path.Join(documentAbsDir, "markdowns")
// image save dir
imagesAbsDir := path.Join(documentAbsDir, "images")
// attachment save dir
attachmentAbsDir := path.Join(documentAbsDir, "attachment")
// search index dir
searchIndexAbsDir := path.Join(documentAbsDir, "search-index")
MarkdownAbsDir = markDownAbsDir
ImageAbsDir = imagesAbsDir
AttachmentAbsDir = attachmentAbsDir
SearchIndexAbsDir = searchIndexAbsDir
dirList := []string{MarkdownAbsDir, ImageAbsDir, AttachmentAbsDir, SearchIndexAbsDir}
// create dir
for _, dir := range dirList {
ok, _ = utils.File.PathIsExists(dir)
if !ok {
err := os.Mkdir(dir, 0777)
if err != nil {
logs.Error("create document dir "+dir+" error=%s", err.Error())
os.Exit(1)
}
}
}
// utils document
utils.Document.MarkdownAbsDir = markDownAbsDir
utils.Document.DocumentAbsDir = documentAbsDir
beego.SetStaticPath("/images/", ImageAbsDir)
// todo
beego.SetStaticPath("/images/:space_id/:document_id/", ImageAbsDir)
}
// check upgrade
func checkUpgrade() {
if *upgrade == true {
logs.Info("Start checking whether MM-Wiki needs upgrading.")
var versionDb = "v0.0.0"
versionConf := models.ConfigModel.GetConfigValueByKey(models.ConfigKeySystemVersion, "v0.0.0")
if versionConf != "" {
versionDb = versionConf
}
logs.Info("MM-Wiki Database version" + versionDb)
logs.Info("MM-Wiki Now version: " + Version)
if versionDb == Version {
logs.Info("MM-Wiki does not need updating.")
} else {
logs.Info("MM-Wiki start upgrading.")
err := models.UpgradeModel.Start(versionDb)
if err != nil {
logs.Error("MM-Wiki upgrade failed.")
os.Exit(1)
}
logs.Info("MM-Wiki upgrade finish.")
}
os.Exit(0)
}
}
func initSearch() {
gseFile := filepath.Join(RootDir, "docs/search_dict/dictionary.txt")
stopFile := filepath.Join(RootDir, "docs/search_dict/stop_tokens.txt")
ok, _ := utils.File.PathIsExists(gseFile)
if !ok {
logs.Error("search dict file " + gseFile + " is not exists!")
os.Exit(1)
}
ok, _ = utils.File.PathIsExists(stopFile)
if !ok {
logs.Error("search stop dict file " + stopFile + " is not exists!")
os.Exit(1)
}
//global.DocSearcher.Init(types.EngineOpts{
// UseStore: true,
// StoreFolder: SearchIndexAbsDir,
// Using: 3,
// //GseDict: "zh",
// GseDict: gseFile,
// StopTokenFile: stopFile,
// IndexerOpts: &types.IndexerOpts{
// IndexType: types.LocsIndex,
// },
//})
}
func initWork() {
work.DocSearchWorker.Start()
}
+342
View File
@@ -0,0 +1,342 @@
package controllers
import (
"fmt"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"os"
"path"
)
type AttachmentController struct {
BaseController
}
func (this *AttachmentController) Page() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("页面参数错误!", "/space/index")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找空间文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
isVisit, isEditor, isManager := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问该空间下的文档!")
}
// get document attachments
attachments, err := models.AttachmentModel.GetAttachmentsByDocumentIdAndSource(documentId, models.Attachment_Source_Default)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 附件失败:" + err.Error())
this.ViewError("查找文档附件失败!")
}
// get username
userIds := []string{}
for _, attachment := range attachments {
userIds = append(userIds, attachment["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 附件失败:" + err.Error())
this.ViewError("查找文档附件失败!")
}
usernameMap := make(map[string]string)
for _, user := range users {
usernameMap[user["user_id"]] = user["username"]
}
for _, attachment := range attachments {
attachment["username"] = usernameMap[attachment["user_id"]]
}
this.Data["attachments"] = attachments
this.Data["document_id"] = documentId
this.Data["is_upload"] = isEditor
this.Data["is_delete"] = isManager
this.viewLayout("attachment/page", "attachment")
}
func (this *AttachmentController) Upload() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
documentId := this.GetString("document_id", "")
if documentId == "" {
this.uploadJsonError("参数错误!", "/space/index")
}
// handle document
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找空间文档 " + documentId + " 失败:" + err.Error())
this.uploadJsonError("查找文档失败!")
}
if len(document) == 0 {
this.uploadJsonError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.uploadJsonError("查找文档失败!")
}
if len(space) == 0 {
this.uploadJsonError("文档所在空间不存在!")
}
// check space visit_level
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.uploadJsonError("您没有权限操作该空间下的文档!")
}
// handle upload
f, h, err := this.GetFile("attachment")
if err != nil {
this.ErrorLog("上传附件数据错误: " + err.Error())
this.uploadJsonError("上传附件数据错误")
return
}
if h == nil || f == nil {
this.ErrorLog("上传附件错误")
this.uploadJsonError("上传附件错误")
return
}
_ = f.Close()
// file save dir
saveDir := fmt.Sprintf("%s/%s/%s", app.AttachmentAbsDir, spaceId, documentId)
ok, _ := utils.File.PathIsExists(saveDir)
if !ok {
err := os.MkdirAll(saveDir, 0777)
if err != nil {
this.ErrorLog("上传附件错误: " + err.Error())
this.uploadJsonError("上传附件失败")
return
}
}
// check file is exists
attachmentFile := path.Join(saveDir, h.Filename)
ok, _ = utils.File.PathIsExists(attachmentFile)
if ok {
this.uploadJsonError("该附件已经存在!")
}
// save file
err = this.SaveToFile("attachment", attachmentFile)
if err != nil {
this.ErrorLog("附件保存失败: " + err.Error())
this.uploadJsonError("附件保存失败")
}
// insert db
attachment := map[string]interface{}{
"user_id": this.UserId,
"document_id": documentId,
"name": h.Filename,
"path": fmt.Sprintf("attachment/%s/%s/%s", spaceId, documentId, h.Filename),
"source": models.Attachment_Source_Default,
}
_, err = models.AttachmentModel.Insert(attachment, spaceId)
if err != nil {
_ = os.Remove(attachmentFile)
this.ErrorLog("上传附件错误: " + err.Error())
this.uploadJsonError("附件信息保存失败")
}
this.InfoLog(fmt.Sprintf("文档 %s 上传附件 %s 成功", documentId, h.Filename))
this.jsonSuccess("附件上传成功", "", "/attachment/page?document_id="+documentId)
}
func (this *AttachmentController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
attachmentId := this.GetString("attachment_id", "")
if attachmentId == "" {
this.jsonError("没有选择附件!")
}
attachment, err := models.AttachmentModel.GetAttachmentByAttachmentId(attachmentId)
if err != nil {
this.ErrorLog("删除附件 " + attachmentId + " 失败: " + err.Error())
this.jsonError("删除附件失败")
}
if len(attachment) == 0 {
this.jsonError("附件不存在")
}
documentId := attachment["document_id"]
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找附件所属空间文档 " + documentId + " 失败:" + err.Error())
this.jsonError("查找附件所属文档失败!")
}
if len(document) == 0 {
this.jsonError("附件所属文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找附件所属文档 " + documentId + " 所在空间失败:" + err.Error())
this.jsonError("查找附件所属文档空间失败!")
}
if len(space) == 0 {
this.jsonError("附件所属文档所在空间不存在!")
}
// check space visit_level
_, _, isManager := this.GetDocumentPrivilege(space)
if !isManager {
this.jsonError("您没有权限删除该空间下的文档!")
}
attachmentName := attachment["name"]
attachmentSource := attachment["source"]
// delete db
err = models.AttachmentModel.DeleteAttachmentDBFile(attachmentId)
if err != nil {
this.ErrorLog("删除附件 " + attachmentId + " 失败: " + err.Error())
this.jsonError("删除附件失败")
}
// update document log
go func(userId string, documentId string, attachmentName string, spaceId string) {
_, _ = models.LogDocumentModel.UpdateAction(userId, documentId, "删除了附件 "+attachmentName, spaceId)
}(this.UserId, documentId, attachmentName, spaceId)
redirect := fmt.Sprintf("/attachment/page?document_id=%s", documentId)
if attachmentSource == fmt.Sprintf("%d", models.Attachment_Source_Image) {
redirect = fmt.Sprintf("/attachment/image?document_id=%s", documentId)
}
this.InfoLog("删除文档 " + documentId + " 附件 " + attachmentName + " 成功")
this.jsonSuccess("删除成功", nil, redirect)
}
func (this *AttachmentController) Download() {
attachmentId := this.GetString("attachment_id", "")
if attachmentId == "" {
this.ViewError("没有选择附件!")
}
attachment, err := models.AttachmentModel.GetAttachmentByAttachmentId(attachmentId)
if err != nil {
this.ErrorLog("下载附件 " + attachmentId + " 失败: " + err.Error())
this.ViewError("下载附件失败")
}
if len(attachment) == 0 {
this.ViewError("附件不存在")
}
documentId := attachment["document_id"]
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找附件所属空间文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找附件所属文档失败!")
}
if len(document) == 0 {
this.ViewError("附件所属文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找附件所属文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找附件所属文档空间失败!")
}
if len(space) == 0 {
this.ViewError("附件所属文档所在空间不存在!")
}
// check space visit_level
isVisit, _, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问或下载该空间下的资料!")
}
attachmentFilePath := path.Join(app.DocumentAbsDir, attachment["path"])
attachmentName := attachment["name"]
this.Ctx.Output.Download(attachmentFilePath, attachmentName)
}
func (this *AttachmentController) Image() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("页面参数错误!", "/space/index")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找空间文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
isVisit, isEditor, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问该空间下的文档!")
}
// get document attachment images
attachments, err := models.AttachmentModel.GetAttachmentsByDocumentIdAndSource(documentId, models.Attachment_Source_Image)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 图片失败:" + err.Error())
this.ViewError("查找文档图片失败!")
}
// get username
userIds := []string{}
for _, attachment := range attachments {
userIds = append(userIds, attachment["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 图片失败:" + err.Error())
this.ViewError("查找文档图片失败!")
}
usernameMap := make(map[string]string)
for _, user := range users {
usernameMap[user["user_id"]] = user["username"]
}
for _, attachment := range attachments {
attachment["username"] = usernameMap[attachment["user_id"]]
}
this.Data["attachments"] = attachments
this.Data["document_id"] = documentId
this.Data["is_delete"] = isEditor
this.viewLayout("attachment/image", "attachment")
}
+190
View File
@@ -0,0 +1,190 @@
package controllers
import (
"fmt"
"strings"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/services"
"github.com/phachon/mm-wiki/app/utils"
)
type AuthorController struct {
BaseController
}
// login index
func (this *AuthorController) Index() {
// is open auth login
ssoOpen := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyAuthLogin, "0")
this.Data["sso_open"] = ssoOpen
this.viewLayout("author/login", "author")
}
// login
func (this *AuthorController) Login() {
if !this.IsPost() {
this.ViewError("请求方式有误!")
}
username := strings.TrimSpace(this.GetString("username"))
password := strings.TrimSpace(this.GetString("password"))
if username == "" {
this.jsonError("系统用户名不能为空!")
}
if strings.Contains(username, "_") {
this.jsonError("系统用户名不合法!")
}
if password == "" {
this.jsonError("密码不能为空!")
}
user, err := models.UserModel.GetUserByUsername(username)
if err != nil {
this.jsonError("登录出错")
}
if len(user) == 0 || username != user["username"] {
this.jsonError("用户名或密码错误!")
}
if user["is_forbidden"] == fmt.Sprintf("%d", models.User_Forbidden_True) {
this.jsonError("用户已被禁用!")
}
password = utils.Encrypt.Md5Encode(password)
if user["password"] != password {
this.jsonError("用户名或密码错误!")
}
// update last_ip and last_login_time
updateValue := map[string]interface{}{
"last_time": time.Now().Unix(),
"last_ip": this.GetClientIp(),
}
_, err = models.UserModel.Update(user["user_id"], updateValue)
if err != nil {
this.jsonError("登录出错")
}
// save session
this.SetSession("author", user)
// save cookie
identify := utils.Encrypt.Md5Encode(this.Ctx.Request.UserAgent() + this.GetClientIp() + password)
passportValue := utils.Encrypt.Base64Encode(username + "@" + identify)
passport := beego.AppConfig.String("author::passport")
cookieExpired, _ := beego.AppConfig.Int64("author::cookie_expired")
this.Ctx.SetCookie(passport, passportValue, cookieExpired)
this.Ctx.Request.PostForm.Del("password")
this.InfoLog("登录成功")
this.jsonSuccess("登录成功!", nil, "/main/index")
}
// auth login
func (this *AuthorController) AuthLogin() {
if !this.IsPost() {
this.ViewError("请求方式有误!")
}
// is open auth login
authLoginConf := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyAuthLogin, "0")
if authLoginConf != "1" {
this.jsonError("系统未开启统一登录功能!")
}
// get auth login config
authLogin, err := models.AuthModel.GetUsedAuth()
if err != nil || len(authLogin) == 0 {
this.jsonError("统一登录认证配置不可用!")
}
username := strings.TrimSpace(this.GetString("username"))
password := strings.TrimSpace(this.GetString("password"))
if username == "" {
this.jsonError("统一登录用户名不能为空!")
}
if password == "" {
this.jsonError("统一登录密码不能为空!")
}
authLoginRes, err := services.AuthLogin.AuthLogin(username, password)
if err != nil {
logs.Error("统一登录失败:", err.Error())
this.jsonError("统一登录失败!")
return
}
if authLoginRes == nil {
this.jsonError("统一登录失败!")
return
}
realUsername := authLogin["username_prefix"] + "_" + username
passwordEncode := models.UserModel.EncodePassword(password)
userValue := map[string]interface{}{
"username": realUsername,
"given_name": authLoginRes.GivenName,
"password": passwordEncode,
"email": authLoginRes.Email,
"mobile": authLoginRes.Mobile,
"phone": authLoginRes.Phone,
"department": authLoginRes.Department,
"position": authLoginRes.Position,
"location": authLoginRes.Location,
"im": authLoginRes.Im,
"last_time": time.Now().Unix(),
"last_ip": this.GetClientIp(),
}
ok, err := models.UserModel.HasUsername(realUsername)
if err != nil {
this.jsonError("登录失败!")
}
if ok {
// update user info
_, err = models.UserModel.UpdateUserByUsername(userValue)
} else {
// insert user info
userValue["role_id"] = models.Role_Default_Id
_, err = models.UserModel.Insert(userValue)
}
if err != nil {
this.jsonError("登录失败!" + err.Error())
}
// get user by username
user, err := models.UserModel.GetUserByUsername(realUsername)
if err != nil {
this.jsonError("登录失败:" + err.Error())
}
if len(user) == 0 {
this.jsonError("登录失败!")
}
// save session
this.SetSession("author", user)
// save cookie
identify := utils.Encrypt.Md5Encode(this.Ctx.Request.UserAgent() + this.GetClientIp() + passwordEncode)
passportValue := utils.Encrypt.Base64Encode(user["username"] + "@" + identify)
passport := beego.AppConfig.String("author::passport")
cookieExpired, _ := beego.AppConfig.Int64("author::cookie_expired")
this.Ctx.SetCookie(passport, passportValue, cookieExpired)
this.Ctx.Request.PostForm.Del("password")
this.InfoLog("登录成功")
this.jsonSuccess("登录成功!", nil, "/main/index")
}
//logout
func (this *AuthorController) Logout() {
this.InfoLog("退出成功")
passport := beego.AppConfig.String("author::passport")
this.Ctx.SetCookie(passport, "")
this.SetSession("author", nil)
this.DelSession("author")
this.Redirect("/", 302)
}
+63
View File
@@ -0,0 +1,63 @@
package controllers
import "encoding/json"
type BaseController struct {
TemplateController
}
// view layout
func (this *BaseController) viewLayout(viewName, layout string) {
layout = "layouts/" + layout
this.ViewLayout(viewName, layout)
}
// return json success
func (this *BaseController) jsonSuccess(message interface{}, data ...interface{}) {
this.JsonSuccess(message, data...)
}
// return json error
func (this *BaseController) jsonError(message interface{}, data ...interface{}) {
this.JsonError(message, data...)
}
type UploadJsonResponse struct {
Code int `json:"code"`
Message interface{} `json:"message"`
Data interface{} `json:"data"`
Redirect map[string]interface{} `json:"redirect"`
Error interface{} `json:"error"`
}
func (this *BaseController) uploadJsonError(message interface{}, data ...interface{}) {
url := ""
sleep := 2000
var _data interface{}
if len(data) > 0 {
_data = data[0]
}
if len(data) > 1 {
url = data[1].(string)
}
if len(data) > 2 {
sleep = data[2].(int)
}
this.Data["json"] = UploadJsonResponse{
Code: 0,
Message: message,
Data: _data,
Redirect: map[string]interface{}{
"url": url,
"sleep": sleep,
},
Error: message,
}
j, err := json.MarshalIndent(this.Data["json"], "", " \t")
if err != nil {
this.Abort(err.Error())
} else {
this.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
this.Abort(string(j))
}
}
+87
View File
@@ -0,0 +1,87 @@
package controllers
import (
"time"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
)
type CollectionController struct {
BaseController
}
func (this *CollectionController) Add() {
redirect := this.Ctx.Request.Referer()
if !this.IsPost() {
this.ViewError("请求方式有误!", "/main/index")
}
resourceId := this.GetString("resource_id", "")
colType, _ := this.GetInt("type", 1)
if resourceId == "" {
this.jsonError("没有选项收藏资源!")
}
if colType != models.Collection_Type_Doc && colType != models.Collection_Type_Space {
this.jsonError("收藏类型错误!")
}
collect, err := models.CollectionModel.GetCollectionByUserIdTypeAndResourceId(this.UserId, colType, resourceId)
if err != nil {
this.ErrorLog("添加收藏失败:" + err.Error())
this.jsonError("添加收藏失败!")
}
if len(collect) > 0 {
this.jsonError("您已收藏过,不能重复收藏!")
}
insertCollection := map[string]interface{}{
"user_id": this.UserId,
"resource_id": resourceId,
"type": colType,
"create_time": time.Now().Unix(),
}
collectId, err := models.CollectionModel.Insert(insertCollection)
if err != nil {
this.ErrorLog("添加收藏失败:" + err.Error())
this.jsonError("添加收藏失败!")
}
this.InfoLog("添加收藏 " + utils.Convert.IntToString(collectId, 10) + " 成功")
this.jsonSuccess("收藏成功!", nil, redirect)
}
func (this *CollectionController) Cancel() {
redirect := this.Ctx.Request.Referer()
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/list")
}
collectionId := this.GetString("collection_id", "")
if collectionId == "" {
this.jsonError("没有选择收藏资源!")
}
collection, err := models.CollectionModel.GetCollectionByCollectionId(collectionId)
if err != nil {
this.ErrorLog("取消收藏 " + collectionId + " 失败:" + err.Error())
this.jsonError("取消收藏失败!")
}
if len(collection) == 0 {
this.jsonError("收藏资源不存在!")
}
if collection["user_id"] != this.UserId {
this.jsonError("您只能取消自己的收藏!")
}
err = models.CollectionModel.Delete(collectionId)
if err != nil {
this.ErrorLog("取消收藏 " + collectionId + " 失败:" + err.Error())
this.jsonError("取消收藏失败!")
}
this.InfoLog("取消收藏 " + collectionId + " 成功")
this.jsonSuccess("已取消收藏!", nil, redirect)
}
+492
View File
@@ -0,0 +1,492 @@
package controllers
import (
"fmt"
"github.com/phachon/mm-wiki/app/services"
"regexp"
"strings"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
)
type DocumentController struct {
BaseController
}
// document index
func (this *DocumentController) Index() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("页面参数错误!", "/space/index")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找空间文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
isVisit, _, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问该空间下的文档!")
}
// get default space document
spaceDocument, err := models.DocumentModel.GetSpaceDefaultDocument(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(spaceDocument) == 0 {
this.ViewError(" 空间首页文档不存在!")
}
// get space all document
documents, err := models.DocumentModel.GetAllSpaceDocuments(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
// get space privilege
_, isEditor, isDelete := this.GetDocumentPrivilege(space)
this.Data["is_editor"] = isEditor
this.Data["is_delete"] = isDelete
this.Data["documents"] = documents
this.Data["default_document_id"] = documentId
this.Data["space"] = space
this.Data["space_document"] = spaceDocument
this.viewLayout("document/index", "document")
}
// add document
func (this *DocumentController) Add() {
spaceId := this.GetString("space_id", "0")
parentId := this.GetString("parent_id", "0")
if spaceId == "0" {
this.ViewError("没有选择空间!")
}
if parentId == "0" {
this.ViewError("没有选择上级!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("添加文档失败:" + err.Error())
this.ViewError("添加文档失败!")
}
if len(space) == 0 {
this.ViewError("空间不存在!")
}
// check space document privilege
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.ViewError("您没有权限在该空间下创建文档!")
}
parentDocument, err := models.DocumentModel.GetDocumentByDocumentId(parentId)
if err != nil {
this.ErrorLog("添加文档 " + parentId + " 失败:" + err.Error())
this.ViewError("添加文档失败!")
}
if len(parentDocument) == 0 {
this.ViewError("父文档不存在!")
}
path := parentDocument["path"] + "," + parentId
// get parent documents by path
parentDocuments, err := models.DocumentModel.GetParentDocumentsByPath(path)
if err != nil {
this.ErrorLog("查找父文档失败:" + err.Error())
this.ViewError("查找父文档失败!")
}
if len(parentDocuments) == 0 {
this.ViewError("父文档不存在!")
}
this.Data["parent_documents"] = parentDocuments
this.Data["parent_id"] = parentId
this.Data["space_id"] = spaceId
this.viewLayout("document/form", "default")
}
// save document
func (this *DocumentController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/main/index")
}
spaceId := strings.TrimSpace(this.GetString("space_id", "0"))
parentId := strings.TrimSpace(this.GetString("parent_id", "0"))
docType, _ := this.GetInt("type", models.Document_Type_Page)
name := strings.TrimSpace(this.GetString("name", ""))
if spaceId == "0" {
this.jsonError("没有选择空间!")
}
if parentId == "0" {
this.jsonError("没有选择父文档!")
}
if name == "" {
this.jsonError("文档名称不能为空!")
}
match, err := regexp.MatchString(`[\\\\/:*?\"<>、|]`, name)
if err != nil {
this.jsonError("文档名称格式不正确!")
}
if match {
this.jsonError("文档名称格式不正确!")
}
if name == utils.Document_Default_FileName {
this.jsonError("文档名称不能为 " + utils.Document_Default_FileName + " ")
}
if docType != models.Document_Type_Page &&
docType != models.Document_Type_Dir {
this.jsonError("文档类型错误!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("创建保存文档失败:" + err.Error())
this.jsonError("创建文档失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
// check space document privilege
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.jsonError("您没有权限在该空间下创建文档!")
}
parentDocument, err := models.DocumentModel.GetDocumentByDocumentId(parentId)
if err != nil {
this.ErrorLog("创建保存文档失败:" + err.Error())
this.jsonError("创建文档失败!")
}
if len(parentDocument) == 0 {
this.jsonError("父文档不存在!")
}
if parentDocument["type"] != fmt.Sprintf("%d", models.Document_Type_Dir) {
this.jsonError("父文档不是目录!")
}
// check document name
document, err := models.DocumentModel.GetDocumentByNameParentIdAndSpaceId(name, parentId, spaceId, docType)
if err != nil {
this.ErrorLog("创建保存文档失败:" + err.Error())
this.jsonError("创建文档失败!")
}
if len(document) != 0 {
this.jsonError("该文档名称已经存在!")
}
insertDocument := map[string]interface{}{
"parent_id": parentId,
"space_id": spaceId,
"name": name,
"type": docType,
"path": parentDocument["path"] + "," + parentId,
"create_user_id": this.UserId,
"edit_user_id": this.UserId,
}
documentId, err := models.DocumentModel.Insert(insertDocument)
if err != nil {
this.ErrorLog("创建文档失败:" + err.Error())
this.jsonError("创建文档失败")
}
this.InfoLog("创建文档 " + utils.Convert.IntToString(documentId, 10) + " 成功")
this.jsonSuccess("创建文档成功", nil, "/document/index?document_id="+utils.Convert.IntToString(documentId, 10))
}
// document history
func (this *DocumentController) History() {
page, _ := this.GetInt("page", 1)
documentId := this.GetString("document_id", "0")
number, _ := this.GetRangeInt("number", 10, 10, 100)
limit := (page - 1) * number
if documentId == "0" {
this.ViewError("没有选择文档目录!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查看文档 " + documentId + " 修改历史失败:" + err.Error())
this.ViewError("查看文档修改历史失败!")
}
if len(document) == 0 {
this.jsonError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
isVisit, _, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限查看该空间修改历史!")
}
logDocuments, err := models.LogDocumentModel.GetLogDocumentsByDocumentIdAndLimit(documentId, limit, number)
if err != nil {
this.ErrorLog("查看文档 " + documentId + " 修改历史失败:" + err.Error())
this.ViewError("查看文档修改历史失败!")
}
count, err := models.LogDocumentModel.CountLogDocumentsByDocumentId(documentId)
if err != nil {
this.ErrorLog("查看文档 " + documentId + " 修改历史失败:" + err.Error())
this.ViewError("查看文档修改历史失败!")
}
userIds := []string{}
for _, logDocument := range logDocuments {
userIds = append(userIds, logDocument["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("查看文档 " + documentId + " 修改历史失败:" + err.Error())
this.ViewError("查看文档修改历史失败!")
}
for _, logDocument := range logDocuments {
logDocument["username"] = ""
for _, user := range users {
if logDocument["user_id"] == user["user_id"] {
logDocument["username"] = user["username"]
break
}
}
}
this.Data["logDocuments"] = logDocuments
this.SetPaginator(number, count)
this.viewLayout("document/history", "default")
}
// move document
func (this *DocumentController) Move() {
documentId := this.GetString("document_id", "0")
targetId := this.GetString("target_id", "0")
moveType := this.GetString("move_type", "") // 同层文件排序
if documentId == "0" {
this.jsonError("没有选择文档节点!")
}
if targetId == "0" {
this.jsonError("没有选择目标文档节点!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找移动文档失败:" + err.Error())
this.jsonError("移动文档失败!")
}
if len(document) == 0 {
this.jsonError("文档不存在!")
}
if moveType != "next" && moveType != "prev" {
if document["type"] == fmt.Sprintf("%d", models.Document_Type_Dir) {
this.jsonError("不能移动文档目录!")
}
}
targetDocument, err := models.DocumentModel.GetDocumentByDocumentId(targetId)
if err != nil {
this.ErrorLog("查找目标文档失败:" + err.Error())
this.jsonError("移动文档失败!")
}
if len(targetDocument) == 0 {
this.jsonError("目标文档不存在!")
}
if document["space_id"] != targetDocument["space_id"] {
this.jsonError("文档和目标文档不在同一空间!")
}
if moveType != "next" && moveType != "prev" {
if targetDocument["type"] != fmt.Sprintf("%d", models.Document_Type_Dir) {
this.jsonError("目标文档必须是目录!")
}
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("移动文档失败:" + err.Error())
this.jsonError("移动文档失败!")
}
if len(space) == 0 {
this.jsonError("文档空间不存在!")
}
// check space document privilege
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.jsonError("您没有权限移动该空间下的文档!")
}
// 排序逻辑:next-移动到目标文档之后 prev-移动到目标文档之前
if moveType == "next" || moveType == "prev" {
this.updateDocSequence(moveType, document, targetDocument)
return
}
_, oldPageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("移动文档 " + documentId + " 失败:" + err.Error())
this.jsonError("移动文档失败!")
}
newDocument := map[string]string{
"space_id": document["space_id"],
"parent_id": targetId,
"name": document["name"],
"type": document["type"],
"path": targetDocument["path"] + "," + targetId,
}
_, newPageFile, err := models.DocumentModel.GetParentDocumentsByDocument(newDocument)
if err != nil {
this.ErrorLog("移动文档 " + documentId + " 失败:" + err.Error())
this.jsonError("移动文档失败!")
}
// update database and move document file
updateValue := map[string]interface{}{
"parent_id": targetId,
"path": targetDocument["path"] + "," + targetId,
"edit_user_id": this.UserId,
}
_, err = models.DocumentModel.MoveDBAndFile(documentId, spaceId, updateValue,
oldPageFile, newPageFile, document["type"], "移动文档到 "+targetDocument["name"])
if err != nil {
this.ErrorLog("移动文档 " + documentId + " 失败:" + err.Error())
this.jsonError("移动文档失败!")
}
this.InfoLog("移动文档 " + documentId + " 成功")
this.jsonSuccess("移动文档成功", nil, "/document/index?document_id="+documentId)
}
// 移动文档排序
func (this *DocumentController) updateDocSequence(moveType string, document map[string]string, targetDocument map[string]string) {
sequence := utils.Convert.StringToInt(targetDocument["sequence"])
spaceId := targetDocument["space_id"]
targetDocumentId := targetDocument["document_id"]
movedDocumentId := document["document_id"]
updateSequence := sequence
if moveType == "next" {
updateSequence = sequence + 1
}
// 批量修改序号
_, err := models.DocumentModel.MoveSequenceBySpaceIdAndGtSequence(spaceId, updateSequence, 1)
if err != nil {
this.ErrorLog("移动文档 " + movedDocumentId + "到目标文档 " + targetDocumentId + " " + moveType + " 失败:" + err.Error())
this.jsonError("移动文档失败!")
}
// 修改当前文档的序号
updateValue := map[string]interface{}{
"sequence": updateSequence,
"edit_user_id": this.UserId,
}
_, err = models.DocumentModel.Update(movedDocumentId, updateValue, fmt.Sprintf("移动文档"), spaceId)
if err != nil {
this.ErrorLog("移动文档 " + movedDocumentId + "到目标文档 " + targetDocumentId + " " + moveType + " 失败:" + err.Error())
this.jsonError("移动文档失败!")
}
this.jsonSuccess("移动文档成功", "", "/document/index?document_id="+movedDocumentId)
}
// delete document
func (this *DocumentController) Delete() {
documentId := this.GetString("document_id", "0")
if documentId == "0" {
this.jsonError("没有选择文档!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("删除文档失败:" + err.Error())
this.jsonError("删除文档失败!")
}
if len(document) == 0 {
this.jsonError("文档不存在!")
}
if document["type"] == fmt.Sprintf("%d", models.Document_Type_Dir) {
childDocs, err := models.DocumentModel.GetDocumentsByParentId(document["document_id"])
if err != nil {
this.ErrorLog("删除文档失败:" + err.Error())
this.jsonError("删除文档失败!")
}
if len(childDocs) > 0 {
this.jsonError("请先删除或移动目录下所有文档!")
}
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(document["space_id"])
if err != nil {
this.ErrorLog("删除文档失败:" + err.Error())
this.jsonError("删除文档失败!")
}
if len(space) == 0 {
this.jsonError("文档空间不存在!")
}
// check space document privilege
_, _, isManager := this.GetDocumentPrivilege(space)
if !isManager {
this.jsonError("您没有权限删除该空间下的文档!")
}
_, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("删除文档 " + documentId + " 失败:" + err.Error())
this.jsonError("删除文档失败!")
}
err = models.DocumentModel.DeleteDBAndFile(documentId, spaceId, this.UserId, pageFile, document["type"])
if err != nil {
this.ErrorLog("删除文档 " + documentId + " 失败:" + err.Error())
this.jsonError("删除文档失败!")
}
// delete attachment
err = models.AttachmentModel.DeleteAttachmentsDBFileByDocumentId(documentId)
if err != nil {
this.ErrorLog("删除文档 " + documentId + " 附件失败:" + err.Error())
}
// 删除文档索引
go func(documentId string) {
services.DocIndexService.ForceDelDocIdIndex(documentId)
}(documentId)
this.InfoLog("删除文档 " + documentId + " 成功")
this.jsonSuccess("删除文档成功", "", "/document/index?document_id="+document["parent_id"])
}
+79
View File
@@ -0,0 +1,79 @@
package controllers
import (
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
)
type FollowController struct {
BaseController
}
func (this *FollowController) Add() {
redirect := this.Ctx.Request.Referer()
if !this.IsPost() {
this.ViewError("请求方式有误!", "/main/index")
}
objectId := this.GetString("object_id", "")
followType, _ := this.GetInt("type", 1)
if objectId == "" {
this.jsonError("没有选择关注对象!")
}
if followType != models.Follow_Type_Doc && followType != models.Follow_Type_User {
this.jsonError("关注类型错误!")
}
if followType == models.Follow_Type_User && objectId == this.UserId {
this.jsonError("不能关注自己!")
}
follow, err := models.FollowModel.GetFollowByUserIdAndTypeAndObjectId(this.UserId, followType, objectId)
if err != nil {
this.ErrorLog("添加关注失败:" + err.Error())
this.jsonError("添加关注失败!")
}
if len(follow) > 0 {
this.jsonError("您已关注过,不能重复关注!")
}
fId, err := models.FollowModel.Insert(this.UserId, followType, objectId)
if err != nil {
this.ErrorLog("添加关注失败:" + err.Error())
this.jsonError("添加关注失败!")
}
this.InfoLog("添加关注" + utils.Convert.IntToString(fId, 10) + " 成功")
this.jsonSuccess("关注成功!", nil, redirect)
}
func (this *FollowController) Cancel() {
redirect := this.Ctx.Request.Referer()
if !this.IsPost() {
this.ViewError("请求方式有误!", "/main/index")
}
followId := this.GetString("follow_id", "")
if followId == "" {
this.jsonError("没有选择关注对象!")
}
follow, err := models.FollowModel.GetFollowByFollowId(followId)
if err != nil {
this.ErrorLog("取消关注失败:" + err.Error())
this.jsonError("取消关注失败!")
}
if len(follow) == 0 {
this.jsonError("关注对象不存在!")
}
if follow["user_id"] != this.UserId {
this.jsonError("您只能取消自己的关注!")
}
err = models.FollowModel.Delete(followId)
if err != nil {
this.ErrorLog("取消关注 " + followId + " 失败:" + err.Error())
this.jsonError("取消关注用户失败!")
}
this.InfoLog("取消关注 " + followId + " 成功")
this.jsonSuccess("已取消关注!", nil, redirect)
}
+147
View File
@@ -0,0 +1,147 @@
package controllers
import (
"encoding/json"
"fmt"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"os"
"path"
)
type UploadResponse struct {
Success int `json:"success"`
Message string `json:"message"`
Url string `json:"url"`
}
type ImageController struct {
BaseController
}
func (this *ImageController) Upload() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
documentId := this.GetString("document_id", "")
if documentId == "" {
this.jsonError("参数错误!")
}
// handle document
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找空间文档 " + documentId + " 失败:" + err.Error())
this.jsonError("查找文档失败!")
}
if len(document) == 0 {
this.jsonError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.jsonError("查找文档失败!")
}
if len(space) == 0 {
this.jsonError("文档所在空间不存在!")
}
// check space visit_level
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.jsonError("您没有权限操作该空间下的文档!")
}
// handle upload
f, h, err := this.GetFile("editormd-image-file")
if err != nil {
this.ErrorLog("上传图片数据错误: " + err.Error())
this.jsonError("上传图片数据错误")
return
}
if h == nil || f == nil {
this.ErrorLog("上传图片错误")
this.jsonError("上传图片错误")
return
}
_ = f.Close()
// file save dir
saveDir := fmt.Sprintf("%s/%s/%s", app.ImageAbsDir, spaceId, documentId)
ok, _ := utils.File.PathIsExists(saveDir)
if !ok {
err := os.MkdirAll(saveDir, 0777)
if err != nil {
this.ErrorLog("上传图片错误: " + err.Error())
this.jsonError("上传图片失败")
return
}
}
// check file is exists
imageFile := path.Join(saveDir, h.Filename)
ok, _ = utils.File.PathIsExists(imageFile)
if ok {
this.jsonError("该图片已经上传过!")
}
// save file
err = this.SaveToFile("editormd-image-file", imageFile)
if err != nil {
this.ErrorLog("图片保存失败: " + err.Error())
this.jsonError("图片保存失败")
}
// insert db
attachment := map[string]interface{}{
"user_id": this.UserId,
"document_id": documentId,
"name": h.Filename,
"path": fmt.Sprintf("images/%s/%s/%s", spaceId, documentId, h.Filename),
"source": models.Attachment_Source_Image,
}
_, err = models.AttachmentModel.Insert(attachment, spaceId)
if err != nil {
_ = os.Remove(imageFile)
this.ErrorLog("上传图片保存信息错误: " + err.Error())
this.jsonError("图片信息保存失败")
}
this.InfoLog(fmt.Sprintf("文档 %s 上传图片 %s 成功", documentId, h.Filename))
this.jsonSuccess("上传成功", fmt.Sprintf("/%s", attachment["path"]))
}
func (this *ImageController) jsonError(message string) {
uploadRes := UploadResponse{
Success: 0,
Message: message,
Url: "",
}
j, err := json.Marshal(uploadRes)
if err != nil {
this.Abort(err.Error())
} else {
this.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
this.Abort(string(j))
}
}
func (this *ImageController) jsonSuccess(message string, url string) {
uploadRes := UploadResponse{
Success: 1,
Message: message,
Url: url,
}
j, err := json.Marshal(uploadRes)
if err != nil {
this.Abort(err.Error())
} else {
this.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
this.Abort(string(j))
}
}
+211
View File
@@ -0,0 +1,211 @@
package controllers
import (
"strings"
"github.com/phachon/mm-wiki/app/models"
)
type MainController struct {
BaseController
}
func (this *MainController) Index() {
collectDocs, err := models.CollectionModel.GetCollectionsByUserIdAndType(this.UserId, models.Collection_Type_Doc)
if err != nil {
this.ErrorLog("查找收藏文档错误: " + err.Error())
this.ViewError("查找收藏文档错误!")
}
docIds := []string{}
for _, collectDoc := range collectDocs {
docIds = append(docIds, collectDoc["resource_id"])
}
documents, err := models.DocumentModel.GetDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("查找收藏文档错误: " + err.Error())
this.ViewError("查找收藏文档错误!")
}
this.Data["documents"] = documents
this.Data["count"] = len(documents)
this.viewLayout("main/index", "main")
}
func (this *MainController) Default() {
page, _ := this.GetInt("page", 1)
number, _ := this.GetInt("number", 10)
maxPage := 10
if page >= maxPage {
page = maxPage
}
//number := 8
limit := (page - 1) * number
userId := this.UserId
logDocuments, err := models.LogDocumentModel.GetLogDocumentsByLimit(userId, limit, number)
if err != nil {
this.ErrorLog("查找更新文档列表失败:" + err.Error())
this.ViewError("查找更新文档列表失败!")
}
count, err := models.LogDocumentModel.CountLogDocuments()
if err != nil {
this.ErrorLog("查找更新文档总数失败:" + err.Error())
this.ViewError("查找更新文档列表失败!")
}
if count >= int64(maxPage*number) {
count = int64(maxPage * number)
}
userIds := []string{}
docIds := []string{}
for _, logDocument := range logDocuments {
userIds = append(userIds, logDocument["user_id"])
docIds = append(docIds, logDocument["document_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("查找更新文档用户失败:" + err.Error())
this.ViewError("查找更新文档列表失败!")
}
docs, err := models.DocumentModel.GetAllDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("查找文档信息失败:" + err.Error())
this.ViewError("查找更新文档列表失败!")
}
for _, logDocument := range logDocuments {
logDocument["username"] = ""
for _, user := range users {
if logDocument["user_id"] == user["user_id"] {
logDocument["username"] = user["username"]
logDocument["given_name"] = user["given_name"]
break
}
}
for _, doc := range docs {
if logDocument["document_id"] == doc["document_id"] {
logDocument["document_name"] = doc["name"]
logDocument["document_type"] = doc["type"]
break
}
}
}
// link
links, err := models.LinkModel.GetLinksOrderBySequence()
if err != nil {
this.ErrorLog("查找快捷链接失败:" + err.Error())
this.ViewError("查找快捷链接失败!")
}
// contacts
contacts, err := models.ContactModel.GetAllContact()
if err != nil {
this.ErrorLog("查找快捷链接失败:" + err.Error())
this.ViewError("查找快捷链接失败!")
}
// main title config
mainTitle := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyMainTitle, "")
mainDescription := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyMainDescription, "")
this.Data["panel_title"] = mainTitle
this.Data["panel_description"] = mainDescription
this.Data["logDocuments"] = logDocuments
this.Data["links"] = links
this.Data["contacts"] = contacts
this.SetPaginator(number, count)
this.viewLayout("main/default", "default")
}
func (this *MainController) About() {
this.viewLayout("main/about", "default")
}
// 搜索,支持根据标题和内容搜索
func (this *MainController) Search() {
keyword := strings.TrimSpace(this.GetString("keyword", ""))
searchType := this.GetString("search_type", "content")
this.Data["search_type"] = searchType
this.Data["keyword"] = keyword
this.Data["count"] = 0
if keyword == "" {
this.viewLayout("main/search", "default")
return
}
var documents = []map[string]string{}
var err error
// 获取该用户有权限的空间
publicSpaces, err := models.SpaceModel.GetSpacesByVisitLevel(models.Space_VisitLevel_Public)
if err != nil {
this.ErrorLog("搜索文档列表获取用户空间权限出错:" + err.Error())
this.ViewError("搜索文档错误!")
}
spaceUsers, err := models.SpaceUserModel.GetSpaceUsersByUserId(this.UserId)
if err != nil {
this.ErrorLog("搜索文档列表获取用户空间权限出错:" + err.Error())
this.ViewError("搜索文档错误!")
}
spaceIdsMap := make(map[string]bool)
for _, publicSpace := range publicSpaces {
spaceIdsMap[publicSpace["space_id"]] = true
}
for _, spaceUser := range spaceUsers {
if _, ok := spaceIdsMap[spaceUser["space_id"]]; !ok {
spaceIdsMap[spaceUser["space_id"]] = true
}
}
searchDocContents := make(map[string]string)
// 默认根据内容搜索
// v0.2.1 下线全文搜索功能
searchType = "title"
//if searchType == "title" {
// documents, err = models.DocumentModel.GetDocumentsByLikeName(keyword)
//} else {
// searchRes := global.DocSearcher.SearchDoc(types.SearchReq{Text: keyword})
// searchDocIds := []string{}
// for _, searchDoc := range searchRes.Docs {
// if len(searchDoc.TokenSnippetLocs) == 0 {
// continue
// }
// docId := searchDoc.DocId
// content := searchDoc.Content
// locIndex := searchDoc.TokenSnippetLocs[0]
// searchContent := utils.Misc.SubStrUnicodeBySubStrIndex(content, keyword, locIndex, 30, 30)
// searchDocContents[docId] = searchContent
// searchDocIds = append(searchDocIds, docId)
// }
// documents, err = models.DocumentModel.GetDocumentsByDocumentIds(searchDocIds)
//}
documents, err = models.DocumentModel.GetDocumentsByLikeName(keyword)
if err != nil {
this.ErrorLog("搜索文档出错:" + err.Error())
this.ViewError("搜索文档错误!")
}
// 过滤一下没权限的空间
realDocuments := []map[string]string{}
for _, document := range documents {
spaceId, _ := document["space_id"]
documentId, _ := document["document_id"]
if _, ok := spaceIdsMap[spaceId]; !ok {
continue
}
if searchType != "title" {
searchContent, ok := searchDocContents[documentId]
if !ok || searchContent == "" {
continue
}
document["search_content"] = searchContent
}
realDocuments = append(realDocuments, document)
}
this.Data["search_type"] = searchType
this.Data["keyword"] = keyword
this.Data["documents"] = realDocuments
this.Data["count"] = len(realDocuments)
this.viewLayout("main/search", "default")
}
+531
View File
@@ -0,0 +1,531 @@
package controllers
import (
"errors"
"fmt"
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/services"
"github.com/phachon/mm-wiki/app/utils"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/astaxie/beego/logs"
)
type PageController struct {
BaseController
}
// document page view
func (this *PageController) View() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("文档未找到!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
isVisit, isEditor, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问该空间!")
}
// get parent documents by document
parentDocuments, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("查找父文档失败:" + err.Error())
this.ViewError("查找父文档失败!")
}
if len(parentDocuments) == 0 {
this.ViewError("父文档不存在!")
}
// get document content
documentContent, err := utils.Document.GetContentByPageFile(pageFile)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("文档不存在!")
}
// get edit user and create user
users, err := models.UserModel.GetUsersByUserIds([]string{document["create_user_id"], document["edit_user_id"]})
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(users) == 0 {
this.ViewError("文档创建用户不存在!")
}
var createUser = map[string]string{}
var editUser = map[string]string{}
for _, user := range users {
if user["user_id"] == document["create_user_id"] {
createUser = user
}
if user["user_id"] == document["edit_user_id"] {
editUser = user
}
}
collectionId := "0"
collection, err := models.CollectionModel.GetCollectionByUserIdTypeAndResourceId(this.UserId, models.Collection_Type_Doc, documentId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("文档查找失败!")
}
if len(collection) > 0 {
collectionId = collection["collection_id"]
}
this.Data["is_editor"] = isEditor
this.Data["space"] = space
this.Data["create_user"] = createUser
this.Data["edit_user"] = editUser
this.Data["document"] = document
this.Data["collection_id"] = collectionId
this.Data["page_content"] = documentContent
this.Data["parent_documents"] = parentDocuments
this.viewLayout("page/view", "document_page")
}
// page edit
func (this *PageController) Edit() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("文档未找到!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("修改文档 " + documentId + " 失败:" + err.Error())
this.ViewError("修改文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("修改文档 " + documentId + " 失败:" + err.Error())
this.ViewError("修改文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space visit_level
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.ViewError("您没有权限修改该空间下文档!")
}
// get parent documents by document
_, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("查找父文档失败:" + err.Error())
this.ViewError("查找父文档失败!")
}
// get document content
documentContent, err := utils.Document.GetContentByPageFile(pageFile)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("文档不存在!")
}
autoFollowDoc := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyAutoFollowdoc, "0")
sendEmail := models.ConfigModel.GetConfigValueByKey(models.ConfigKeySendEmail, "0")
this.Data["sendEmail"] = sendEmail
this.Data["autoFollowDoc"] = autoFollowDoc
this.Data["page_content"] = documentContent
this.Data["document"] = document
this.viewLayout("page/edit", "document_page")
}
// page modify
func (this *PageController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
documentId := this.GetString("document_id", "")
newName := strings.TrimSpace(this.GetString("name", ""))
documentContent := this.GetString("document_page_editor-markdown-doc", "")
comment := strings.TrimSpace(this.GetString("comment", ""))
isNoticeUser := strings.TrimSpace(this.GetString("is_notice_user", "0"))
isFollowDoc := strings.TrimSpace(this.GetString("is_follow_doc", "0"))
// rm document_page_editor-markdown-doc
this.Ctx.Request.PostForm.Del("document_page_editor-markdown-doc")
if documentId == "" {
this.jsonError("您没有选择文档!")
}
if newName == "" {
this.jsonError("文档名称不能为空!")
}
match, err := regexp.MatchString(`[\\\\/:*?\"<>、|]`, newName)
if err != nil {
this.jsonError("文档名称格式不正确!")
}
if match {
this.jsonError("文档名称格式不正确!")
}
if newName == utils.Document_Default_FileName {
this.jsonError("文档名称不能为 " + utils.Document_Default_FileName + " ")
}
//if comment == "" {
// this.jsonError("必须输入此次修改的备注!")
//}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("修改文档 " + documentId + " 失败:" + err.Error())
this.jsonError("保存文档失败!")
}
if len(document) == 0 {
this.jsonError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("修改文档 " + documentId + " 失败:" + err.Error())
this.jsonError("保存文档失败!")
}
if len(space) == 0 {
this.jsonError("文档所在空间不存在!")
}
// check space document privilege
_, isEditor, _ := this.GetDocumentPrivilege(space)
if !isEditor {
this.jsonError("您没有权限修改该空间下文档!")
}
// not allow update space document home page name
if document["parent_id"] == "0" {
newName = document["name"]
}
// check document name
if newName != document["name"] {
newDocument, err := models.DocumentModel.GetDocumentByNameParentIdAndSpaceId(newName,
document["parent_id"], document["space_id"], utils.Convert.StringToInt(document["type"]))
if err != nil {
this.ErrorLog("修改文档失败:" + err.Error())
this.jsonError("保存文档失败!")
}
if len(newDocument) != 0 {
this.jsonError("该文档名称已经存在!")
}
}
// update document and file content
updateValue := map[string]interface{}{
"name": newName,
"edit_user_id": this.UserId,
}
_, err = models.DocumentModel.UpdateDBAndFile(documentId, spaceId, document, documentContent, updateValue, comment)
if err != nil {
this.ErrorLog("修改文档 " + documentId + " 失败:" + err.Error())
this.jsonError("修改文档失败!")
}
// send email to follow user
if isNoticeUser == "1" {
logInfo := this.GetLogInfoByCtx()
url := fmt.Sprintf("%s:%d/document/index?document_id=%s", this.Ctx.Input.Site(), this.Ctx.Input.Port(), documentId)
go func(documentId string, username string, comment string, url string) {
err := sendEmail(documentId, username, comment, url)
if err != nil {
logInfo["message"] = "更新文档时发送邮件通知失败:" + err.Error()
logInfo["level"] = models.Log_Level_Error
models.LogModel.Insert(logInfo)
logs.Error("更新文档时发送邮件通知失败:" + err.Error())
}
}(documentId, this.User["username"], comment, url)
}
// follow doc
if isFollowDoc == "1" {
go func(userId string, documentId string) {
_, _ = models.FollowModel.FollowDocument(userId, documentId)
}(this.UserId, documentId)
}
// 更新文档索引
go func(documentId string) {
_ = services.DocIndexService.ForceUpdateDocIndexByDocId(documentId)
}(documentId)
this.InfoLog("修改文档 " + documentId + " 成功")
this.jsonSuccess("文档修改成功!", nil, "/document/index?document_id="+documentId)
}
// document share display
func (this *PageController) Display() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("文档未找到!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
// get document space
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("分享文档 " + documentId + " 失败:" + err.Error())
this.ViewError("保存文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space is allow display
if space["is_share"] != fmt.Sprintf("%d", models.Space_Share_True) {
this.ViewError("该文档不能被分享!")
}
// get parent documents by document
parentDocuments, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("查找父文档失败:" + err.Error())
this.ViewError("查找父文档失败!")
}
if len(parentDocuments) == 0 {
this.ViewError("父文档不存在!")
}
// get document content
documentContent, err := utils.Document.GetContentByPageFile(pageFile)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 内容失败:" + err.Error())
this.ViewError("文档不存在!")
}
// get edit user and create user
users, err := models.UserModel.GetUsersByUserIds([]string{document["create_user_id"], document["edit_user_id"]})
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(users) == 0 {
this.ViewError("文档创建用户不存在!")
}
var createUser = map[string]string{}
var editUser = map[string]string{}
for _, user := range users {
if user["user_id"] == document["create_user_id"] {
createUser = user
}
if user["user_id"] == document["edit_user_id"] {
editUser = user
}
}
this.Data["create_user"] = createUser
this.Data["edit_user"] = editUser
this.Data["document"] = document
this.Data["page_content"] = documentContent
this.Data["parent_documents"] = parentDocuments
this.viewLayout("page/display", "document_share")
}
// export file
func (this *PageController) Export() {
documentId := this.GetString("document_id", "")
if documentId == "" {
this.ViewError("文档未找到!")
}
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(document) == 0 {
this.ViewError("文档不存在!")
}
spaceId := document["space_id"]
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找文档 " + documentId + " 所在空间失败:" + err.Error())
this.ViewError("查找文档失败!")
}
if len(space) == 0 {
this.ViewError("文档所在空间不存在!")
}
// check space document privilege
isVisit, _, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限导出该空间下文档!")
}
// check space is allow export
if space["is_export"] != fmt.Sprintf("%d", models.Space_Download_True) {
this.ViewError("该文档不允许被导出!")
}
// get parent documents by document
parentDocuments, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
this.ErrorLog("查找父文档失败:" + err.Error())
this.ViewError("查找父文档失败!")
}
if len(parentDocuments) == 0 {
this.ViewError("父文档不存在!")
}
packFiles := []*utils.CompressFileInfo{}
absPageFile := utils.Document.GetAbsPageFileByPageFile(pageFile)
// pack document file
packFiles = append(packFiles, &utils.CompressFileInfo{
File: absPageFile,
PrefixPath: "",
})
// get document attachments
attachments, err := models.AttachmentModel.GetAttachmentsByDocumentId(documentId)
if err != nil {
this.ErrorLog("查找文档附件失败:" + err.Error())
this.ViewError("查找文档附件失败!")
}
for _, attachment := range attachments {
if attachment["path"] == "" {
continue
}
path := attachment["path"]
attachmentFile := filepath.Join(app.DocumentAbsDir, path)
packFile := &utils.CompressFileInfo{
File: attachmentFile,
PrefixPath: filepath.Dir(path),
}
packFiles = append(packFiles, packFile)
}
var dest = fmt.Sprintf("%s/mm_wiki/%s.zip", os.TempDir(), document["name"])
err = utils.Zipx.PackFile(packFiles, dest)
if err != nil {
this.ErrorLog("导出文档附件失败:" + err.Error())
this.ViewError("导出文档失败!")
}
this.Ctx.Output.Download(dest, document["name"]+".zip")
}
func sendEmail(documentId string, username string, comment string, url string) error {
// get document by documentId
document, err := models.DocumentModel.GetDocumentByDocumentId(documentId)
if err != nil {
return errors.New("发送邮件通知查找文档失败:" + err.Error())
}
// get send email open config
sendEmailConfig := models.ConfigModel.GetConfigValueByKey(models.ConfigKeySendEmail, "0")
if sendEmailConfig == "0" {
return nil
}
// get email config
emailConfig, err := models.EmailModel.GetUsedEmail()
if err != nil {
return errors.New("发送邮件通知查找邮件服务器配置失败:" + err.Error())
}
if len(emailConfig) == 0 {
return nil
}
// get follow doc user
follows, err := models.FollowModel.GetFollowsByObjectIdAndType(documentId, models.Follow_Type_Doc)
if err != nil {
return errors.New("发送邮件查找关注文档用户失败:" + err.Error())
}
if len(follows) == 0 {
return nil
}
userIds := []string{}
for _, follow := range follows {
userIds = append(userIds, follow["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
return errors.New("发送邮件查找关注文档用户失败:" + err.Error())
}
if len(users) == 0 {
return nil
}
emails := []string{}
for _, user := range users {
if user["email"] != "" {
emails = append(emails, user["email"])
}
}
// get parent documents by document
parentDocuments, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
return errors.New("查找文档内容失败: " + err.Error())
}
if len(parentDocuments) == 0 {
return errors.New("查找文档内容失败")
}
// get document content
documentContent, err := utils.Document.GetContentByPageFile(pageFile)
if err != nil {
return errors.New("查找文档内容失败: " + err.Error())
}
if len([]byte(documentContent)) > 500 {
documentContent = string([]byte(documentContent)[:500])
}
documentValue := document
documentValue["content"] = documentContent
documentValue["username"] = username
documentValue["comment"] = comment
documentValue["url"] = url
emailTemplate := beego.BConfig.WebConfig.ViewsPath + "/system/email/template.html"
body, err := utils.Email.MakeDocumentHtmlBody(documentValue, emailTemplate)
if err != nil {
return errors.New("发送邮件生成模板失败:" + err.Error())
}
// start send email
return utils.Email.Send(emailConfig, emails, "文档更新通知", body)
}
+401
View File
@@ -0,0 +1,401 @@
package controllers
import (
"strings"
"time"
"github.com/phachon/mm-wiki/app/models"
)
type SpaceController struct {
BaseController
}
func (this *SpaceController) Index() {
// get space tags
spaceTags := map[string]string{}
spaces, err := models.SpaceModel.GetSpaces()
if err == nil {
for _, space := range spaces {
tags := space["tags"]
if tags == "" {
continue
}
tagList := strings.Split(tags, ",")
for _, tagName := range tagList {
spaceTags[tagName] = tagName
}
}
}
this.Data["spaceTags"] = spaceTags
this.viewLayout("space/index", "space")
}
func (this *SpaceController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var spaces []map[string]string
if keyword != "" {
count, err = models.SpaceModel.CountSpacesByKeyword(keyword)
spaces, err = models.SpaceModel.GetSpacesByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.SpaceModel.CountSpaces()
spaces, err = models.SpaceModel.GetSpacesByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取全部空间列表失败: " + err.Error())
this.ViewError("获取空间列表失败", "/main/index")
}
collectionSpaces, err := models.CollectionModel.GetCollectionsByUserIdAndType(this.UserId, models.Collection_Type_Space)
if err != nil {
this.ErrorLog("获取全部空间列表失败: " + err.Error())
this.ViewError("获取全部空间列表失败", "/main/index")
}
for _, space := range spaces {
space["collection"] = "0"
space["collection_id"] = "0"
for _, collectionSpace := range collectionSpaces {
if collectionSpace["resource_id"] == space["space_id"] {
space["collection"] = "1"
space["collection_id"] = collectionSpace["collection_id"]
break
}
}
}
this.Data["spaces"] = spaces
this.Data["keyword"] = keyword
this.Data["count"] = count
this.SetPaginator(number, count)
this.viewLayout("space/list", "default")
}
func (this *SpaceController) Member() {
page, _ := this.GetInt("page", 1)
spaceId := strings.TrimSpace(this.GetString("space_id", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
if spaceId == "" {
this.ViewError("没有选择空间!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找空间 " + spaceId + " 失败:" + err.Error())
this.ViewError("空间不存在!")
}
if len(space) == 0 {
this.ViewError("空间不存在!")
}
limit := (page - 1) * number
count, err := models.SpaceUserModel.CountSpaceUsersBySpaceId(spaceId)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/space/index")
}
spaceUsers, err := models.SpaceUserModel.GetSpaceUsersBySpaceIdAndLimit(spaceId, limit, number)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/space/index")
}
var userIds = []string{}
for _, spaceUser := range spaceUsers {
userIds = append(userIds, spaceUser["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/space/index")
}
for _, user := range users {
for _, spaceUser := range spaceUsers {
if spaceUser["user_id"] == user["user_id"] {
user["space_privilege"] = spaceUser["privilege"]
user["space_user_id"] = spaceUser["space_user_id"]
}
}
}
this.Data["users"] = users
this.Data["space_id"] = spaceId
this.SetPaginator(number, count)
// check user space privilege
_, _, isManager := this.GetDocumentPrivilege(space)
if isManager {
var otherUsers = []map[string]string{}
if len(userIds) > 0 {
otherUsers, err = models.UserModel.GetUserByNotUserIds(userIds)
} else {
otherUsers, err = models.UserModel.GetUsers()
}
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/space/index")
}
this.Data["otherUsers"] = otherUsers
this.viewLayout("space/manager_member", "default")
} else {
this.viewLayout("space/member", "default")
}
}
func (this *SpaceController) AddMember() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
spaceId := strings.TrimSpace(this.GetString("space_id", ""))
userId := this.GetString("user_id", "")
privilege := strings.TrimSpace(this.GetString("privilege", "0"))
if spaceId == "" {
this.jsonError("空间不存在!")
}
if userId == "" {
this.jsonError("没有选择用户!")
}
if privilege == "" {
this.jsonError("没有选择用户空间权限!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("添加空间 " + spaceId + " 成员失败: " + err.Error())
this.jsonError("添加空间成员失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
// check login user space member privilege
_, _, isManager := this.GetDocumentPrivilege(space)
if !isManager {
this.jsonError("您没有权限添加该空间成员!", "/space/index")
}
spaceUser, err := models.SpaceUserModel.GetSpaceUserBySpaceIdAndUserId(spaceId, userId)
if err != nil {
this.ErrorLog("添加空间 " + spaceId + " 成员 " + userId + " 失败: " + err.Error())
this.jsonError("添加空间成员失败!")
}
if len(spaceUser) > 0 {
this.jsonError("该用户已经是空间成员!")
}
insertValue := map[string]interface{}{
"user_id": userId,
"space_id": spaceId,
"privilege": privilege,
"create_time": time.Now().Unix(),
"update_time": time.Now().Unix(),
}
_, err = models.SpaceUserModel.Insert(insertValue)
if err != nil {
this.ErrorLog("添加空间 " + spaceId + " 成员 " + userId + " 失败: " + err.Error())
this.jsonError("添加成员失败!")
}
this.InfoLog("空间 " + spaceId + " 添加成员 " + userId + " 成功")
this.jsonSuccess("添加成员成功!", nil, "/space/member?space_id="+spaceId)
}
func (this *SpaceController) RemoveMember() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/index")
}
spaceId := this.GetString("space_id", "")
userId := this.GetString("user_id", "")
spaceUserId := this.GetString("space_user_id", "")
if spaceUserId == "" {
this.jsonError("空间成员不存在!")
}
if spaceId == "" {
this.jsonError("空间不存在!")
}
if userId == "" {
this.jsonError("用户不存在!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("移除空间 " + spaceId + " 成员失败: " + err.Error())
this.jsonError("移除空间成员失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
// check login user space member privilege
_, _, isManager := this.GetDocumentPrivilege(space)
if !isManager {
this.ViewError("您没有权限移除该空间成员!", "/space/index")
}
err = models.SpaceUserModel.Delete(spaceUserId)
if err != nil {
this.ErrorLog("移除空间 " + spaceId + " 下成员 " + userId + " 失败:" + err.Error())
this.jsonError("移除成员失败!")
}
this.InfoLog("移除空间 " + spaceId + " 下成员 " + userId + " 成功")
this.jsonSuccess("移除成员成功!", nil, "/space/member?space_id="+spaceId)
}
func (this *SpaceController) ModifyMember() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/space/list")
}
spaceUserId := this.GetString("space_user_id", "")
privilege := this.GetString("privilege", "0")
userId := this.GetString("user_id", "")
spaceId := this.GetString("space_id", "")
if spaceUserId == "" {
this.jsonError("更新权限错误!")
}
if privilege == "" {
this.jsonError("没有选择权限!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("更新空间 " + spaceId + " 成员权限失败: " + err.Error())
this.jsonError("更新空间成员权限失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
// check login user space member privilege
_, _, isManager := this.GetDocumentPrivilege(space)
if !isManager {
this.ViewError("您没有权限修改该空间成员!", "/space/index")
}
_, err = models.SpaceUserModel.Update(spaceUserId, map[string]interface{}{
"privilege": privilege,
"update_time": time.Now().Unix(),
})
if err != nil {
this.ErrorLog("更新空间 " + spaceId + " 下成员 " + userId + " 权限失败:" + err.Error())
this.jsonError("更新权限失败!")
}
this.InfoLog("更新空间 " + spaceId + " 下成员 " + userId + " 权限成功")
this.jsonSuccess("更新权限成功!", nil)
}
func (this *SpaceController) Collection() {
collectionSpaces, err := models.CollectionModel.GetCollectionsByUserIdAndType(this.UserId, models.Collection_Type_Space)
if err != nil {
this.ErrorLog("获取收藏空间列表失败: " + err.Error())
this.ViewError("获取收藏空间列表失败", "/space/list")
}
spaceIds := []string{}
for _, collectionSpace := range collectionSpaces {
spaceIds = append(spaceIds, collectionSpace["resource_id"])
}
spaces, err := models.SpaceModel.GetSpaceBySpaceIds(spaceIds)
if err != nil {
this.ErrorLog("获取收藏空间列表失败: " + err.Error())
this.ViewError("获取收藏空间列表失败", "/space/list")
}
for _, space := range spaces {
space["collection_id"] = "0"
for _, collectionSpace := range collectionSpaces {
if collectionSpace["resource_id"] == space["space_id"] {
space["collection_id"] = collectionSpace["collection_id"]
break
}
}
}
this.Data["spaces"] = spaces
this.Data["count"] = len(spaces)
this.viewLayout("space/collection", "default")
}
func (this *SpaceController) Document() {
spaceId := this.GetString("space_id", "")
if spaceId == "" {
this.ViewError("空间不存在")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找空间 " + spaceId + " 失败:" + err.Error())
this.ViewError("空间不存在!")
}
if len(space) == 0 {
this.ViewError("空间不存在!")
}
// check space visit_level
isVisit, _, _ := this.GetDocumentPrivilege(space)
if !isVisit {
this.ViewError("您没有权限访问该空间!")
}
spaceDocument, err := models.DocumentModel.GetSpaceDefaultDocument(spaceId)
if err != nil {
this.ErrorLog("查找空间 " + spaceId + " 失败:" + err.Error())
this.ViewError("查找空间页面失败!")
}
if len(spaceDocument) == 0 {
this.ViewError("空间首页不存在!")
}
documentId := spaceDocument["document_id"]
this.Redirect("/document/index?document_id="+documentId, 302)
}
func (this *SpaceController) Search() {
tagName := strings.TrimSpace(this.GetString("tag", ""))
spaces, err := models.SpaceModel.GetSpacesByTags(tagName)
if err != nil {
this.ErrorLog("搜索空间标签列表失败: " + err.Error())
this.ViewError("获取空间列表失败", "/main/index")
}
collectionSpaces, err := models.CollectionModel.GetCollectionsByUserIdAndType(this.UserId, models.Collection_Type_Space)
if err != nil {
this.ErrorLog("获取全部空间列表失败: " + err.Error())
this.ViewError("获取全部空间列表失败", "/main/index")
}
for _, space := range spaces {
space["collection"] = "0"
space["collection_id"] = "0"
for _, collectionSpace := range collectionSpaces {
if collectionSpace["resource_id"] == space["space_id"] {
space["collection"] = "1"
space["collection_id"] = collectionSpace["collection_id"]
break
}
}
}
this.Data["tag"] = tagName
this.Data["spaces"] = spaces
this.Data["count"] = len(spaces)
this.viewLayout("space/search", "default")
}
+379
View File
@@ -0,0 +1,379 @@
package controllers
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/astaxie/beego"
)
type TemplateController struct {
beego.Controller
UserId string
User map[string]string
controllerName string
actionName string
}
type JsonResponse struct {
Code int `json:"code"`
Message interface{} `json:"message"`
Data interface{} `json:"data"`
Redirect map[string]interface{} `json:"redirect"`
}
// prepare
func (this *TemplateController) Prepare() {
controllerName, action := this.GetControllerAndAction()
this.controllerName = strings.ToLower(controllerName[0 : len(controllerName)-10])
this.actionName = strings.ToLower(action)
this.Data["navName"] = this.controllerName
this.Data["version"] = app.Version
this.Data["copyright"] = app.CopyRight
if this.controllerName == "author" {
return
}
if !this.isLogin() {
if this.IsAjax() {
this.JsonError("未登录或登录已失效!", nil, "/author/index")
} else {
this.Redirect("/author/index", 302)
}
this.StopRun()
}
if !this.checkAccess() {
if this.IsPost() {
this.JsonError("抱歉,您没有权限操作!", nil, "/system/main/index")
} else {
this.ViewError("您没有权限访问该页面!", "/system/main/index")
}
this.StopRun()
}
}
// check is login
func (this *TemplateController) isLogin() bool {
if this.controllerName == "page" && this.actionName == "display" {
return true
}
passport := beego.AppConfig.String("author::passport")
cookie := this.Ctx.GetCookie(passport)
// cookie is empty
if cookie == "" {
return false
}
user := this.GetSession("author")
// session is empty
if user == nil {
return false
}
cookieValue, _ := utils.Encrypt.Base64Decode(cookie)
identifyList := strings.Split(cookieValue, "@")
if cookieValue == "" || len(identifyList) != 2 {
return false
}
username := identifyList[0]
identify := identifyList[1]
userValue := user.(map[string]string)
// cookie session name
if username != userValue["username"] {
return false
}
// UAG and IP
if identify != utils.Encrypt.Md5Encode(this.Ctx.Request.UserAgent()+this.GetClientIp()+userValue["password"]) {
return false
}
// flush session
newUser, err := models.UserModel.GetUserByUserId(userValue["user_id"])
if err != nil {
this.ErrorLog("登录成功 flush session 失败:" + err.Error())
return false
}
// flush session
this.SetSession("author", newUser)
this.User = this.GetSession("author").(map[string]string)
this.UserId = this.User["user_id"]
// 查找系统名称
systemName := models.ConfigModel.GetConfigValueByKey(models.ConfigKeySystemName, "Markdown Mini Wiki")
this.Data["system_name"] = systemName
this.Data["login_user_id"] = this.UserId
this.Data["login_username"] = this.User["username"]
this.Data["login_role_id"] = this.User["role_id"]
// success
return true
}
// check access
func (this *TemplateController) checkAccess() bool {
path := this.Ctx.Request.URL.Path
mca := strings.Split(strings.Trim(path, "/"), "/")
// must /system/controller/action
if (len(mca) >= 3) && (strings.ToLower(mca[0]) == "system") {
this.Data["navName"] = "system"
// no check '/system/main/index' '/system/main/default'
if (this.controllerName == "main" && this.actionName == "index") || this.controllerName == "main" && this.actionName == "default" {
return true
}
if this.IsRoot() {
return true
}
_, controllers, err := models.PrivilegeModel.GetTypePrivilegesByUserId(this.UserId)
if err != nil {
this.ErrorLog("获取用户 " + this.UserId + " 权限失败:" + err.Error())
return false
}
for _, controller := range controllers {
action := strings.ToLower(controller["action"])
controller := strings.ToLower(controller["controller"])
if this.controllerName == controller && this.actionName == action {
return true
}
}
return false
}
return true
}
// view layout
func (this *TemplateController) ViewLayout(viewName, layout string) {
this.Layout = layout + ".html"
this.TplName = viewName + ".html"
this.Data["title"] = "MM-Wiki"
this.Data["copyright"] = app.CopyRight
this.Render()
}
// view layout
func (this *TemplateController) ViewError(content string, redirect ...string) {
this.Layout = "error/default.html"
this.TplName = "layouts/default.html"
var url = ""
var sleep = "5"
if len(redirect) == 1 {
url = redirect[0]
}
if len(redirect) > 1 {
sleep = redirect[1]
}
if content == "" {
content = "操作失败"
}
this.Data["content"] = content
this.Data["url"] = url
this.Data["sleep"] = sleep
this.Data["copyright"] = app.CopyRight
this.Render()
}
// return json success
func (this *TemplateController) JsonSuccess(message interface{}, data ...interface{}) {
url := ""
sleep := 2000
var _data interface{}
if len(data) > 0 {
_data = data[0]
}
if len(data) > 1 {
url = data[1].(string)
}
if len(data) > 2 {
sleep = data[2].(int)
}
this.Data["json"] = JsonResponse{
Code: 1,
Message: message,
Data: _data,
Redirect: map[string]interface{}{
"url": url,
"sleep": sleep,
},
}
j, err := json.MarshalIndent(this.Data["json"], "", "\t")
if err != nil {
this.Abort(err.Error())
} else {
this.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
this.Abort(string(j))
}
}
// return json error
func (this *TemplateController) JsonError(message interface{}, data ...interface{}) {
url := ""
sleep := 2000
var _data interface{}
if len(data) > 0 {
_data = data[0]
}
if len(data) > 1 {
url = data[1].(string)
}
if len(data) > 2 {
sleep = data[2].(int)
}
this.Data["json"] = JsonResponse{
Code: 0,
Message: message,
Data: _data,
Redirect: map[string]interface{}{
"url": url,
"sleep": sleep,
},
}
j, err := json.MarshalIndent(this.Data["json"], "", " \t")
if err != nil {
this.Abort(err.Error())
} else {
this.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
this.Abort(string(j))
}
}
// get client ip
func (this *TemplateController) GetClientIp() string {
s := strings.Split(this.Ctx.Request.RemoteAddr, ":")
return s[0]
}
// paginator
func (this *TemplateController) SetPaginator(per int, nums int64) *utils.Paginator {
p := utils.NewPaginator(this.Ctx.Request, per, nums)
this.Data["paginator"] = p
return p
}
// is Post
func (this *TemplateController) IsPost() bool {
return this.Ctx.Input.Method() == "POST"
}
// is Get
func (this *TemplateController) IsGet() bool {
return this.Ctx.Input.Method() == "GET"
}
// 是否是超级管理员
func (this *TemplateController) IsRoot() bool {
return this.User["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id)
}
func (this *TemplateController) GetRangeInt(key string, def int, min int, max int) (n int, err error) {
n, err = this.GetInt(key, def)
if err != nil {
return
}
if n < min {
n = min
}
if n > max {
n = max
}
return n, nil
}
func (this *TemplateController) GetDocumentPrivilege(space map[string]string) (isVisit, isEditor, isManager bool) {
if this.IsRoot() {
return true, true, true
}
spaceUser, _ := models.SpaceUserModel.GetSpaceUserBySpaceIdAndUserId(space["space_id"], this.UserId)
if len(spaceUser) == 0 {
if space["visit_level"] == models.Space_VisitLevel_Private {
return false, false, false
} else {
return true, false, false
}
}
if spaceUser["privilege"] == fmt.Sprintf("%d", models.SpaceUser_Privilege_Editor) {
return true, true, false
}
if spaceUser["privilege"] == fmt.Sprintf("%d", models.SpaceUser_Privilege_Manager) {
return true, true, true
}
return true, false, false
}
// insert action log
func (this *TemplateController) RecordLog(message string, level int) {
userAgent := this.Ctx.Request.UserAgent()
referer := this.Ctx.Request.Referer()
getParams := this.Ctx.Request.URL.String()
path := this.Ctx.Request.URL.Path
this.Ctx.Request.ParseForm()
postParamsMap := map[string][]string(this.Ctx.Request.PostForm)
postParams, _ := json.Marshal(postParamsMap)
user := this.GetSession("author").(map[string]string)
logValue := map[string]interface{}{
"level": level,
"path": path,
"get": getParams,
"post": string(postParams),
"message": message,
"ip": this.GetClientIp(),
"user_agent": userAgent,
"referer": referer,
"user_id": user["user_id"],
"username": user["username"],
"create_time": time.Now().Unix(),
}
models.LogModel.Insert(logValue)
}
func (this *TemplateController) ErrorLog(message string) {
this.RecordLog(message, models.Log_Level_Error)
}
func (this *TemplateController) WarningLog(message string) {
this.RecordLog(message, models.Log_Level_Warning)
}
func (this *TemplateController) InfoLog(message string) {
this.RecordLog(message, models.Log_Level_Info)
}
func (this *TemplateController) DebugLog(message string) {
this.RecordLog(message, models.Log_Level_Debug)
}
func (this *TemplateController) GetLogInfoByCtx() map[string]interface{} {
userAgent := this.Ctx.Request.UserAgent()
referer := this.Ctx.Request.Referer()
getParams := this.Ctx.Request.URL.String()
path := this.Ctx.Request.URL.Path
this.Ctx.Request.ParseForm()
postParamsMap := map[string][]string(this.Ctx.Request.PostForm)
postParams, _ := json.Marshal(postParamsMap)
user := this.GetSession("author").(map[string]string)
logValue := map[string]interface{}{
"level": models.Log_Level_Info,
"path": path,
"get": getParams,
"post": string(postParams),
"message": "",
"ip": this.GetClientIp(),
"user_agent": userAgent,
"referer": referer,
"user_id": user["user_id"],
"username": user["username"],
"create_time": time.Now().Unix(),
}
return logValue
}
+264
View File
@@ -0,0 +1,264 @@
package controllers
import (
"strings"
"github.com/phachon/mm-wiki/app/models"
)
type UserController struct {
BaseController
}
func (this *UserController) Index() {
this.viewLayout("user/index", "user")
}
func (this *UserController) List() {
keywords := map[string]string{}
page, _ := this.GetInt("page", 1)
number, _ := this.GetRangeInt("number", 20, 10, 100)
username := strings.TrimSpace(this.GetString("username", ""))
if username != "" {
keywords["username"] = username
}
limit := (page - 1) * number
var err error
var count int64
var users []map[string]string
if len(keywords) != 0 {
count, err = models.UserModel.CountUsersByKeywords(keywords)
users, err = models.UserModel.GetUsersByKeywordsAndLimit(keywords, limit, number)
} else {
count, err = models.UserModel.CountUsers()
users, err = models.UserModel.GetUsersByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取全部用户列表失败: " + err.Error())
this.ViewError("获取全部用户列表失败", "/main/index")
}
followUsers, err := models.FollowModel.GetFollowsByUserIdAndType(this.UserId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取全部用户列表失败: " + err.Error())
this.ViewError("获取全部用户列表失败", "/main/index")
}
for _, user := range users {
user["follow"] = "0"
user["follow_id"] = "0"
for _, followUser := range followUsers {
if followUser["object_id"] == user["user_id"] {
user["follow_id"] = followUser["follow_id"]
user["follow"] = "1"
break
}
}
}
this.Data["users"] = users
this.Data["count"] = count
this.Data["login_user_id"] = this.UserId
this.SetPaginator(number, count)
this.viewLayout("user/list", "default")
}
func (this *UserController) Follow() {
followUsers, err := models.FollowModel.GetFollowsByUserIdAndType(this.UserId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
userIds := []string{}
for _, followUser := range followUsers {
userIds = append(userIds, followUser["object_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
for _, user := range users {
user["follow_id"] = "0"
for _, followUser := range followUsers {
if followUser["object_id"] == user["user_id"] {
user["follow_id"] = followUser["follow_id"]
break
}
}
}
this.Data["users"] = users
this.Data["count"] = len(users)
this.viewLayout("user/follow", "default")
}
func (this *UserController) Info() {
userId := this.GetString("user_id", "")
if userId == "" {
this.ViewError("用户不存在!", "/main/index")
}
if this.UserId == userId {
this.Redirect("/system/main/index", 302)
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("查找用户出错:" + err.Error())
this.ViewError("查找用户出错!", "/main/index")
}
if len(user) == 0 {
this.ViewError("用户不存在!", "/main/index")
}
logDocuments, err := models.LogDocumentModel.GetLogDocumentsByUserIdAndLimit(userId, 0, 10)
if err != nil {
this.ErrorLog("查找用户活动出错:" + err.Error())
this.ViewError("查找用户活动出错!", "/main/index")
}
docIds := []string{}
for _, logDocument := range logDocuments {
docIds = append(docIds, logDocument["document_id"])
}
documents, err := models.DocumentModel.GetDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("查找用户活动出错: " + err.Error())
this.ViewError("查找用户活动出错", "/main/index")
}
for _, logDocument := range logDocuments {
for _, document := range documents {
if document["document_id"] == logDocument["document_id"] {
logDocument["document_id"] = document["document_id"]
logDocument["document_name"] = document["name"]
logDocument["document_type"] = document["type"]
logDocument["update_time"] = document["update_time"]
}
}
}
this.Data["user"] = user
this.Data["logDocuments"] = logDocuments
this.Data["count"] = len(logDocuments)
this.viewLayout("user/info", "default")
}
func (this *UserController) FollowUser() {
userId := this.GetString("user_id", "")
if userId == "" {
this.ViewError("用户不存在!", "/user/list")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("查找用户出错:" + err.Error())
this.ViewError("查找用户出错!", "/user/list")
}
if len(user) == 0 {
this.ViewError("用户不存在!", "/user/list")
}
// follow users
followUsers, err := models.FollowModel.GetFollowsByUserIdAndType(userId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
userIds := []string{}
for _, followUser := range followUsers {
userIds = append(userIds, followUser["object_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
for _, user := range users {
user["follow_id"] = "0"
for _, followUser := range followUsers {
if followUser["object_id"] == user["user_id"] {
user["follow_id"] = followUser["follow_id"]
break
}
}
}
// fans users
followedUsers, err := models.FollowModel.GetFollowsByObjectIdAndType(userId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
followedUserIds := []string{}
for _, followedUser := range followedUsers {
followedUserIds = append(followedUserIds, followedUser["user_id"])
}
fansUsers, err := models.UserModel.GetUsersByUserIds(followedUserIds)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/user/list")
}
this.Data["users"] = users
this.Data["fansUsers"] = fansUsers
this.Data["followCount"] = len(users)
this.Data["fansCount"] = len(fansUsers)
this.Data["user"] = user
this.viewLayout("user/follow_user", "default")
}
func (this *UserController) FollowPage() {
userId := this.GetString("user_id", "")
if userId == "" {
this.ViewError("用户不存在!", "/user/list")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("查找用户出错:" + err.Error())
this.ViewError("查找用户出错!", "/user/list")
}
if len(user) == 0 {
this.ViewError("用户不存在!", "/user/list")
}
followPages, err := models.FollowModel.GetFollowsByUserIdAndType(userId, models.Follow_Type_Doc)
if err != nil {
this.ErrorLog("获取用户关注页面列表失败: " + err.Error())
this.ViewError("获取用户关注页面列表失败", "/user/list")
}
documentIds := []string{}
for _, followPage := range followPages {
documentIds = append(documentIds, followPage["object_id"])
}
pages, err := models.DocumentModel.GetDocumentsByDocumentIds(documentIds)
if err != nil {
this.ErrorLog("获取用户关注页面列表失败: " + err.Error())
this.ViewError("获取用户关注页面列表失败", "/user/list")
}
for _, page := range pages {
page["follow_id"] = "0"
for _, followPage := range followPages {
if page["document_id"] == followPage["object_id"] {
page["follow_id"] = followPage["follow_id"]
break
}
}
}
this.Data["pages"] = pages
this.Data["count"] = len(pages)
this.Data["user"] = user
this.viewLayout("user/collect_page", "default")
}
+265
View File
@@ -0,0 +1,265 @@
package models
import (
"fmt"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const Table_Attachment_Name = "attachment"
const (
Attachment_Source_Default = 0
Attachment_Source_Image = 1
)
type Attachment struct {
}
var AttachmentModel = Attachment{}
// get attachment by attachment_id
func (a *Attachment) GetAttachmentByAttachmentId(attachmentId string) (attachment map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"attachment_id": attachmentId,
}))
if err != nil {
return
}
attachment = rs.Row()
return
}
// attachment_id and name is exists
func (a *Attachment) HasSameName(attachmentId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"attachment_id <>": attachmentId,
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (a *Attachment) HasAttachmentName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get attachment by name
func (a *Attachment) GetAttachmentByName(name string) (attachment map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
attachment = rs.Row()
return
}
// get attachments by document and source
func (a *Attachment) GetAttachmentsByDocumentIdAndSource(documentId string, source int) (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"document_id": documentId,
"source": source,
}).OrderBy("attachment_id", "desc"))
if err != nil {
return
}
attachments = rs.Rows()
return
}
// get attachments by document_id
func (a *Attachment) GetAttachmentsByDocumentId(documentId string) (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"document_id": documentId,
}))
if err != nil {
return
}
attachments = rs.Rows()
return
}
// get attachments by document_id
func (a *Attachment) GetAttachmentsByDocumentIds(documentIds []string) (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"document_id": documentIds,
}))
if err != nil {
return
}
attachments = rs.Rows()
return
}
// get attachments by space_id
func (a *Attachment) GetAttachmentsBySpaceId(spaceId string) (attachments []map[string]string, err error) {
documents, err := DocumentModel.GetDocumentsBySpaceId(spaceId)
if err != nil {
return
}
documentIds := []string{}
for _, document := range documents {
documentIds = append(documentIds, document["document_id"])
}
return a.GetAttachmentsByDocumentIds(documentIds)
}
// delete attachment by attachment_id
func (a *Attachment) Delete(attachmentId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Attachment_Name, map[string]interface{}{
"attachment_id": attachmentId,
}))
if err != nil {
return
}
return
}
// insert attachment
func (a *Attachment) Insert(attachmentValue map[string]interface{}, spaceId string) (id int64, err error) {
attachmentValue["create_time"] = time.Now().Unix()
attachmentValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Attachment_Name, attachmentValue))
if err != nil {
return
}
id = rs.LastInsertId
// create document log
go func(attachmentValue map[string]interface{}, spaceId string) {
comment := fmt.Sprintf("上传了附件 %s", attachmentValue["name"].(string))
if attachmentValue["source"].(int) == Attachment_Source_Image {
comment = fmt.Sprintf("上传了图片 %s", attachmentValue["name"].(string))
}
_, _ = LogDocumentModel.UpdateAction(attachmentValue["user_id"].(string),
attachmentValue["document_id"].(string), comment, spaceId)
}(attachmentValue, spaceId)
return
}
// get all attachments
func (a *Attachment) GetAttachments() (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Attachment_Name))
if err != nil {
return
}
attachments = rs.Rows()
return
}
// get attachments by like name
func (a *Attachment) GetAttachmentsByLikeName(name string) (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
}).Limit(0, 1))
if err != nil {
return
}
attachments = rs.Rows()
return
}
// get attachment by many attachment_id
func (a *Attachment) GetAttachmentByAttachmentIds(attachmentIds []string) (attachments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Attachment_Name).Where(map[string]interface{}{
"attachment_id": attachmentIds,
}))
if err != nil {
return
}
attachments = rs.Rows()
return
}
func (a *Attachment) DeleteAttachmentsDBFileByDocumentId(documentId string) (err error) {
db := G.DB()
attachments, err := a.GetAttachmentsByDocumentId(documentId)
if err != nil {
return
}
// delete attachment file
err = utils.Document.DeleteAttachment(attachments)
if err != nil {
return err
}
// delete db attachment
_, err = db.Exec(db.AR().Delete(Table_Attachment_Name, map[string]interface{}{
"document_id": documentId,
}))
if err != nil {
return
}
return nil
}
func (a *Attachment) DeleteAttachmentDBFile(attachmentId string) (err error) {
db := G.DB()
attachment, err := a.GetAttachmentByAttachmentId(attachmentId)
if err != nil {
return
}
// delete attachment file
err = utils.Document.DeleteAttachment([]map[string]string{attachment})
if err != nil {
return err
}
// delete db attachment
_, err = db.Exec(db.AR().Delete(Table_Attachment_Name, map[string]interface{}{
"attachment_id": attachmentId,
}))
if err != nil {
return
}
return nil
}
+317
View File
@@ -0,0 +1,317 @@
package models
import (
"time"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
)
const (
Auth_Used_True = 1
Auth_Used_False = 0
)
const Table_Auth_Name = "login_auth"
type Auth struct {
}
var AuthModel = Auth{}
// get auth by auth_id
func (a *Auth) GetAuthByAuthId(authId string) (auth map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"login_auth_id": authId,
}))
if err != nil {
return
}
auth = rs.Row()
return
}
// auth_id and name is exists
func (a *Auth) HasSameName(authId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"login_auth_id <>": authId,
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// auth_id and name is exists
func (a *Auth) HasSameUsernamePrefix(authId, usernamePrefix string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"login_auth_id <>": authId,
"username_prefix": usernamePrefix,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (a *Auth) HasAuthName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (a *Auth) HasAuthUsernamePrefix(usernamePrefix string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"username_prefix": usernamePrefix,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get auth by name
func (a *Auth) GetAuthByName(name string) (auth map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
auth = rs.Row()
return
}
// delete auth by auth_id
func (a *Auth) Delete(authId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Auth_Name, map[string]interface{}{
"login_auth_id": authId,
}))
if err != nil {
return
}
return
}
// insert auth
func (a *Auth) Insert(authValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
// is_used
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"is_used": Auth_Used_True,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() == 0 {
authValue["is_used"] = Auth_Used_True
} else {
authValue["is_used"] = Auth_Used_False
}
authValue["create_time"] = time.Now().Unix()
authValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Insert(Table_Auth_Name, authValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update auth by auth_id
func (a *Auth) Update(authId string, authValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
authValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Auth_Name, authValue, map[string]interface{}{
"login_auth_id": authId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit auths by search keyword
func (a *Auth) GetAuthsByKeywordAndLimit(keyword string, limit int, number int) (auths []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}).Limit(limit, number).OrderBy("auth_id", "DESC"))
if err != nil {
return
}
auths = rs.Rows()
return
}
// get limit auths
func (a *Auth) GetAuthsByLimit(limit int, number int) (auths []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Auth_Name).
Limit(limit, number).
OrderBy("login_auth_id", "DESC"))
if err != nil {
return
}
auths = rs.Rows()
return
}
// get all auths
func (a *Auth) GetAuths() (auths []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Auth_Name))
if err != nil {
return
}
auths = rs.Rows()
return
}
// get auth count
func (a *Auth) CountAuths() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Auth_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get auth count by keyword
func (a *Auth) CountAuthsByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_Auth_Name).
Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get auths by like name
func (a *Auth) GetAuthsByLikeName(name string) (auths []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
}).Limit(0, 1))
if err != nil {
return
}
auths = rs.Rows()
return
}
// get auth by many auth_id
func (a *Auth) GetAuthByAuthIds(authIds []string) (auths []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Auth_Name).Where(map[string]interface{}{
"login_auth_id": authIds,
}))
if err != nil {
return
}
auths = rs.Rows()
return
}
// set auth used
func (a *Auth) SetAuthUsed(authId string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Update(Table_Auth_Name, map[string]interface{}{"is_used": Auth_Used_False}, map[string]interface{}{
"is_used": Auth_Used_True,
}))
if err != nil {
return
}
rs, err = db.Exec(db.AR().Update(Table_Auth_Name, map[string]interface{}{"is_used": Auth_Used_True}, map[string]interface{}{
"login_auth_id": authId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get used auth
func (a *Auth) GetUsedAuth() (auth map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("*").From(Table_Auth_Name).Where(map[string]interface{}{
"is_used": Auth_Used_True,
}).Limit(0, 1))
if err != nil {
return
}
auth = rs.Row()
return
}
+192
View File
@@ -0,0 +1,192 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
)
const (
Collection_Type_Doc = 1
Collection_Type_Space = 2
)
const Table_Collection_Name = "collection"
type Collection struct {
}
var CollectionModel = Collection{}
// get collection by collection_id
func (c *Collection) GetCollectionByCollectionId(collectionId string) (collection map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Collection_Name).Where(map[string]interface{}{
"collection_id": collectionId,
}))
if err != nil {
return
}
collection = rs.Row()
return
}
// get collections by user_id
func (c *Collection) GetCollectionsByUserId(userId string) (collections []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Collection_Name).Where(map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
collections = rs.Rows()
return
}
// get collections by user_id
func (c *Collection) GetCollectionsByUserIdAndType(userId string, typeS int) (collections []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Collection_Name).Where(map[string]interface{}{
"user_id": userId,
"type": typeS,
}))
if err != nil {
return
}
collections = rs.Rows()
return
}
// get collections by user_id type and resource_id
func (c *Collection) GetCollectionByUserIdTypeAndResourceId(userId string, typeS int, resId string) (collection map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Collection_Name).Where(map[string]interface{}{
"user_id": userId,
"type": typeS,
"resource_id": resId,
}).Limit(0, 1))
if err != nil {
return
}
collection = rs.Row()
return
}
// delete collection by collection_id
func (c *Collection) Delete(collectionId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Collection_Name, map[string]interface{}{
"collection_id": collectionId,
}))
if err != nil {
return
}
return
}
// delete collection by type and object_id
func (c *Collection) DeleteByResourceIdType(resourceId string, collectType string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Collection_Name, map[string]interface{}{
"type": collectType,
"resource_id": resourceId,
}))
if err != nil {
return
}
return
}
// insert collection
func (c *Collection) Insert(collectionValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Collection_Name, collectionValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get all collections
func (c *Collection) GetCollections() (collections []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Collection_Name))
if err != nil {
return
}
collections = rs.Rows()
return
}
// get collection count
func (c *Collection) CountCollections() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Collection_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get collections by many collection_id
func (c *Collection) GetCollectionsByCollectionIds(collectionIds []string) (collections []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Collection_Name).Where(map[string]interface{}{
"collection_id": collectionIds,
}))
if err != nil {
return
}
collections = rs.Rows()
return
}
func (c *Collection) GetResourceIdsOrderByCountLimit(limit int, collectType int) (collects []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("resource_id, count('resource_id') as total").
From(Table_Collection_Name).Where(map[string]interface{}{
"type": collectType,
}).
GroupBy("resource_id").
OrderBy("total", "DESC").
Limit(0, limit)
rs, err = db.Query(sql)
if err != nil {
return
}
collects = rs.Rows()
return
}
func (c *Collection) GetCollectionGroupUserId(colType int) (collects []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("user_id, count('user_id') as total").
From(Table_Collection_Name).Where(map[string]interface{}{
"type": colType,
}).GroupBy("user_id")
rs, err = db.Query(sql)
if err != nil {
return
}
collects = rs.Rows()
return
}
+178
View File
@@ -0,0 +1,178 @@
package models
import (
"github.com/snail007/go-activerecord/mysql"
"time"
)
const Table_Config_Name = "config"
const (
ConfigKeyMainTitle = "main_title"
ConfigKeyMainDescription = "main_description"
ConfigKeyAutoFollowdoc = "auto_follow_doc_open"
ConfigKeySendEmail = "send_email_open"
ConfigKeyAuthLogin = "sso_open"
ConfigKeySystemVersion = "system_version"
ConfigKeyFulltextSearch = "fulltext_search_open"
ConfigKeyDocSearchTimer = "doc_search_timer"
ConfigKeySystemName = "system_name"
)
type Config struct {
}
var ConfigModel = Config{}
// get config by config_id
func (c *Config) GetConfigByConfigId(configId string) (config map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Config_Name).Where(map[string]interface{}{
"config_id": configId,
}))
if err != nil {
return
}
config = rs.Row()
return
}
// update config by config_id
func (c *Config) Update(configId string, configValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
configValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Config_Name, configValue, map[string]interface{}{
"config_id": configId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update config by key
func (c *Config) UpdateByKey(key string, value string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
configValue := map[string]interface{}{}
configValue["value"] = value
configValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Config_Name, configValue, map[string]interface{}{
"key": key,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get all configs
func (c *Config) GetConfigs() (configs []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Config_Name))
if err != nil {
return
}
configs = rs.Rows()
return
}
// get all configs key map
func (c *Config) GetConfigsKeyMap() (configMaps map[string]map[string]string, err error) {
configMaps = make(map[string]map[string]string)
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Config_Name))
if err != nil {
return
}
configs := rs.Rows()
for _, config := range configs {
key, ok := config["key"]
if ok {
configMaps[key] = config
}
}
return
}
// get config by many config_id
func (c *Config) GetConfigByConfigIds(configIds []string) (configs []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Config_Name).Where(map[string]interface{}{
"config_id": configIds,
}))
if err != nil {
return
}
configs = rs.Rows()
return
}
// insert batch configs
func (c *Config) InsertBatch(insertValues []map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().InsertBatch(Table_Config_Name, insertValues))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// insert config
func (c *Config) Insert(insertValue map[string]interface{}) (id int64, err error) {
insertValue["create_time"] = time.Now().Unix()
insertValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Config_Name, insertValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get config by config key
func (c *Config) GetConfigByKey(key string) (config map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Config_Name).Where(map[string]interface{}{
"key": key,
}).Limit(0, 1))
if err != nil {
return
}
config = rs.Row()
return
}
// get config value by config key
func (c *Config) GetConfigValueByKey(key string, defaultValue string) (value string) {
configData, err := c.GetConfigByKey(key)
if err != nil {
return defaultValue
}
if len(configData) == 0 {
return defaultValue
}
if value, ok := configData["value"]; ok {
return value
}
return defaultValue
}
+140
View File
@@ -0,0 +1,140 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
)
const Table_Contact_Name = "contact"
type Contact struct {
}
var ContactModel = Contact{}
// 分页获取联系人
func (c *Contact) GetContactByLimit(limit, number int) (contact []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Contact_Name).Limit(limit, number))
if err != nil {
return
}
contact = rs.Rows()
return
}
// 获取联系人总数
func (c *Contact) CountContact() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_Contact_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// 分页筛选名字查询结果
func (c *Contact) GetContactByLimitAndName(name string, limit, number int) (contacts []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Contact_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
}).Limit(limit, number))
if err != nil {
return
}
contacts = rs.Rows()
return
}
// 获取筛选名字查询结果条数
func (c *Contact) CountContactByName(name string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Contact_Name).Select("count(*) as total").Where(map[string]interface{}{
"name Like": "%" + name + "%",
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// 通过 contact_id 获取联系人数据
func (c *Contact) GetContactByContactId(contactId string) (contact map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Contact_Name).Where(map[string]interface{}{
"contact_id": contactId,
}))
if err != nil {
return
}
contact = rs.Row()
return
}
// 通过 contact_id 更新联系人信息
func (c *Contact) UpdateByContactId(contact map[string]interface{}, contactId string) (affect int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Update(Table_Contact_Name, contact, map[string]interface{}{
"contact_id": contactId,
}))
if err != nil {
return
}
affect = rs.RowsAffected
return
}
// 通过 contact_id 更新联系人信息
func (c *Contact) Insert(contact map[string]interface{}) (contactId int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Contact_Name, contact))
if err != nil {
return
}
contactId = rs.LastInsertId
return
}
// 通过 contact_id 删除联系人信息
func (c *Contact) DeleteByContactId(contactId string) (affect int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Delete(Table_Contact_Name, map[string]interface{}{
"contact_id": contactId,
}))
if err != nil {
return
}
affect = rs.RowsAffected
return
}
// 获取所有联系人信息
func (c *Contact) GetAllContact() (contacts []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Contact_Name))
if err != nil {
return
}
contacts = rs.Rows()
return
}
+757
View File
@@ -0,0 +1,757 @@
package models
import (
"fmt"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"strconv"
"strings"
"time"
)
const (
Document_Delete_True = 1
Document_Delete_False = 0
Document_Type_Page = 1
Document_Type_Dir = 2
)
const Table_Document_Name = "document"
type Document struct {
}
var DocumentModel = Document{}
// get document by document_id
func (d *Document) GetDocumentByDocumentId(documentId string) (document map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"document_id": documentId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
document = rs.Row()
return
}
// get documents by parent_id
func (d *Document) GetDocumentsByParentId(parentId string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"parent_id": parentId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document by name
func (d *Document) GetDocumentsByName(name string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"name": name,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document by name and spaceId
func (d *Document) GetDocumentByNameAndSpaceId(name string, spaceId string) (document map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"name": name,
"space_id": spaceId,
"is_delete": Document_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
document = rs.Row()
return
}
// get document by name and spaceId
func (d *Document) GetDocumentByNameParentIdAndSpaceId(name string, parentId string, spaceId string, docType int) (document map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"name": name,
"space_id": spaceId,
"parent_id": parentId,
"type": docType,
"is_delete": Document_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
document = rs.Row()
return
}
// get document by name and spaceId
func (d *Document) GetDocumentByParentIdAndSpaceId(parentId string, spaceId string, docType int) (document map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id": parentId,
"type": docType,
"is_delete": Document_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
document = rs.Row()
return
}
// get document by name and spaceId
func (d *Document) GetDocumentsByParentIdAndSpaceIdOnly(parentId string, spaceId string) (document []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id": parentId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
document = rs.Rows()
return
}
// get max sequence
func (d *Document) GetDocumentMaxSequence(parentId string, spaceId string) (sequence int, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id": parentId,
}).OrderBy("sequence", "desc").Limit(0, 1))
if err != nil {
return
}
document := rs.Row()
sequenceStr := document["sequence"]
sequence, err = strconv.Atoi(sequenceStr)
return
}
// delete document by document_id
func (d *Document) DeleteDBAndFile(documentId string, spaceId string, userId string, pageFile string, docType string) (err error) {
db := G.DB()
tx, err := db.Begin(db.Config)
if err != nil {
return
}
_, err = db.ExecTx(db.AR().Update(Table_Document_Name, map[string]interface{}{
"is_delete": Document_Delete_True,
"update_time": time.Now().Unix(),
"edit_user_id": userId,
}, map[string]interface{}{
"document_id": documentId,
}), tx)
if err != nil {
tx.Rollback()
return
}
// delete document file
err = utils.Document.Delete(pageFile, utils.Convert.StringToInt(docType))
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
if err != nil {
return
}
// create document log
go func(userId, documentId string, spaceId string) {
_, err := LogDocumentModel.DeleteAction(userId, documentId, spaceId)
if err != nil {
logs.Error("delete document add log err=%s", err.Error())
}
}(userId, documentId, spaceId)
// delete follow doc
go func(documentId string) {
err := FollowModel.DeleteByObjectIdType(documentId, fmt.Sprintf("%d", Follow_Type_Doc))
if err != nil {
logs.Error("delete follow document err=%s", err.Error())
}
}(documentId)
// delete collect doc
go func(documentId string) {
err := CollectionModel.DeleteByResourceIdType(documentId, fmt.Sprintf("%d", Collection_Type_Doc))
if err != nil {
logs.Error("delete collect document err=%s", err.Error())
}
}(documentId)
return
}
// insert document
func (d *Document) Insert(documentValue map[string]interface{}) (id int64, err error) {
db := G.DB()
// start db begin
tx, err := db.Begin(db.Config)
if err != nil {
return
}
// 处理同级排序编号
parentId := documentValue["parent_id"].(string)
spaceId := documentValue["space_id"].(string)
sequence, err := d.GetDocumentMaxSequence(parentId, spaceId)
if err != nil {
sequence = 0
}
sequence += 1
documentValue["sequence"] = strconv.Itoa(sequence)
var rs *mysql.ResultSet
documentValue["create_time"] = time.Now().Unix()
documentValue["update_time"] = time.Now().Unix()
rs, err = db.ExecTx(db.AR().Insert(Table_Document_Name, documentValue), tx)
if err != nil {
tx.Rollback()
return
}
id = rs.LastInsertId
// create document page file
document := map[string]string{
"space_id": documentValue["space_id"].(string),
"parent_id": documentValue["parent_id"].(string),
"name": documentValue["name"].(string),
"type": fmt.Sprintf("%d", documentValue["type"].(int)),
"path": documentValue["path"].(string),
}
_, pageFile, err := d.GetParentDocumentsByDocument(document)
err = utils.Document.Create(pageFile)
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
if err != nil {
return
}
userId := documentValue["create_user_id"].(string)
// create document log
go func(userId, documentId, spaceId string) {
_, err := LogDocumentModel.CreateAction(userId, documentId, spaceId)
if err != nil {
logs.Error("create document add log err=%s", err.Error())
}
}(userId, fmt.Sprintf("%d", id), spaceId)
// follow document
go func(userId, documentId string) {
_, err := FollowModel.CreateAutoFollowDocument(userId, documentId)
if err != nil {
logs.Error("follow document err=%s", err.Error())
}
}(userId, fmt.Sprintf("%d", id))
return
}
// update document by document_id
func (d *Document) Update(documentId string, documentValue map[string]interface{}, comment string, spaceId string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
documentValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Document_Name, documentValue, map[string]interface{}{
"document_id": documentId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
id = rs.LastInsertId
// update document log
go func(editUserId string, documentId string, comment string, spaceId string) {
_, err := LogDocumentModel.UpdateAction(editUserId, documentId, comment, spaceId)
if err != nil {
logs.Error("update document add log err=%s", err.Error())
}
}(documentValue["edit_user_id"].(string), documentId, comment, spaceId)
// follow document
go func(editUserId string, documentId string) {
_, err := FollowModel.CreateAutoFollowDocument(editUserId, documentId)
if err != nil {
logs.Error("follow document err=%s", err.Error())
}
}(documentValue["edit_user_id"].(string), documentId)
return
}
// update document by spaceId and >= sequence
// 批量移动更新文档序号
func (d *Document) MoveSequenceBySpaceIdAndGtSequence(spaceId string, startSequence int, n int) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
//documentValue := map[string]interface{}{
// "sequence": fmt.Sprintf("(sequence+%d)", n),
// "update_time": time.Now().Unix(),
//}
updateTime := time.Now().Unix()
sql := fmt.Sprintf(
"update mw_%s set sequence=sequence+%d, update_time=%d where space_id=%s and sequence >= %d and is_delete=%d",
Table_Document_Name, n, updateTime, spaceId, startSequence, Document_Delete_False,
)
rs, err = db.ExecSQL(sql)
if err != nil {
logs.Error(err.Error())
return
}
id = rs.LastInsertId
return
}
// move document
func (d *Document) MoveDBAndFile(documentId string, spaceId string, updateValue map[string]interface{},
oldPageFile string, newPageFile string, docType string, comment string) (id int64, err error) {
db := G.DB()
tx, err := db.Begin(db.Config)
if err != nil {
return
}
var rs *mysql.ResultSet
updateValue["update_time"] = time.Now().Unix()
rs, err = db.ExecTx(db.AR().Update(Table_Document_Name, updateValue, map[string]interface{}{
"document_id": documentId,
"is_delete": Document_Delete_False,
}), tx)
if err != nil {
tx.Rollback()
return
}
id = rs.LastInsertId
err = utils.Document.Move(oldPageFile, newPageFile, utils.Convert.StringToInt(docType))
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
if err != nil {
return
}
// create document log
go func(userId, documentId, comment string, spaceId string) {
_, err := LogDocumentModel.UpdateAction(updateValue["edit_user_id"].(string), documentId, comment, spaceId)
if err != nil {
logs.Error("update document add log err=%s", err.Error())
}
}(updateValue["edit_user_id"].(string), documentId, comment, spaceId)
return
}
// update document by document_id
func (d *Document) UpdateDBAndFile(documentId string, spaceId string, document map[string]string, documentContent string, updateValue map[string]interface{}, comment string) (id int64, err error) {
// get document page file
_, oldPageFile, err := DocumentModel.GetParentDocumentsByDocument(document)
if err != nil {
return
}
// begin update
db := G.DB()
tx, err := db.Begin(db.Config)
if err != nil {
return
}
var rs *mysql.ResultSet
updateValue["update_time"] = time.Now().Unix()
rs, err = db.ExecTx(db.AR().Update(Table_Document_Name, updateValue, map[string]interface{}{
"document_id": documentId,
"is_delete": Document_Delete_False,
}), tx)
if err != nil {
tx.Rollback()
return
}
id = rs.LastInsertId
// update document file
docType := utils.Convert.StringToInt(document["type"])
nameIsChange := false
if updateValue["name"].(string) != document["name"] {
nameIsChange = true
}
err = utils.Document.Update(oldPageFile, updateValue["name"].(string), documentContent, docType, nameIsChange)
if err != nil {
tx.Rollback()
return
}
// commit
err = tx.Commit()
if err != nil {
return
}
// create document log
go func(documentId string, comment string, spaceId string) {
_, _ = LogDocumentModel.UpdateAction(updateValue["edit_user_id"].(string), documentId, comment, spaceId)
}(documentId, comment, spaceId)
// create follow doc
go func(documentId string) {
_, _ = FollowModel.CreateAutoFollowDocument(updateValue["edit_user_id"].(string), documentId)
}(documentId)
return
}
// get all documents
func (d *Document) GetDocumentsBySpaceId(spaceId string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document by spaceId and parentId
func (d *Document) GetDocumentsBySpaceIdAndParentId(spaceId string, parentId string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id": parentId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document by spaceId
func (d *Document) GetSpaceDefaultDocument(spaceId string) (document map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id": "0",
"is_delete": Document_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
document = rs.Row()
return
}
// get document by spaceId
func (d *Document) GetAllSpaceDocuments(spaceId string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"space_id": spaceId,
"parent_id >": "0",
"is_delete": Document_Delete_False,
}).OrderBy("sequence", "ASC"))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document count
func (d *Document) CountDocumentsBySpaceId(spaceId string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Document_Name).
Where(map[string]interface{}{
"space_id": spaceId,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get document count
func (d *Document) CountDocuments() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Document_Name).
Where(map[string]interface{}{
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get document by name
func (d *Document) GetDocumentsByLikeName(name string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
// get document link name and limit
func (d *Document) GetDocumentsByLikeNameAndLimit(name string, limit int, number int) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
"is_delete": Document_Delete_False,
}).Limit(limit, number))
if err != nil {
return
}
documents = rs.Rows()
return
}
// count document like name
func (d *Document) CountDocumentsLikeName(name string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Document_Name).
Where(map[string]interface{}{
"name Like": "%" + name + "%",
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
// get document by spaceId and document_ids
func (d *Document) GetDocumentsByDocumentIds(documentIds []string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"document_id": documentIds,
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetAllDocumentsByDocumentIds(documentIds []string) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"document_id": documentIds,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetAllDocuments() (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Document_Name).Where(map[string]interface{}{
"is_delete": Document_Delete_False,
}))
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetParentDocumentsByDocument(document map[string]string) (parentDocuments []map[string]string, pageFile string, err error) {
if document["parent_id"] == "0" {
parentDocuments = append(parentDocuments, document)
pageFile = utils.Document.GetDefaultPageFileBySpaceName(document["name"])
} else {
documentsIds := strings.Split(document["path"], ",")
parentDocuments, err = d.GetDocumentsByDocumentIds(documentsIds)
if err != nil {
return
}
var parentPath = ""
for _, parentDocument := range parentDocuments {
parentPath += parentDocument["name"] + "/"
}
parentPath = strings.TrimRight(parentPath, "/")
pageFile = utils.Document.GetPageFileByParentPath(document["name"], utils.Convert.StringToInt(document["type"]), parentPath)
}
return
}
func (d *Document) GetParentDocumentsByPath(path string) (parentDocuments []map[string]string, err error) {
documentsIds := strings.Split(path, ",")
parentDocuments, err = d.GetDocumentsByDocumentIds(documentsIds)
if err != nil {
return
}
return
}
func (d *Document) GetSpaceIdsOrderByCountDocumentLimit(limit int) (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("space_id, count('space_id') as total").
From(Table_Document_Name).Where(map[string]interface{}{
"is_delete": Document_Delete_False,
}).
GroupBy("space_id").
OrderBy("total", "DESC").
Limit(0, limit)
rs, err = db.Query(sql)
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetCountGroupByCreateTime(startTime int64) (documents []map[string]string, err error) {
/*select month(FROM_UNIXTIME(time)) from table_name group by month(FROM_UNIXTIME(time))*/
/*select DATE_FORMAT(FROM_UNIXTIME(time),"%Y-%m") from tcm_fund_list group by DATE_FORMAT(FROM_UNIXTIME(time),"%Y-%m")*/
/*select FROM_UNIXTIME(time,"%Y-%m") from tcm_fund_list group by FROM_UNIXTIME(time,"%Y-%m")*/
/*select DATE_FORMAT(FROM_UNIXTIME(time),"%Y-%m-%d") from tcm_fund_list group by DATE_FORMAT(FROM_UNIXTIME(time),"%Y-%m-%d")*/
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("DATE_FORMAT(FROM_UNIXTIME(create_time),'%Y-%m-%d') as date, count('date') as total").
From(Table_Document_Name).Where(map[string]interface{}{
"is_delete": Document_Delete_False,
"create_time >=": startTime,
}).GroupBy("DATE_FORMAT(FROM_UNIXTIME(create_time),'%Y-%m-%d')")
rs, err = db.Query(sql)
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetDocumentGroupCreateUserId() (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("create_user_id, count('create_user_id') as total").
From(Table_Document_Name).Where(map[string]interface{}{
"is_delete": Document_Delete_False,
}).GroupBy("create_user_id")
rs, err = db.Query(sql)
if err != nil {
return
}
documents = rs.Rows()
return
}
func (d *Document) GetDocumentGroupEditUserId() (documents []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("edit_user_id, count('edit_user_id') as total").
From(Table_Document_Name).Where(map[string]interface{}{
"is_delete": Document_Delete_False,
}).GroupBy("edit_user_id")
rs, err = db.Query(sql)
if err != nil {
return
}
documents = rs.Rows()
return
}
// 根据文档信息获取文档内容和文件地址
func (d *Document) GetDocumentContentByDocument(doc map[string]string) (content string, pageFile string, err error) {
// get document page file
_, pageFile, err = DocumentModel.GetParentDocumentsByDocument(doc)
if err != nil {
return content, pageFile, err
}
// get document content
content, err = utils.Document.GetContentByPageFile(pageFile)
if err != nil {
return content, pageFile, err
}
return content, pageFile, nil
}
+281
View File
@@ -0,0 +1,281 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const (
Email_Used_True = 1
Email_Used_False = 0
)
const Table_Email_Name = "email"
type Email struct {
}
var EmailModel = Email{}
// get email by email_id
func (u *Email) GetEmailByEmailId(emailId string) (email map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"email_id": emailId,
}))
if err != nil {
return
}
email = rs.Row()
return
}
// email_id and name is exists
func (u *Email) HasSameName(emailId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"email_id <>": emailId,
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (u *Email) HasEmailName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get email by name
func (u *Email) GetEmailByName(name string) (email map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
email = rs.Row()
return
}
// delete email by email_id
func (u *Email) Delete(emailId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Email_Name, map[string]interface{}{
"email_id": emailId,
}))
if err != nil {
return
}
return
}
// insert email
func (u *Email) Insert(emailValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
// is_used
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"is_used": Email_Used_True,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() == 0 {
emailValue["is_used"] = Email_Used_True
} else {
emailValue["is_used"] = Email_Used_False
}
emailValue["create_time"] = time.Now().Unix()
emailValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Insert(Table_Email_Name, emailValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update email by email_id
func (u *Email) Update(emailId string, emailValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
emailValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Email_Name, emailValue, map[string]interface{}{
"email_id": emailId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit emails by search keyword
func (u *Email) GetEmailsByKeywordAndLimit(keyword string, limit int, number int) (emails []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}).Limit(limit, number).OrderBy("email_id", "DESC"))
if err != nil {
return
}
emails = rs.Rows()
return
}
// get limit emails
func (u *Email) GetEmailsByLimit(limit int, number int) (emails []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Email_Name).
Limit(limit, number).
OrderBy("email_id", "DESC"))
if err != nil {
return
}
emails = rs.Rows()
return
}
// get all emails
func (u *Email) GetEmails() (emails []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Email_Name))
if err != nil {
return
}
emails = rs.Rows()
return
}
// get used email
func (u *Email) GetUsedEmail() (email map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("*").From(Table_Email_Name).Where(map[string]interface{}{
"is_used": Email_Used_True,
}).Limit(0, 1))
if err != nil {
return
}
email = rs.Row()
return
}
// get email count
func (u *Email) CountEmails() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Email_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get email count by keyword
func (u *Email) CountEmailsByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_Email_Name).
Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get emails by like name
func (u *Email) GetEmailsByLikeName(name string) (emails []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
}).Limit(0, 1))
if err != nil {
return
}
emails = rs.Rows()
return
}
// get email by many email_id
func (u *Email) GetEmailByEmailIds(emailIds []string) (emails []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Email_Name).Where(map[string]interface{}{
"email_id": emailIds,
}))
if err != nil {
return
}
emails = rs.Rows()
return
}
// set email used
func (u *Email) SetEmailUsed(emailId string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Update(Table_Email_Name, map[string]interface{}{"is_used": Email_Used_False}, map[string]interface{}{
"is_used": Email_Used_True,
}))
if err != nil {
return
}
rs, err = db.Exec(db.AR().Update(Table_Email_Name, map[string]interface{}{"is_used": Email_Used_True}, map[string]interface{}{
"email_id": emailId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
+257
View File
@@ -0,0 +1,257 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const (
Follow_Type_Doc = 1
Follow_Type_User = 2
)
const Table_Follow_Name = "follow"
type Follow struct {
}
var FollowModel = Follow{}
// get follow by follow_id
func (f *Follow) GetFollowByFollowId(followId string) (follow map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"follow_id": followId,
}))
if err != nil {
return
}
follow = rs.Row()
return
}
// get follows by user_id and type
func (f *Follow) GetFollowsByUserIdAndType(userId string, followType int) (follows []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"user_id": userId,
"type": followType,
}))
if err != nil {
return
}
follows = rs.Rows()
return
}
// get follows by user_id and type limit
func (f *Follow) GetFollowsByUserIdTypeAndLimit(userId string, followType int, limit int, number int) (follows []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"user_id": userId,
"type": followType,
}).Limit(limit, number).OrderBy("follow_id", "DESC"))
if err != nil {
return
}
follows = rs.Rows()
return
}
// get followed follows
func (f *Follow) GetFollowsByObjectIdAndType(objectId string, followType int) (follows []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"object_id": objectId,
"type": followType,
}))
if err != nil {
return
}
follows = rs.Rows()
return
}
// get followed follow
func (f *Follow) GetFollowByUserIdAndTypeAndObjectId(userId string, followType int, objectId string) (follow map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"user_id": userId,
"type": followType,
"object_id": objectId,
}).Limit(0, 1))
if err != nil {
return
}
follow = rs.Row()
return
}
// delete follow by follow_id
func (f *Follow) Delete(followId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Follow_Name, map[string]interface{}{
"follow_id": followId,
}))
if err != nil {
return
}
return
}
// delete follow by type and object_id
func (f *Follow) DeleteByObjectIdType(objectId string, followType string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Follow_Name, map[string]interface{}{
"type": followType,
"object_id": objectId,
}))
if err != nil {
return
}
return
}
// insert follow user
func (f *Follow) Insert(userId string, fType int, objectId string) (id int64, err error) {
followValue := map[string]interface{}{
"user_id": userId,
"type": fType,
"object_id": objectId,
"create_time": time.Now().Unix(),
}
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Follow_Name, followValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get all follows
func (f *Follow) GetFollows() (follows []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Follow_Name))
if err != nil {
return
}
follows = rs.Rows()
return
}
// get follow count
func (f *Follow) CountFollows() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Follow_Name))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
// get follow count
func (f *Follow) CountFollowsByUserIdAndType(userId string, followType int) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_Follow_Name).Where(map[string]interface{}{
"user_id": userId,
"type": followType,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
// get follows by many follow_id
func (f *Follow) GetFollowsByFollowIds(followIds []string) (follows []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Follow_Name).Where(map[string]interface{}{
"follow_id": followIds,
}))
if err != nil {
return
}
follows = rs.Rows()
return
}
// create auto follow document
func (f *Follow) CreateAutoFollowDocument(userId string, documentId string) (id int64, err error) {
autoFollowConf := ConfigModel.GetConfigValueByKey(ConfigKeyAutoFollowdoc, "0")
if autoFollowConf == "1" {
follow, err := f.GetFollowByUserIdAndTypeAndObjectId(userId, Follow_Type_Doc, documentId)
if err != nil {
return 0, err
}
if len(follow) == 0 {
return f.Insert(userId, Follow_Type_Doc, documentId)
}
}
return 0, nil
}
func (f *Follow) FollowDocument(userId string, documentId string) (id int64, err error) {
follow, err := f.GetFollowByUserIdAndTypeAndObjectId(userId, Follow_Type_Doc, documentId)
if err != nil {
return 0, err
}
if len(follow) == 0 {
return f.Insert(userId, Follow_Type_Doc, documentId)
}
return 0, nil
}
func (f *Follow) GetFollowGroupUserId(fType int) (collects []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("user_id, count('user_id') as total").
From(Table_Follow_Name).Where(map[string]interface{}{
"type": fType,
}).GroupBy("user_id")
rs, err = db.Query(sql)
if err != nil {
return
}
collects = rs.Rows()
return
}
func (f *Follow) GetFansUserGroupUserId() (collects []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("object_id, count('object_id') as total").
From(Table_Follow_Name).Where(map[string]interface{}{
"type": Follow_Type_User,
}).GroupBy("object_id")
rs, err = db.Query(sql)
if err != nil {
return
}
collects = rs.Rows()
return
}
+7
View File
@@ -0,0 +1,7 @@
package models
import (
"github.com/snail007/go-activerecord/mysql"
)
var G *mysql.DBGroup
+241
View File
@@ -0,0 +1,241 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const Table_Link_Name = "link"
type Link struct {
}
var LinkModel = Link{}
// get link by link_id
func (l *Link) GetLinkByLinkId(linkId string) (link map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"link_id": linkId,
}))
if err != nil {
return
}
link = rs.Row()
return
}
// link_id and name is exists
func (l *Link) HasSameName(linkId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"link_id <>": linkId,
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (l *Link) HasLinkName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get link by name
func (l *Link) GetLinkByName(name string) (link map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"name": name,
}).Limit(0, 1))
if err != nil {
return
}
link = rs.Row()
return
}
// delete link by link_id
func (l *Link) Delete(linkId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Link_Name, map[string]interface{}{
"link_id": linkId,
}))
if err != nil {
return
}
return
}
// insert link
func (l *Link) Insert(linkValue map[string]interface{}) (id int64, err error) {
linkValue["create_time"] = time.Now().Unix()
linkValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Link_Name, linkValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update link by link_id
func (l *Link) Update(linkId string, linkValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
linkValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Link_Name, linkValue, map[string]interface{}{
"link_id": linkId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit links by search keyword
func (l *Link) GetLinksByKeywordAndLimit(keyword string, limit int, number int) (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}).Limit(limit, number).OrderBy("link_id", "DESC"))
if err != nil {
return
}
links = rs.Rows()
return
}
// get limit links
func (l *Link) GetLinksByLimit(limit int, number int) (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Link_Name).
Limit(limit, number).
OrderBy("link_id", "DESC"))
if err != nil {
return
}
links = rs.Rows()
return
}
// get all links
func (l *Link) GetLinks() (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Link_Name))
if err != nil {
return
}
links = rs.Rows()
return
}
// get all links by sequence
func (l *Link) GetLinksOrderBySequence() (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Link_Name).OrderBy("sequence", "ASC"))
if err != nil {
return
}
links = rs.Rows()
return
}
// get link count
func (l *Link) CountLinks() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Link_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get link count by keyword
func (l *Link) CountLinksByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_Link_Name).
Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get links by like name
func (l *Link) GetLinksByLikeName(name string) (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
}).Limit(0, 1))
if err != nil {
return
}
links = rs.Rows()
return
}
// get link by many link_id
func (l *Link) GetLinkByLinkIds(linkIds []string) (links []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Link_Name).Where(map[string]interface{}{
"link_id": linkIds,
}))
if err != nil {
return
}
links = rs.Rows()
return
}
+184
View File
@@ -0,0 +1,184 @@
package models
import (
"encoding/json"
"github.com/astaxie/beego/context"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"strings"
"time"
)
const (
Log_Level_Emegergency = iota
Log_Level_Alaert
Log_Level_Critical
Log_Level_Error
Log_Level_Warning
Log_Level_Notice
Log_Level_Info
Log_Level_Debug
)
const Table_Log_Name = "log"
type Log struct {
}
var LogModel = Log{}
// 根据 log_id 获取日志
func (l *Log) GetLogByLogId(logId string) (log map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Log_Name).Where(map[string]interface{}{
"log_id": logId,
}))
if err != nil {
return
}
log = rs.Row()
return
}
// 插入
func (l *Log) Insert(log map[string]interface{}) (id int64, err error) {
log["create_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Log_Name, log))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// 根据关键字分页获取日志
func (l *Log) GetLogsByKeywordAndLimit(level, message, username string, limit int, number int) (logs []map[string]string, err error) {
db := G.DB()
where := make(map[string]interface{})
if level != "" {
where["level"] = level
}
if message != "" {
where["message LIKE"] = "%" + message + "%"
}
if username != "" {
where["username LIKE"] = "%" + username + "%"
}
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Log_Name).Where(where).Limit(limit, number).OrderBy("log_id", "DESC"))
if err != nil {
return
}
logs = rs.Rows()
return
}
// 分页获取日志
func (l *Log) GetLogsByLimit(limit int, number int) (logs []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Log_Name).
Limit(limit, number).
OrderBy("log_id", "DESC"))
if err != nil {
return
}
logs = rs.Rows()
return
}
// 获取日志总数
func (l *Log) CountLogs() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Log_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
func (l *Log) CountLogsByLevel(level int) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
Where(map[string]interface{}{
"level": level,
}).
From(Table_Log_Name))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// 根据关键字获取日志总数
func (l *Log) CountLogsByKeyword(level, message, username string) (count int64, err error) {
db := G.DB()
where := make(map[string]interface{})
if level != "" {
where["level"] = level
}
if message != "" {
where["message LIKE"] = "%" + message + "%"
}
if username != "" {
where["username LIKE"] = "%" + username + "%"
}
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_Log_Name).
Where(where))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
func (l *Log) RecordLog(message string, level int, userId string, username string, ctx context.Context) (id int64, err error) {
userAgent := ctx.Request.UserAgent()
referer := ctx.Request.Referer()
getParams := ctx.Request.URL.String()
path := ctx.Request.URL.Path
ctx.Request.ParseForm()
postParamsMap := map[string][]string(ctx.Request.PostForm)
postParams, _ := json.Marshal(postParamsMap)
logValue := map[string]interface{}{
"level": level,
"path": path,
"get": getParams,
"post": string(postParams),
"message": message,
"ip": strings.Split(ctx.Request.RemoteAddr, ":"),
"user_agent": userAgent,
"referer": referer,
"user_id": userId,
"username": username,
"create_time": time.Now().Unix(),
}
return LogModel.Insert(logValue)
}
+290
View File
@@ -0,0 +1,290 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const (
LogDocument_Action_Create = 1
LogDocument_Action_Update = 2
LogDocument_Action_Delete = 3
)
const Table_LogDocument_Name = "log_document"
type LogDocument struct {
}
var LogDocumentModel = LogDocument{}
func (ld *LogDocument) GetLogDocumentByLogDocumentId(logDocId string) (logDocuments map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"log_document_id": logDocId,
}))
if err != nil {
return
}
logDocuments = rs.Row()
return
}
func (ld *LogDocument) Insert(logDocument map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_LogDocument_Name, logDocument))
if err != nil {
return
}
id = rs.LastInsertId
return
}
func (ld *LogDocument) CreateAction(userId string, documentId string, spaceId string) (id int64, err error) {
logDocument := map[string]interface{}{
"user_id": userId,
"document_id": documentId,
"space_id": spaceId,
"comment": "创建了文档",
"action": LogDocument_Action_Create,
"create_time": time.Now().Unix(),
}
return ld.Insert(logDocument)
}
func (ld *LogDocument) UpdateAction(userId string, documentId string, comment string, spaceId string) (id int64, err error) {
logDocument := map[string]interface{}{
"user_id": userId,
"document_id": documentId,
"space_id": spaceId,
"comment": comment,
"action": LogDocument_Action_Update,
"create_time": time.Now().Unix(),
}
return ld.Insert(logDocument)
}
func (ld *LogDocument) DeleteAction(userId string, documentId string, spaceId string) (id int64, err error) {
logDocument := map[string]interface{}{
"user_id": userId,
"document_id": documentId,
"space_id": spaceId,
"comment": "删除了该文档",
"action": LogDocument_Action_Delete,
"create_time": time.Now().Unix(),
}
return ld.Insert(logDocument)
}
func (ld *LogDocument) GetLogDocumentsByDocumentId(documentId string) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"document_id": documentId,
}))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByUserId(userId string) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByDocumentIdAndLimit(documentId string, limit int, number int) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"document_id": documentId,
}).Limit(limit, number).OrderBy("log_document_id", "DESC"))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByUserIdAndLimit(userId string, limit int, number int) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"user_id": userId,
}).Limit(limit, number).OrderBy("log_document_id", "DESC"))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByUserIdKeywordAndLimit(userId string, keyword string, limit int, number int) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"comment LIKE": "%" + keyword + "%",
"user_id": userId,
}).Limit(limit, number).OrderBy("log_document_id", "DESC"))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByKeywordAndLimit(keyword string, limit int, number int) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_LogDocument_Name).Where(map[string]interface{}{
"comment LIKE": "%" + keyword + "%",
}).Limit(limit, number).OrderBy("log_document_id", "DESC"))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) GetLogDocumentsByLimit(userId string, limit int, number int) (logDocuments []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
where := db.AR().From(Table_LogDocument_Name)
// 查询用户空间权限
spaceUserRs, err := db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"user_id": userId,
}))
spaceUsers := spaceUserRs.Rows()
spaceUsersLen := len(spaceUsers)
for i := 0; i < spaceUsersLen; i++ {
spaceUser := spaceUsers[i]
if i == 0 {
where.WhereWrap(map[string]interface{}{
"space_id": spaceUser["space_id"],
}, "", "")
} else {
where.WhereWrap(map[string]interface{}{
"space_id": spaceUser["space_id"],
}, "or", "")
}
}
// 查询公共空间
spaceRs, err := db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"visit_level": "public",
}))
spaces := spaceRs.Rows()
for i := 0; i < len(spaces); i++ {
space := spaces[i]
if i == 0 && spaceUsersLen == 0 {
where.WhereWrap(map[string]interface{}{
"space_id": space["space_id"],
}, "", "")
} else {
where.WhereWrap(map[string]interface{}{
"space_id": space["space_id"],
}, "or", "")
}
}
rs, err = db.Query(where.Limit(limit, number).OrderBy("log_document_id", "DESC"))
if err != nil {
return
}
logDocuments = rs.Rows()
return
}
func (ld *LogDocument) CountLogDocumentsByDocumentId(documentId string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_LogDocument_Name).Where(map[string]interface{}{
"document_id": documentId,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
func (ld *LogDocument) CountLogDocumentsByUserId(userId string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_LogDocument_Name).Where(map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
func (ld *LogDocument) CountLogDocumentsByUserIdAndKeyword(userId string, keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_LogDocument_Name).Where(map[string]interface{}{
"comment LIKE": "%" + keyword + "%",
"user_id": userId,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
func (ld *LogDocument) CountLogDocumentsByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_LogDocument_Name).Where(map[string]interface{}{
"comment LIKE": "%" + keyword + "%",
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
func (ld *LogDocument) CountLogDocuments() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_LogDocument_Name))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
+238
View File
@@ -0,0 +1,238 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const TablePluginName = "plugin"
type Plugin struct {
}
var PluginModel = Plugin{}
// get plugin by plugin_id
func (p *Plugin) GetPluginByPluginId(pluginId string) (plugin map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(TablePluginName).Where(map[string]interface{}{
"plugin_id": pluginId,
}))
if err != nil {
return
}
plugin = rs.Row()
return
}
// update plugin by plugin_id
func (p *Plugin) Update(pluginId string, pluginValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
pluginValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(TablePluginName, pluginValue, map[string]interface{}{
"plugin_id": pluginId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit plugins by search keyword
func (p *Plugin) GetPluginsByKeywordAndLimit(keyword string, limit int, number int) (plugins []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(TablePluginName).Where(map[string]interface{}{
"title LIKE": "%" + keyword + "%",
}).Limit(limit, number).OrderBy("plugin_id", "DESC"))
if err != nil {
return
}
plugins = rs.Rows()
return
}
// get limit plugins
func (p *Plugin) GetPluginsByLimit(limit int, number int) (plugins []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(TablePluginName).
Limit(limit, number).
OrderBy("plugin_id", "DESC"))
if err != nil {
return
}
plugins = rs.Rows()
return
}
// update plugin conf value by pluginKey
func (p *Plugin) UpdateConfValueByKey(pluginKey string, confValue string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
pluginValue := map[string]interface{}{}
pluginValue["conf_value"] = confValue
pluginValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(TablePluginName, pluginValue, map[string]interface{}{
"plugin_key": pluginKey,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update plugin conf value by pluginId
func (p *Plugin) UpdateConfValueByPluginId(pluginId string, confValue string) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
pluginValue := map[string]interface{}{}
pluginValue["conf_value"] = confValue
pluginValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(TablePluginName, pluginValue, map[string]interface{}{
"plugin_id": pluginId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get all plugins
func (p *Plugin) GetPlugins() (plugins []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(TablePluginName))
if err != nil {
return
}
plugins = rs.Rows()
return
}
// get all plugins key map
func (p *Plugin) GetPluginsKeyMap() (pluginMaps map[string]map[string]string, err error) {
pluginMaps = make(map[string]map[string]string)
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(TablePluginName))
if err != nil {
return
}
plugins := rs.Rows()
for _, plugin := range plugins {
key, ok := plugin["key"]
if ok {
pluginMaps[key] = plugin
}
}
return
}
// get plugin by many plugin_id
func (p *Plugin) GetPluginByPluginIds(pluginIds []string) (plugins []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(TablePluginName).Where(map[string]interface{}{
"plugin_id": pluginIds,
}))
if err != nil {
return
}
plugins = rs.Rows()
return
}
// insert plugin
func (p *Plugin) Insert(insertValue map[string]interface{}) (id int64, err error) {
insertValue["create_time"] = time.Now().Unix()
insertValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(TablePluginName, insertValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get plugin by pluginKey
func (p *Plugin) GetPluginByKey(pluginKey string) (plugin map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(TablePluginName).Where(map[string]interface{}{
"plugin_key": pluginKey,
}).Limit(0, 1))
if err != nil {
return
}
plugin = rs.Row()
return
}
// get plugin value by plugin key
func (p *Plugin) GetConfValueByKey(pluginKey string, defaultValue string) (value string) {
pluginData, err := p.GetPluginByKey(pluginKey)
if err != nil {
return defaultValue
}
if len(pluginData) == 0 {
return defaultValue
}
if value, ok := pluginData["conf_value"]; ok {
return value
}
return defaultValue
}
// get plugin count
func (p *Plugin) CountPlugins() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(TablePluginName))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get role count by keyword
func (p *Plugin) CountPluginsByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(TablePluginName).
Where(map[string]interface{}{
"title LIKE": "%" + keyword + "%",
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
+249
View File
@@ -0,0 +1,249 @@
package models
import (
"fmt"
"github.com/snail007/go-activerecord/mysql"
"time"
)
type Privilege struct {
}
const Table_Privilege_Name = "privilege"
const (
Privilege_Type_Menu = "menu"
Privilege_Type_Controller = "controller"
Privilege_DisPlay_True = "1"
Privilege_DisPlay_False = "0"
)
var Privilege_Default_Ids = []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
var PrivilegeModel = Privilege{}
func (p *Privilege) GetTypePrivileges() (menus, controllers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).OrderBy("sequence", "ASC"))
if err != nil {
return
}
menus = []map[string]string{}
controllers = []map[string]string{}
for _, row := range rs.Rows() {
switch row["type"] {
case Privilege_Type_Menu:
menus = append(menus, row)
case Privilege_Type_Controller:
controllers = append(controllers, row)
}
}
return
}
func (p *Privilege) GetPrivileges() (privileges []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name))
if err != nil {
return
}
privileges = rs.Rows()
return
}
func (p *Privilege) GetPrivilegeByTypeControllerAndAction(ty, controller, action string) (privilege map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"type": ty,
"controller": controller,
"action": action,
}))
if err != nil {
return
}
privilege = rs.Row()
return
}
func (p *Privilege) GetTypePrivilegesByUserId(userId string) (menus, controllers []map[string]string, err error) {
user, err := UserModel.GetUserByUserId(userId)
if err != nil {
return
}
if len(user) == 0 {
return
}
roleId := user["role_id"]
if roleId == fmt.Sprintf("%d", Role_Root_Id) {
return PrivilegeModel.GetTypePrivileges()
}
rolePrivileges := []map[string]string{}
rolePrivileges, err = RolePrivilegeModel.GetRolePrivilegesByRoleId(roleId)
if err != nil {
return
}
var privilegeIds = []string{}
for _, rolePrivilege := range rolePrivileges {
privilegeIds = append(privilegeIds, rolePrivilege["privilege_id"])
}
return PrivilegeModel.GetTypePrivilegesByPrivilegeIds(privilegeIds)
}
func (p *Privilege) GetTypePrivilegesByDisplay(display string) (menus, controllers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"is_display": display,
}).OrderBy("sequence", "ASC"))
if err != nil {
return
}
menus = []map[string]string{}
controllers = []map[string]string{}
for _, row := range rs.Rows() {
switch row["type"] {
case Privilege_Type_Menu:
menus = append(menus, row)
case Privilege_Type_Controller:
controllers = append(controllers, row)
}
}
return
}
func (p *Privilege) GetTypePrivilegesByDisplayPrivilegeIds(display string, privilegeIds []string) (menus, controllers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"is_display": display,
"privilege_id": privilegeIds,
}).OrderBy("sequence", "ASC"))
if err != nil {
return
}
menus = []map[string]string{}
controllers = []map[string]string{}
for _, row := range rs.Rows() {
switch row["type"] {
case Privilege_Type_Menu:
menus = append(menus, row)
case Privilege_Type_Controller:
controllers = append(controllers, row)
}
}
return
}
func (p *Privilege) GetTypePrivilegesByPrivilegeIds(privilegeIds []string) (menus, controllers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"privilege_id": privilegeIds,
}).OrderBy("sequence", "ASC"))
if err != nil {
return
}
menus = []map[string]string{}
controllers = []map[string]string{}
for _, row := range rs.Rows() {
switch row["type"] {
case Privilege_Type_Menu:
menus = append(menus, row)
case Privilege_Type_Controller:
controllers = append(controllers, row)
}
}
return
}
func (p *Privilege) GetPrivilegeByPrivilegeId(privilegeId string) (privilege map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"privilege_id": privilegeId,
}))
if err != nil {
return
}
privilege = rs.Row()
return
}
func (p *Privilege) HasSub(privilegeId string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"parent_id": privilegeId,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
func (p *Privilege) Delete(privilegeId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_Privilege_Name, map[string]interface{}{
"privilege_id": privilegeId,
}))
if err != nil {
return
}
return
}
func (p *Privilege) Insert(privilege map[string]interface{}) (id int64, err error) {
privilege["create_time"] = time.Now().Unix()
privilege["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Privilege_Name, privilege))
if err != nil {
return
}
id = rs.LastInsertId
return
}
func (p *Privilege) InsertNotExists(privilege map[string]interface{}) (id int64, err error) {
privilege["create_time"] = time.Now().Unix()
privilege["update_time"] = time.Now().Unix()
db := G.DB()
rs, err := db.Query(db.AR().From(Table_Privilege_Name).Where(map[string]interface{}{
"type": privilege["type"],
"controller": privilege["controller"],
"action": privilege["action"],
}))
if rs.Len() == 0 {
rs, err = db.Exec(db.AR().Insert(Table_Privilege_Name, privilege))
if err != nil {
return
}
id = rs.LastInsertId
}
return
}
func (p *Privilege) Update(privilegeId string, privilege map[string]interface{}) (id int64, err error) {
privilege["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Update(Table_Privilege_Name, privilege, map[string]interface{}{
"privilege_id": privilegeId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
+317
View File
@@ -0,0 +1,317 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const (
Role_Delete_True = 1
Role_Delete_False = 0
Role_Type_System = 1
Role_Type_Default = 0
Role_Root_Id = 1 // 超级管理员
Role_Admin_Id = 2 // 管理员
Role_Default_Id = 3 // 普通用户
)
const Table_Role_Name = "role"
type Role struct {
}
var RoleModel = Role{}
// get role by role_id
func (r *Role) GetRoleByRoleId(roleId string) (role map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"role_id": roleId,
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
role = rs.Row()
return
}
// role_id and name is exists
func (r *Role) HasSameName(roleId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"role_id <>": roleId,
"name": name,
"is_delete": Role_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (r *Role) HasRoleName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"name": name,
"is_delete": Role_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get role by name
func (r *Role) GetRoleByName(name string) (role map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"name": name,
"is_delete": Role_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
role = rs.Row()
return
}
// delete role by role_id
func (r *Role) Delete(roleId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Update(Table_Role_Name, map[string]interface{}{
"is_delete": Role_Delete_True,
"update_time": time.Now().Unix(),
}, map[string]interface{}{
"role_id": roleId,
}))
if err != nil {
return
}
return
}
// insert role
func (r *Role) Insert(roleValue map[string]interface{}) (id int64, err error) {
roleValue["create_time"] = time.Now().Unix()
roleValue["update_time"] = time.Now().Unix()
db := G.DB()
tx, err := db.Begin(db.Config)
if err != nil {
return
}
var rs *mysql.ResultSet
rs, err = db.ExecTx(db.AR().Insert(Table_Role_Name, roleValue), tx)
if err != nil {
tx.Rollback()
return
}
id = rs.LastInsertId
// add default privileges
rolePrivileges := []map[string]interface{}{}
for _, privilegeId := range Privilege_Default_Ids {
rolePrivilege := map[string]interface{}{
"role_id": id,
"privilege_id": privilegeId,
"create_time": time.Now().Unix(),
}
rolePrivileges = append(rolePrivileges, rolePrivilege)
}
_, err = db.ExecTx(db.AR().InsertBatch(Table_RolePrivilege_Name, rolePrivileges), tx)
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
if err != nil {
return
}
return
}
// update role by role_id
func (r *Role) Update(roleId string, roleValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
roleValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Role_Name, roleValue, map[string]interface{}{
"role_id": roleId,
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit roles by search keyword
func (r *Role) GetRolesByKeywordAndLimit(keyword string, limit int, number int) (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
"is_delete": Role_Delete_False,
}).Limit(limit, number).OrderBy("role_id", "DESC"))
if err != nil {
return
}
roles = rs.Rows()
return
}
// get limit roles
func (r *Role) GetRolesByLimit(limit int, number int) (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Role_Name).
Where(map[string]interface{}{
"is_delete": Role_Delete_False,
}).
Limit(limit, number).
OrderBy("role_id", "DESC"))
if err != nil {
return
}
roles = rs.Rows()
return
}
// get all roles
func (r *Role) GetRoles() (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
roles = rs.Rows()
return
}
// get all roles not contain root
func (r *Role) GetRolesNotContainRoot() (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"role_id !=": Role_Root_Id,
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
roles = rs.Rows()
return
}
// get role count
func (r *Role) CountRoles() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Role_Name).
Where(map[string]interface{}{
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get role count by keyword
func (r *Role) CountRolesByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_Role_Name).
Where(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get role by name
func (r *Role) GetRoleByLikeName(name string) (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
"is_delete": Role_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
roles = rs.Rows()
return
}
// get role by many role_id
func (r *Role) GetRoleByRoleIds(roleIds []string) (roles []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"role_id": roleIds,
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
roles = rs.Rows()
return
}
// update role by name
func (r *Role) UpdateRoleByName(role map[string]interface{}) (affect int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
role["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Role_Name, role, map[string]interface{}{
"name": role["name"],
"is_delete": Role_Delete_False,
}))
if err != nil {
return
}
affect = rs.RowsAffected
return
}
+97
View File
@@ -0,0 +1,97 @@
package models
import (
"fmt"
"time"
)
var RolePrivilegeModel = RolePrivilege{}
const Table_RolePrivilege_Name = "role_privilege"
type RolePrivilege struct {
}
func (rolePrivilege *RolePrivilege) GetRolePrivilegesByRoleId(roleId string) (rolePrivileges []map[string]string, err error) {
db := G.DB()
res, err := db.Query(db.AR().From(Table_RolePrivilege_Name).Where(map[string]interface{}{
"role_id": roleId,
}))
if err != nil {
return
}
rolePrivileges = res.Rows()
return
}
func (rolePrivilege *RolePrivilege) GetRootRolePrivileges() (rolePrivileges []map[string]string, err error) {
privileges, err := PrivilegeModel.GetPrivileges()
if err != nil {
return
}
for _, privilege := range privileges {
rolePrivilege := map[string]string{
"role_privilege_id": "",
"role_id": fmt.Sprintf("%d", Role_Root_Id),
"privilege_id": privilege["privilege_id"],
}
rolePrivileges = append(rolePrivileges, rolePrivilege)
}
return
}
func (rolePrivilege *RolePrivilege) GrantRolePrivileges(roleId string, privilegeIds []string) (res bool, err error) {
res = false
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_RolePrivilege_Name, map[string]interface{}{
"role_id": roleId,
}))
if err != nil {
return
}
rolePrivileges := []map[string]interface{}{}
for _, privilegeId := range privilegeIds {
rolePrivilege := map[string]interface{}{
"role_id": roleId,
"privilege_id": privilegeId,
"create_time": time.Now().Unix(),
}
rolePrivileges = append(rolePrivileges, rolePrivilege)
}
_, err = db.Exec(db.AR().InsertBatch(Table_RolePrivilege_Name, rolePrivileges))
if err != nil {
return
}
res = true
return
}
// delete role privilege by role_id
func (rolePrivilege *RolePrivilege) DeleteByRoleId(roleId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_RolePrivilege_Name, map[string]interface{}{
"role_id": roleId,
}))
if err != nil {
return
}
return
}
// delete role privilege by privilege_id
func (rolePrivilege *RolePrivilege) DeleteByPrivilegeId(privilegeId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_RolePrivilege_Name, map[string]interface{}{
"privilege_id": privilegeId,
}))
if err != nil {
return
}
return
}
+400
View File
@@ -0,0 +1,400 @@
package models
import (
"fmt"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const (
Space_Share_False = 0
Space_Share_True = 1
Space_Download_False = 0
Space_Download_True = 1
Space_Delete_True = 1
Space_Delete_False = 0
Space_Root_Id = 1
Space_Admin_Id = 2
Space_Default_Id = 3
Space_VisitLevel_Public = "public"
Space_VisitLevel_Private = "private"
)
const Table_Space_Name = "space"
type Space struct {
}
var SpaceModel = Space{}
// get space by space_id
func (s *Space) GetSpaceBySpaceId(spaceId string) (space map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"space_id": spaceId,
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
space = rs.Row()
return
}
// space_id and name is exists
func (s *Space) HasSameName(spaceId, name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"space_id <>": spaceId,
"name": name,
"is_delete": Space_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// name is exists
func (s *Space) HasSpaceName(name string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"name": name,
"is_delete": Space_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get space by name
func (s *Space) GetSpaceByName(name string) (space map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"name": name,
"is_delete": Space_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
space = rs.Row()
return
}
// delete space by space_id
func (s *Space) Delete(spaceId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Update(Table_Space_Name, map[string]interface{}{
"is_delete": Space_Delete_True,
"update_time": time.Now().Unix(),
}, map[string]interface{}{
"space_id": spaceId,
}))
if err != nil {
return
}
// delete collect space
go func() {
CollectionModel.DeleteByResourceIdType(spaceId, fmt.Sprintf("%d", Collection_Type_Space))
}()
return
}
// insert space
func (s *Space) Insert(spaceValue map[string]interface{}) (id int64, err error) {
spaceValue["create_time"] = time.Now().Unix()
spaceValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_Space_Name, spaceValue))
if err != nil {
return
}
id = rs.LastInsertId
return id, nil
}
// update space by space_id
func (s *Space) Update(spaceId string, spaceValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
spaceValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Space_Name, spaceValue, map[string]interface{}{
"space_id": spaceId,
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update space db and file name by space_id
func (s *Space) UpdateDBAndSpaceFileName(spaceId string, spaceValue map[string]interface{}, oldName string) (id int64, err error) {
// begin update
db := G.DB()
tx, err := db.Begin(db.Config)
if err != nil {
return
}
var rs *mysql.ResultSet
// get real old space name (v0.1.2 #53 bug)
defaultDocument, err := DocumentModel.GetDocumentByParentIdAndSpaceId("0", spaceId, Document_Type_Dir)
if err != nil {
return
}
if oldName != defaultDocument["name"] {
oldName = defaultDocument["name"]
}
// update space db
spaceValue["update_time"] = time.Now().Unix()
rs, err = db.ExecTx(db.AR().Update(Table_Space_Name, spaceValue, map[string]interface{}{
"space_id": spaceId,
"is_delete": Space_Delete_False,
}), tx)
if err != nil {
tx.Rollback()
return
}
id = rs.LastInsertId
documentValue := map[string]interface{}{
"name": spaceValue["name"],
"update_time": time.Now().Unix(),
}
// update space document name
_, err = db.ExecTx(db.AR().Update(Table_Document_Name, documentValue, map[string]interface{}{
"space_id": spaceId,
"parent_id": 0,
"type": Document_Type_Dir,
}), tx)
if err != nil {
tx.Rollback()
return
}
// update space name
err = utils.Document.UpdateSpaceName(oldName, spaceValue["name"].(string))
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
return
}
// get limit spaces by search keyword
func (s *Space) GetSpacesByKeywordAndLimit(keyword string, limit int, number int) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"is_delete": Space_Delete_False,
}).WhereWrap(map[string]interface{}{
"name LIKE": "%" + keyword + "%",
}, "AND (", "").WhereWrap(map[string]interface{}{
"description LIKE": "%" + keyword + "%",
}, "OR", ")").Limit(limit, number).OrderBy("space_id", "DESC")
rs, err = db.Query(sql)
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get limit spaces
func (s *Space) GetSpacesByLimit(limit int, number int) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_Space_Name).
Where(map[string]interface{}{
"is_delete": Space_Delete_False,
}).
Limit(limit, number).
OrderBy("space_id", "DESC"))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get all spaces
func (s *Space) GetSpaces() (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get spaces by visitLevel
func (s *Space) GetSpacesByVisitLevel(visitLevel string) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"visit_level": visitLevel,
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get space count
func (s *Space) CountSpaces() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Space_Name).
Where(map[string]interface{}{
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get space count
func (s *Space) CountSpacesByTags(tag string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_Space_Name).
Where(map[string]interface{}{
"tags LIKE": "%" + tag + "%",
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get space count by keyword
func (s *Space) CountSpacesByKeyword(keyword string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
sql := db.AR().Select("count(*) as total").From(Table_Space_Name).
Where(map[string]interface{}{"is_delete": Space_Delete_False}).
WhereWrap(map[string]interface{}{"name LIKE": "%" + keyword + "%"}, "AND (", "").
WhereWrap(map[string]interface{}{"description LIKE": "%" + keyword + "%"}, "OR", ")")
rs, err = db.Query(sql)
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
// get space count by tags
func (s *Space) GetSpacesByTags(tag string) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"tags LIKE": "%" + tag + "%",
"is_delete": Space_Delete_False,
}).OrderBy("space_id", "DESC"))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get space by name
func (s *Space) GetSpaceByLikeName(name string) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"name Like": "%" + name + "%",
"is_delete": Space_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// get space by many space_id
func (s *Space) GetSpaceBySpaceIds(spaceIds []string) (spaces []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Space_Name).Where(map[string]interface{}{
"space_id": spaceIds,
"is_delete": Space_Delete_False,
}))
if err != nil {
return
}
spaces = rs.Rows()
return
}
// update space by name
func (s *Space) UpdateSpaceByName(space map[string]interface{}) (affect int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
space["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_Space_Name, space, map[string]interface{}{
"name": space["name"],
}))
if err != nil {
return
}
affect = rs.RowsAffected
return
}
+236
View File
@@ -0,0 +1,236 @@
package models
import (
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"time"
)
const Table_SpaceUser_Name = "space_user"
const (
SpaceUser_Privilege_Visitor = 0
SpaceUser_Privilege_Editor = 1
SpaceUser_Privilege_Manager = 2
)
type SpaceUser struct {
}
var SpaceUserModel = SpaceUser{}
// get space_user by space_user_id
func (s *SpaceUser) GetSpaceUserBySpaceUserId(spaceUserId string) (spaceUser map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"space_user_id": spaceUserId,
}))
if err != nil {
return
}
spaceUser = rs.Row()
return
}
// get space_user by name
func (s *SpaceUser) GetSpaceUsersByUserId(userId string) (spaceUsers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
spaceUsers = rs.Rows()
return
}
// get space_user by name
func (s *SpaceUser) GetSpaceUsersBySpaceId(spaceId string) (spaceUsers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"space_id": spaceId,
}))
if err != nil {
return
}
spaceUsers = rs.Rows()
return
}
// get space_user count by keyword
func (s *SpaceUser) GetSpaceUserBySpaceIdAndUserId(spaceId string, userId string) (spaceUser map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"space_id": spaceId,
"user_id": userId,
}).Limit(0, 1))
if err != nil {
return
}
spaceUser = rs.Row()
return
}
// delete space_user by space_user_id
func (s *SpaceUser) Delete(spaceUserId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_SpaceUser_Name, map[string]interface{}{
"space_user_id": spaceUserId,
}))
if err != nil {
return
}
return
}
// delete space_user by space_user_id
func (s *SpaceUser) DeleteBySpaceId(spaceId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_SpaceUser_Name, map[string]interface{}{
"space_id": spaceId,
}))
if err != nil {
return
}
return
}
// delete space_user by space_user_id
func (s *SpaceUser) DeleteByUserId(userId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_SpaceUser_Name, map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
return
}
// delete space_user by space_id and user_id
func (s *SpaceUser) DeleteBySpaceIdAndUserId(spaceId string, userId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Delete(Table_SpaceUser_Name, map[string]interface{}{
"space_id": spaceId,
"user_id": userId,
}))
if err != nil {
return
}
return
}
// insert space_user
func (s *SpaceUser) Insert(spaceUserValue map[string]interface{}) (id int64, err error) {
spaceUserValue["create_time"] = time.Now().Unix()
spaceUserValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_SpaceUser_Name, spaceUserValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update space_user by space_user_id
func (s *SpaceUser) Update(spaceUserId string, spaceUserValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
spaceUserValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_SpaceUser_Name, spaceUserValue, map[string]interface{}{
"space_user_id": spaceUserId,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// get limit space_users by spaceId
func (s *SpaceUser) GetSpaceUsersBySpaceIdAndLimit(spaceId string, limit int, number int) (spaceUsers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"space_id": spaceId,
}).Limit(limit, number))
if err != nil {
return
}
spaceUsers = rs.Rows()
return
}
// get all space_users
func (s *SpaceUser) GetSpaceUsers() (spaceUsers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().From(Table_SpaceUser_Name))
if err != nil {
return
}
spaceUsers = rs.Rows()
return
}
// get space_user count by keyword
func (s *SpaceUser) CountSpaceUsersBySpaceId(spaceId string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().
Select("count(*) as total").
From(Table_SpaceUser_Name).
Where(map[string]interface{}{
"space_id": spaceId,
}))
if err != nil {
return
}
count = utils.Convert.StringToInt64(rs.Value("total"))
return
}
// get space_user by many space_user_id
func (s *SpaceUser) GetSpaceUsersBySpaceUserIds(spaceUserIds []string) (spaceUsers []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_SpaceUser_Name).Where(map[string]interface{}{
"space_user_id": spaceUserIds,
}))
if err != nil {
return
}
spaceUsers = rs.Rows()
return
}
// space user is exists
func (s *SpaceUser) HasSpaceUser(spaceId string, userId string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_Role_Name).Where(map[string]interface{}{
"space_id": spaceId,
"user_id": userId,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
+254
View File
@@ -0,0 +1,254 @@
package models
import (
"database/sql"
"errors"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app/utils"
"github.com/phachon/mm-wiki/global"
"time"
)
type Upgrade struct {
}
type upgradeHandleFunc func() error
type upgradeHandle struct {
Version string
Func upgradeHandleFunc
}
var (
UpgradeModel = Upgrade{}
upgradeMap = []*upgradeHandle{}
)
// upgrade handle func
func (up *Upgrade) initHandleFunc() {
// v0 ~ v0.1.2
upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.1.2", Func: up.v0ToV012})
// v0.1.2 ~ v0.1.3
upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.1.3", Func: up.v012ToV013})
// v0.1.3 ~ v0.1.8
upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.1.8", Func: up.v013ToV018})
// v0.1.8 ~ v0.2.0
upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.2.0", Func: up.v018ToV020})
// v0.2.1 ~ v0.2.7
//upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.2.7", Func: up.v021ToV027})
// v0.2.7 ~ v0.3.3
//upgradeMap = append(upgradeMap, &upgradeHandle{Version: "v0.3.3", Func: up.v027ToV033})
}
// upgrade start
func (up *Upgrade) Start(dbVersion string) (err error) {
up.initHandleFunc()
var tmpVersion = dbVersion
for _, upHandle := range upgradeMap {
// upgrade now version, exit
if tmpVersion == global.SYSTEM_VERSION {
break
}
// tmpVersion < upHandle.version
if utils.VersionCompare.Lt(tmpVersion, upHandle.Version) {
// upgrade handle
err = upHandle.Func()
if err != nil {
logs.Error("upgrade to " + upHandle.Version + " error: " + err.Error())
return errors.New("upgrade to " + upHandle.Version + " error: " + err.Error())
}
// update system database version
err = up.upgradeAfter(upHandle.Version)
if err != nil {
logs.Error("upgrade to database " + upHandle.Version + " error: " + err.Error())
return errors.New("upgrade to database " + upHandle.Version + " error: " + err.Error())
}
logs.Info("upgrade to " + upHandle.Version + " success")
// update version record
tmpVersion = upHandle.Version
}
}
// last update current version
err = up.upgradeAfter(global.SYSTEM_VERSION)
if err != nil {
logs.Error("upgrade to database " + global.SYSTEM_VERSION + " error: " + err.Error())
return errors.New("upgrade to database " + global.SYSTEM_VERSION + " error: " + err.Error())
}
logs.Info("upgrade finish, version: " + global.SYSTEM_VERSION)
return nil
}
// upgrade v0.0.0 ~ v0.1.2
func (up *Upgrade) v0ToV012() (err error) {
// 1. add privilege '/email/test'
// INSERT INTO mw_privilege (name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES ('测试邮件服务器', 53, 'controller', 'email', 'test', 'glyphicon-list', 0, 80, unix_timestamp(now()), unix_timestamp(now()));
privilege := map[string]interface{}{
"name": "测试邮件服务器",
"type": "controller",
"parent_id": 53,
"controller": "email",
"action": "test",
"target": "",
"icon": "glyphicon-list",
"is_display": 0,
"sequence": 80,
}
_, err = PrivilegeModel.InsertNotExists(privilege)
if err != nil {
return
}
// 2. table mw_email add field 'is_ssl'
// alter table mw_email add `is_ssl` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用ssl 0 默认不使用 1 使用' after `password`
db := G.DB()
db.Exec(db.AR().Raw("alter table mw_email DROP COLUMN `is_ssl`"))
_, err = db.Exec(db.AR().Raw("alter table mw_email add `is_ssl` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用ssl 0 默认不使用 1 使用' after `password`"))
return
}
// upgrade v0.1.2 ~ v0.1.3
func (up *Upgrade) v012ToV013() error {
// create attachment table
sql := "DROP TABLE IF EXISTS `mw_attachment`;" +
"CREATE TABLE `mw_attachment` (" +
"`attachment_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '附件 id'," +
"`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '创建用户id'," +
"`document_id` int(10) NOT NULL DEFAULT '0' COMMENT '所属文档id'," +
"`name` varchar(50) NOT NULL DEFAULT '' COMMENT '附件名称'," +
"`path` varchar(100) NOT NULL DEFAULT '' COMMENT '附件路径'," +
"`source` tinyint(1) NOT NULL DEFAULT '0' COMMENT '附件来源, 0 默认是附件 1 图片'," +
"`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间'," +
"`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间'," +
"PRIMARY KEY (`attachment_id`)," +
"KEY (`document_id`, `source`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='附件信息表';"
return up.createTable(sql)
}
// upgrade v0.1.3 ~ v0.1.8
func (up *Upgrade) v013ToV018() error {
db := G.DB()
// 1. 文档日志表增加 space_id 字段
// `space_id` int(10) NOT NULL DEFAULT '0' COMMENT '空间id'
_, err := db.Exec(db.AR().Raw("alter table mw_log_document add `space_id` int(10) NOT NULL DEFAULT '0' COMMENT '空间ID'"))
if err == nil {
// 文档日志表里的 space_id
_, err = db.Exec(db.AR().Raw("update mw_log_document as logDocment, mw_document as document set logDocment.space_id = document.space_id WHERE logDocment.document_id = document.document_id"))
if err != nil {
return err
}
}
// 2. 修改文档表里的排序号,需要先判断排序号是否已经修改过(只修改sequence=0)
_, err = db.Exec(db.AR().Raw("update mw_document set mw_document.sequence = mw_document.document_id WHERE sequence=0"))
if err != nil {
return err
}
return nil
}
// upgrade v0.1.8 ~ v0.2.0
func (up *Upgrade) v018ToV020() error {
// 配置表增加数据
db := G.DB()
updateTime := time.Now().Unix()
// 1. 配置表增加全文搜索开关
insertSql := fmt.Sprintf("INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('开启全文搜索', 'fulltext_search_open', '1', %d, %d)", updateTime, updateTime)
_, err := db.Exec(db.AR().Raw(insertSql))
if err != nil {
return err
}
// 2. 配置表增加搜索索引时间间隔
insertSql = fmt.Sprintf("INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('索引更新间隔', 'doc_search_timer', '3600', %d, %d)", updateTime, updateTime)
_, err = db.Exec(db.AR().Raw(insertSql))
if err != nil {
return err
}
// 3. 配置表增加系统名称配置
insertSql = fmt.Sprintf("INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('系统名称', 'system_name', 'Markdown Mini Wiki', %d, %d)", updateTime, updateTime)
_, err = db.Exec(db.AR().Raw(insertSql))
if err != nil {
return err
}
// 4. 权限表增加导入联系人权限
// INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (93, '导入联系人', 71, 'controller', 'contact', 'import', 'glyphicon-list', '', 0, 97, unix_timestamp(now()), unix_timestamp(now()));
privilege := map[string]interface{}{
"name": "导入联系人",
"type": "controller",
"parent_id": 71,
"controller": "contact",
"action": "import",
"target": "",
"icon": "glyphicon-list",
"is_display": 0,
"sequence": 97,
}
_, err = PrivilegeModel.InsertNotExists(privilege)
if err != nil {
return err
}
return nil
}
// upgrade v0.2.1 ~ v0.2.7
func (up *Upgrade) v021ToV027() error {
return nil
}
// upgrade v0.2.7 ~ v0.3.3
func (up *Upgrade) v027ToV033() error {
return nil
}
func (up *Upgrade) createTable(sqlTable string) error {
host := beego.AppConfig.String("db::host")
port, _ := beego.AppConfig.Int("db::port")
user := beego.AppConfig.String("db::user")
pass := beego.AppConfig.String("db::pass")
name := beego.AppConfig.String("db::name")
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&multiStatements=true", user, pass, host, port, name))
if err != nil {
return err
}
defer db.Close()
_, err = db.Exec(sqlTable)
if err != nil {
return err
}
return nil
}
func (up *Upgrade) upgradeAfter(version string) (err error) {
// update system version
config, err := ConfigModel.GetConfigByKey(ConfigKeySystemVersion)
if err != nil {
return
}
if len(config) == 0 {
configValue := map[string]interface{}{
"name": "系统版本号",
"key": "system_version",
"value": version,
}
_, err = ConfigModel.Insert(configValue)
} else {
_, err = ConfigModel.UpdateByKey(ConfigKeySystemVersion, version)
}
return err
}
+408
View File
@@ -0,0 +1,408 @@
package models
import (
"crypto/md5"
"encoding/hex"
"errors"
"github.com/phachon/mm-wiki/app/utils"
"github.com/snail007/go-activerecord/mysql"
"strings"
"time"
)
const (
User_Delete_True = 1
User_Delete_False = 0
User_Forbidden_True = 1
User_Is_Forbidden_False = 0
)
const Table_User_Name = "user"
type User struct {
}
var UserModel = User{}
// get user by user_id
func (u *User) GetUserByUserId(userId string) (user map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"user_id": userId,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
user = rs.Row()
return
}
// user_id and username is exists
func (u *User) HasSameUsername(userId, username string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"user_id <>": userId,
"username": username,
"is_delete": User_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// username is exists
func (u *User) HasUsername(username string) (has bool, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"username": username,
"is_delete": User_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
if rs.Len() > 0 {
has = true
}
return
}
// get user by username
func (u *User) GetUserByUsername(username string) (user map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"username": username,
"is_delete": User_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
user = rs.Row()
return
}
// delete user by user_id
func (u *User) Delete(userId string) (err error) {
db := G.DB()
_, err = db.Exec(db.AR().Update(Table_User_Name, map[string]interface{}{
"is_delete": User_Delete_False,
"update_time": time.Now().Unix(),
}, map[string]interface{}{
"user_id": userId,
}))
if err != nil {
return
}
return
}
// insert user
func (u *User) Insert(userValue map[string]interface{}) (id int64, err error) {
userValue["create_time"] = time.Now().Unix()
userValue["update_time"] = time.Now().Unix()
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Exec(db.AR().Insert(Table_User_Name, userValue))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update user by user_id
func (u *User) Update(userId string, userValue map[string]interface{}) (id int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
userValue["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_User_Name, userValue, map[string]interface{}{
"user_id": userId,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
id = rs.LastInsertId
return
}
// update user password
func (u *User) ChangePassword(userId, newPassword, oldPassword string) (err error) {
db := G.DB()
userValue, err := u.GetUserByUserId(userId)
if userValue["password"] != u.EncodePassword(oldPassword) {
return errors.New("旧密码错误")
}
if err != nil {
return
}
_, err = db.Exec(db.AR().Update(Table_User_Name, map[string]interface{}{
"password": u.EncodePassword(newPassword),
"update_time": time.Now().Unix(),
}, map[string]interface{}{
"user_id": userId,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
return
}
// encode password
func (u *User) EncodePassword(password string) (passwordHash string) {
hasher := md5.New()
hasher.Write([]byte(password))
passwordHash = strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
return
}
// get limit users by search keyword
func (u *User) GetUsersByKeywordsAndLimit(keywords map[string]string, limit int, number int) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
var whereValue = map[string]interface{}{
"is_delete": User_Delete_False,
}
username, ok := keywords["username"]
if ok && username != "" {
whereValue["username LIKE"] = "%" + username + "%"
}
roleId, ok := keywords["role_id"]
if ok && roleId != "" {
whereValue["role_id"] = roleId
}
rs, err = db.Query(db.AR().From(Table_User_Name).Where(whereValue).Limit(limit, number).OrderBy("user_id", "DESC"))
if err != nil {
return
}
users = rs.Rows()
return
}
// get limit users
func (u *User) GetUsersByLimit(limit int, number int) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
From(Table_User_Name).
Where(map[string]interface{}{
"is_delete": User_Delete_False,
}).
Limit(limit, number).
OrderBy("user_id", "DESC"))
if err != nil {
return
}
users = rs.Rows()
return
}
// get user count
func (u *User) CountUsers() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_User_Name).
Where(map[string]interface{}{
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get user count by lastTime
func (u *User) CountUsersByLastTime(lastTime int64) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_User_Name).
Where(map[string]interface{}{
"last_time >=": lastTime,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get normal user count
func (u *User) CountNormalUsers() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_User_Name).
Where(map[string]interface{}{
"is_forbidden": User_Is_Forbidden_False,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get forbidden user count
func (u *User) CountForbiddenUsers() (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(
db.AR().
Select("count(*) as total").
From(Table_User_Name).
Where(map[string]interface{}{
"is_forbidden": User_Forbidden_True,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get user count by keyword
func (u *User) CountUsersByKeywords(keywords map[string]string) (count int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
var whereValue = map[string]interface{}{
"is_delete": User_Delete_False,
}
username, ok := keywords["username"]
if ok && username != "" {
whereValue["username LIKE"] = "%" + username + "%"
}
roleId, ok := keywords["role_id"]
if ok && roleId != "" {
whereValue["role_id"] = roleId
}
rs, err = db.Query(db.AR().Select("count(*) as total").From(Table_User_Name).Where(whereValue))
if err != nil {
return
}
count = utils.NewConvert().StringToInt64(rs.Value("total"))
return
}
// get user by username
func (u *User) GetUserByLikeName(username string) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"username Like": "%" + username + "%",
"is_delete": User_Delete_False,
}).Limit(0, 1))
if err != nil {
return
}
users = rs.Rows()
return
}
// get user by many user_id
func (u *User) GetUsersByUserIds(userIds []string) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"user_id": userIds,
"is_delete": User_Delete_False,
}).OrderBy("user_id", "DESC"))
if err != nil {
return
}
users = rs.Rows()
return
}
// get user by many user_id
func (u *User) GetUsersByRoleId(roleId string) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"role_id": roleId,
"is_delete": User_Delete_False,
}).OrderBy("user_id", "DESC"))
if err != nil {
return
}
users = rs.Rows()
return
}
// get user by not in user_ids
func (u *User) GetUserByNotUserIds(userIds []string) (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"user_id NOT": userIds,
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
users = rs.Rows()
return
}
// get all users
func (u *User) GetUsers() (users []map[string]string, err error) {
db := G.DB()
var rs *mysql.ResultSet
rs, err = db.Query(db.AR().From(Table_User_Name).Where(map[string]interface{}{
"is_delete": User_Delete_False,
}))
if err != nil {
return
}
users = rs.Rows()
return
}
// update user by username
func (u *User) UpdateUserByUsername(user map[string]interface{}) (affect int64, err error) {
db := G.DB()
var rs *mysql.ResultSet
user["update_time"] = time.Now().Unix()
rs, err = db.Exec(db.AR().Update(Table_User_Name, user, map[string]interface{}{
"username": user["username"],
}))
if err != nil {
return
}
affect = rs.RowsAffected
return
}
+259
View File
@@ -0,0 +1,259 @@
package controllers
import (
"github.com/phachon/mm-wiki/app/services"
"net/url"
"strings"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/astaxie/beego/validation"
)
type AuthController struct {
BaseController
}
func (this *AuthController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var auths []map[string]string
if keyword != "" {
count, err = models.AuthModel.CountAuthsByKeyword(keyword)
auths, err = models.AuthModel.GetAuthsByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.AuthModel.CountAuths()
auths, err = models.AuthModel.GetAuthsByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取登录认证列表失败: " + err.Error())
this.ViewError("获取登录认证列表失败", "/system/main/index")
}
this.Data["auths"] = auths
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("auth/list", "auth")
}
func (this *AuthController) Add() {
this.viewLayout("auth/form", "auth")
}
func (this *AuthController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/auth/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
authUrl := strings.TrimSpace(this.GetString("url", ""))
usernamePrefix := strings.TrimSpace(this.GetString("username_prefix", ""))
extData := strings.TrimSpace(this.GetString("ext_data", ""))
v := validation.Validation{}
if name == "" {
this.jsonError("登录认证名称不能为空!")
}
if usernamePrefix == "" {
this.jsonError("用户名前缀不能为空!")
}
if !v.AlphaNumeric(usernamePrefix, "username_prefix").Ok {
this.jsonError("用户名前缀格式不正确!")
}
if authUrl == "" {
this.jsonError("认证URL不能为空!")
}
u, err := url.Parse(authUrl)
if err != nil || u == nil {
this.jsonError("认证 URL 解析错误!")
return
}
if !services.AuthLogin.UrlIsSupport(u.Scheme) {
this.jsonError("认证 URL 协议不支持!")
}
ok, err := models.AuthModel.HasAuthName(name)
if err != nil {
this.ErrorLog("添加登录认证失败:" + err.Error())
this.jsonError("添加登录认证失败!")
}
if ok {
this.jsonError("登录认证名称已经存在!")
}
ok, err = models.AuthModel.HasAuthUsernamePrefix(usernamePrefix)
if err != nil {
this.ErrorLog("添加登录认证失败:" + err.Error())
this.jsonError("添加登录认证失败!")
}
if ok {
this.jsonError("用户名前缀已经存在!")
}
authId, err := models.AuthModel.Insert(map[string]interface{}{
"name": name,
"url": authUrl,
"username_prefix": usernamePrefix,
"ext_data": extData,
})
if err != nil {
this.ErrorLog("添加登录认证失败:" + err.Error())
this.jsonError("添加登录认证失败")
}
this.InfoLog("添加登录认证 " + utils.Convert.IntToString(authId, 10) + " 成功")
this.jsonSuccess("添加登录认证成功", nil, "/system/auth/list")
}
func (this *AuthController) Edit() {
authId := this.GetString("login_auth_id", "")
if authId == "" {
this.ViewError("登录认证不存在", "/system/auth/list")
}
auth, err := models.AuthModel.GetAuthByAuthId(authId)
if err != nil {
this.ViewError("登录认证不存在", "/system/auth/list")
}
this.Data["auth"] = auth
this.viewLayout("auth/form", "auth")
}
func (this *AuthController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/auth/list")
}
authId := this.GetString("login_auth_id", "")
name := strings.TrimSpace(this.GetString("name", ""))
authUrl := strings.TrimSpace(this.GetString("url", ""))
usernamePrefix := strings.TrimSpace(this.GetString("username_prefix", ""))
extData := strings.TrimSpace(this.GetString("ext_data", ""))
v := validation.Validation{}
if authId == "" {
this.jsonError("登录认证不存在!")
}
if name == "" {
this.jsonError("登录认证名称不能为空!")
}
if usernamePrefix == "" {
this.jsonError("用户名前缀不能为空!")
}
if !v.AlphaNumeric(usernamePrefix, "username_prefix").Ok {
this.jsonError("用户名前缀格式不正确!")
}
if authUrl == "" {
this.jsonError("认证URL不能为空!")
}
u, err := url.Parse(authUrl)
if err != nil || u == nil {
this.jsonError("认证 URL 解析错误!")
return
}
if !services.AuthLogin.UrlIsSupport(u.Scheme) {
this.jsonError("认证 URL 协议不支持!")
}
auth, err := models.AuthModel.GetAuthByAuthId(authId)
if err != nil {
this.ErrorLog("修改登录认证 " + authId + " 失败: " + err.Error())
this.jsonError("修改登录认证失败!")
}
if len(auth) == 0 {
this.jsonError("登录认证不存在!")
}
ok, _ := models.AuthModel.HasSameName(authId, name)
if ok {
this.jsonError("登录认证名称已经存在!")
}
ok, _ = models.AuthModel.HasSameUsernamePrefix(authId, usernamePrefix)
if ok {
this.jsonError("用户名前缀已经存在!")
}
_, err = models.AuthModel.Update(authId, map[string]interface{}{
"name": name,
"url": authUrl,
"username_prefix": usernamePrefix,
"ext_data": extData,
})
if err != nil {
this.ErrorLog("修改登录认证 " + authId + " 失败:" + err.Error())
this.jsonError("修改登录认证失败")
}
this.InfoLog("修改登录认证 " + authId + " 成功")
this.jsonSuccess("修改登录认证成功", nil, "/system/auth/list")
}
func (this *AuthController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/auth/list")
}
authId := this.GetString("login_auth_id", "")
if authId == "" {
this.jsonError("没有选择登录认证!")
}
auth, err := models.AuthModel.GetAuthByAuthId(authId)
if err != nil {
this.ErrorLog("删除登录认证 " + authId + " 失败: " + err.Error())
this.jsonError("删除登录认证失败")
}
if len(auth) == 0 {
this.jsonError("登录认证不存在")
}
err = models.AuthModel.Delete(authId)
if err != nil {
this.ErrorLog("删除登录认证 " + authId + " 失败: " + err.Error())
this.jsonError("删除登录认证失败")
}
this.InfoLog("删除登录认证 " + authId + " 成功")
this.jsonSuccess("删除登录认证成功", nil, "/system/auth/list")
}
func (this *AuthController) Used() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/auth/list")
}
authId := this.GetString("login_auth_id", "")
if authId == "" {
this.jsonError("没有选择登录认证!")
}
auth, err := models.AuthModel.GetAuthByAuthId(authId)
if err != nil {
this.ErrorLog("登录认证 " + authId + " 启用失败: " + err.Error())
this.jsonError("登录认证启用失败")
}
if len(auth) == 0 {
this.jsonError("登录认证不存在")
}
_, err = models.AuthModel.SetAuthUsed(authId)
if err != nil {
this.ErrorLog("登录认证 " + authId + " 启用失败: " + err.Error())
this.jsonError("登录认证启用失败")
}
this.InfoLog("启用登录认证 " + authId + " 成功")
this.jsonSuccess("启用登录认证成功", nil, "/system/auth/list")
}
func (this *AuthController) Doc() {
this.viewLayout("auth/doc", "auth")
}
+26
View File
@@ -0,0 +1,26 @@
package controllers
import (
"github.com/phachon/mm-wiki/app/controllers"
)
type BaseController struct {
controllers.TemplateController
}
// view layout
func (this *BaseController) viewLayout(viewName, layout string) {
viewName = "system/" + viewName
layout = "system/layouts/" + layout
this.ViewLayout(viewName, layout)
}
// return json success
func (this *BaseController) jsonSuccess(message interface{}, data ...interface{}) {
this.JsonSuccess(message, data...)
}
// return json error
func (this *BaseController) jsonError(message interface{}, data ...interface{}) {
this.JsonError(message, data...)
}
+147
View File
@@ -0,0 +1,147 @@
package controllers
import (
"fmt"
"github.com/phachon/mm-wiki/app/work"
"strings"
"github.com/phachon/mm-wiki/app/models"
)
type ConfigController struct {
BaseController
}
func (this *ConfigController) Global() {
configs, err := models.ConfigModel.GetConfigs()
if err != nil {
this.ErrorLog("获取全局配置失败: " + err.Error())
this.ViewError("邮件服务器不存在", "/system/main/index")
}
var configValue = map[string]string{}
for _, config := range configs {
if config["key"] == models.ConfigKeyAutoFollowdoc && config["value"] != "1" {
config["value"] = "0"
}
if config["key"] == models.ConfigKeySendEmail && config["value"] != "1" {
config["value"] = "0"
}
if config["key"] == models.ConfigKeyAuthLogin && config["value"] != "1" {
config["value"] = "0"
}
configValue[config["key"]] = config["value"]
}
this.Data["configValue"] = configValue
this.viewLayout("config/form", "config")
}
func (this *ConfigController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
mainTitle := this.GetString(models.ConfigKeyMainTitle, "")
mainDescription := strings.TrimSpace(this.GetString(models.ConfigKeyMainDescription, ""))
autoFollowDocOpen := strings.TrimSpace(this.GetString(models.ConfigKeyAutoFollowdoc, "0"))
sendEmailOpen := strings.TrimSpace(this.GetString(models.ConfigKeySendEmail, "0"))
ssoOpen := strings.TrimSpace(this.GetString(models.ConfigKeyAuthLogin, "0"))
fulltextSearch := strings.TrimSpace(this.GetString(models.ConfigKeyFulltextSearch, "0"))
docSearchTimer := strings.TrimSpace(this.GetString(models.ConfigKeyDocSearchTimer, "3600"))
systemName := strings.TrimSpace(this.GetString(models.ConfigKeySystemName, "Markdown Mini Wiki"))
if sendEmailOpen == "1" {
email, err := models.EmailModel.GetUsedEmail()
if err != nil {
this.ErrorLog("获取可用的邮箱配置失败: " + err.Error())
this.jsonError("配置出错!")
}
if len(email) == 0 {
this.jsonError("开启邮件通知必须先启用一个邮件服务器配置!")
}
}
if ssoOpen == "1" {
auth, err := models.AuthModel.GetUsedAuth()
if err != nil {
this.ErrorLog("获取可用的登录认证失败: " + err.Error())
this.jsonError("配置出错!")
}
if len(auth) == 0 {
this.jsonError("开启统一登录必须先添加并启用一个登录认证!")
}
}
updateValues := map[string]string{
models.ConfigKeyMainTitle: mainTitle,
models.ConfigKeyMainDescription: mainDescription,
models.ConfigKeyAutoFollowdoc: autoFollowDocOpen,
models.ConfigKeySendEmail: sendEmailOpen,
models.ConfigKeyAuthLogin: ssoOpen,
models.ConfigKeyFulltextSearch: fulltextSearch,
models.ConfigKeyDocSearchTimer: docSearchTimer,
models.ConfigKeySystemName: systemName,
}
// 有修改再更新
configs, err := models.ConfigModel.GetConfigs()
if err != nil {
this.ErrorLog("获取配置信息失败: " + err.Error())
this.jsonError("获取配置出错!")
}
updateKeys := make(map[string]string)
for _, config := range configs {
if len(config) == 0 {
continue
}
name := config["name"]
key := config["key"]
value := config["value"]
updateValue, ok := updateValues[key]
if !ok {
continue
}
// 没有修改不更新
if value == updateValue {
continue
}
_, err := models.ConfigModel.UpdateByKey(key, updateValue)
if err != nil {
this.ErrorLog(fmt.Sprintf("修改配置 %s 失败: %s", name, err.Error()))
this.jsonError(fmt.Sprintf("修改配置 %s 失败", name))
}
updateKeys[key] = updateValue
}
// 更新后的回调
//this.configUpdateCallback(updateKeys)
this.InfoLog("修改全局配置成功")
this.jsonSuccess("修改全局配置成功", nil, "/system/config/global")
}
// 配置更新通知回调
func (this *ConfigController) configUpdateCallback(updateKeyMaps map[string]string) {
fullTextOpenUpdate := false
updateValue, ok := updateKeyMaps[models.ConfigKeyFulltextSearch]
if ok {
fullTextOpenUpdate = true
}
docSearchTimerUpdate := false
_, ok = updateKeyMaps[models.ConfigKeyDocSearchTimer]
if ok {
docSearchTimerUpdate = true
}
// 索引时间更新,开关没有更新,重启一下 worker
if docSearchTimerUpdate && !fullTextOpenUpdate {
work.DocSearchWorker.Restart()
return
}
// 开关更新
if fullTextOpenUpdate {
if updateValue == "1" {
work.DocSearchWorker.Start()
return
}
work.DocSearchWorker.Stop()
}
}
+199
View File
@@ -0,0 +1,199 @@
package controllers
import (
"strings"
"time"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/astaxie/beego/validation"
)
type ContactController struct {
BaseController
}
func (this *ContactController) Add() {
this.viewLayout("contact/form", "contact")
}
func (this *ContactController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/contact/list")
}
name := strings.Trim(this.GetString("name", ""), "")
mobile := strings.Trim(this.GetString("mobile", ""), "")
position := strings.Trim(this.GetString("position", ""), "")
email := strings.Trim(this.GetString("email", ""), "")
v := validation.Validation{}
if name == "" {
this.jsonError("联系人姓名不能为空!")
}
if email == "" {
this.jsonError("邮箱不能为空!")
}
if !v.Email(email, "email").Ok {
this.jsonError("邮箱格式不正确!")
}
contact := map[string]interface{}{
"name": name,
"mobile": mobile,
"position": position,
"email": email,
}
contactId, err := models.ContactModel.Insert(contact)
if err != nil {
this.ErrorLog("添加联系人失败:" + err.Error())
this.jsonError("添加联系人失败")
}
this.InfoLog("添加联系人 " + utils.Convert.IntToString(contactId, 10) + " 成功")
this.jsonSuccess("添加联系人成功", nil, "/system/contact/list")
}
func (this *ContactController) List() {
var err error
var contacts []map[string]string
contacts, err = models.ContactModel.GetAllContact()
if err != nil {
this.ErrorLog("获取联系人列表出错: " + err.Error())
this.ViewError("获取联系人列表出错", "/system/main/index")
}
this.Data["contacts"] = contacts
this.viewLayout("contact/list", "contact")
}
func (this *ContactController) Edit() {
contactId := this.GetString("contact_id", "")
if contactId == "" {
this.ViewError("联系人不存在", "/system/contact/list")
}
contact, err := models.ContactModel.GetContactByContactId(contactId)
if err != nil {
this.ViewError("联系人不存在", "/system/contact/list")
}
this.Data["contact"] = contact
this.viewLayout("contact/form", "contact")
}
func (this *ContactController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/contact/list")
}
contactId := strings.Trim(this.GetString("contact_id", ""), "")
name := strings.Trim(this.GetString("name", ""), "")
mobile := strings.Trim(this.GetString("mobile", ""), "")
position := strings.Trim(this.GetString("position", ""), "")
email := strings.Trim(this.GetString("email", ""), "")
v := validation.Validation{}
if contactId == "" {
this.jsonError("参数错误!")
}
if name == "" {
this.jsonError("联系人姓名不能为空!")
}
if position == "" {
this.jsonError("职位不能为空!")
}
if mobile == "" {
this.jsonError("联系电话不能为空!")
}
if !v.Phone(mobile, "mobile").Ok {
this.jsonError("联系电话格式不正确!")
}
if email == "" {
this.jsonError("邮箱不能为空!")
}
if !v.Email(email, "email").Ok {
this.jsonError("邮箱格式不正确!")
}
contact := map[string]interface{}{
"name": name,
"mobile": mobile,
"position": position,
"email": email,
"update_time": time.Now().Unix(),
}
_, err := models.ContactModel.UpdateByContactId(contact, contactId)
if err != nil {
this.ErrorLog("修改联系人 " + contactId + " 失败:" + err.Error())
this.jsonError("修改联系人失败")
}
this.InfoLog("修改联系人 " + contactId + " 成功")
this.jsonSuccess("修改联系人成功", nil, "/system/contact/list")
}
func (this *ContactController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/contact/list")
}
contactId := this.GetString("contact_id", "")
if contactId == "" {
this.jsonError("没有选择联系人!")
}
contact, err := models.ContactModel.GetContactByContactId(contactId)
if err != nil {
this.ErrorLog("删除联系人 " + contactId + " 失败: " + err.Error())
this.jsonError("删除联系人失败")
}
if len(contact) == 0 {
this.jsonError("联系人不存在")
}
_, err = models.ContactModel.DeleteByContactId(contactId)
if err != nil {
this.ErrorLog("删除联系人 " + contactId + " 失败: " + err.Error())
this.jsonError("删除联系人失败")
}
this.InfoLog("删除联系人 " + contactId + " 成功")
this.jsonSuccess("删除联系人成功", nil, "/system/contact/list")
}
// 从用户导入联系人
func (this *ContactController) Import() {
keywords := map[string]string{}
page, _ := this.GetInt("page", 1)
username := strings.TrimSpace(this.GetString("username", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
if username != "" {
keywords["username"] = username
}
limit := (page - 1) * number
var err error
var count int64
var users []map[string]string
if len(keywords) != 0 {
count, err = models.UserModel.CountUsersByKeywords(keywords)
users, err = models.UserModel.GetUsersByKeywordsAndLimit(keywords, limit, number)
} else {
count, err = models.UserModel.CountUsers()
users, err = models.UserModel.GetUsersByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取用户列表失败", "/system/main/index")
}
this.Data["users"] = users
this.Data["username"] = username
this.SetPaginator(number, count)
this.viewLayout("contact/import", "contact")
}
+341
View File
@@ -0,0 +1,341 @@
package controllers
import (
"fmt"
"strings"
"time"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/astaxie/beego"
"github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
)
type EmailController struct {
BaseController
}
func (this *EmailController) List() {
keyword := strings.TrimSpace(this.GetString("keyword", ""))
var err error
var emails []map[string]string
if keyword != "" {
emails, err = models.EmailModel.GetEmailsByLikeName(keyword)
} else {
emails, err = models.EmailModel.GetEmails()
}
if err != nil {
this.ErrorLog("获取邮件服务器列表失败: " + err.Error())
this.ViewError("获取邮件服务器列表失败", "/system/main/index")
}
this.Data["emails"] = emails
this.Data["keyword"] = keyword
this.viewLayout("email/list", "email")
}
func (this *EmailController) Add() {
this.viewLayout("email/form", "email")
}
func (this *EmailController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
senderAddress := strings.TrimSpace(this.GetString("sender_address", ""))
senderName := strings.TrimSpace(this.GetString("sender_name", ""))
senderTitlePrefix := strings.TrimSpace(this.GetString("sender_title_prefix", ""))
host := strings.TrimSpace(this.GetString("host", ""))
port := strings.TrimSpace(this.GetString("port", "25"))
username := strings.TrimSpace(this.GetString("username", ""))
password := strings.TrimSpace(this.GetString("password", ""))
isSsl := strings.TrimSpace(this.GetString("is_ssl", "0"))
if name == "" {
this.jsonError("邮件服务器名称不能为空!")
}
if host == "" {
this.jsonError("邮件服务器主机不能为空!")
}
if validation.Validate(host, is.Host) != nil {
this.jsonError("邮件服务器主机格式不正确!")
}
if port == "" {
this.jsonError("邮件服务器端口不能为空!")
}
if validation.Validate(port, is.Port) != nil {
this.jsonError("邮件服务器端口格式不正确!")
}
if senderAddress == "" {
this.jsonError("发件人邮箱不能为空!")
}
if username == "" {
this.jsonError("发件用户名不能为空!")
}
if password == "" {
this.jsonError("发件人密码不能为空!")
}
ok, err := models.EmailModel.HasEmailName(name)
if err != nil {
this.ErrorLog("添加邮件服务器失败:" + err.Error())
this.jsonError("添加邮件服务器失败!")
}
if ok {
this.jsonError("邮件服务器名称已经存在!")
}
emailId, err := models.EmailModel.Insert(map[string]interface{}{
"name": name,
"sender_address": senderAddress,
"sender_name": senderName,
"sender_title_prefix": senderTitlePrefix,
"host": host,
"port": port,
"username": username,
"password": password,
"is_ssl": isSsl,
})
if err != nil {
this.ErrorLog("添加邮件服务器失败:" + err.Error())
this.jsonError("添加邮件服务器失败")
}
this.InfoLog("添加邮件服务器 " + utils.Convert.IntToString(emailId, 10) + " 成功")
this.jsonSuccess("添加邮件服务器成功", nil, "/system/email/list")
}
func (this *EmailController) Edit() {
emailId := this.GetString("email_id", "")
if emailId == "" {
this.ViewError("邮件服务器不存在", "/system/email/list")
}
email, err := models.EmailModel.GetEmailByEmailId(emailId)
if err != nil {
this.ViewError("邮件服务器不存在", "/system/email/list")
}
this.Data["email"] = email
this.viewLayout("email/form", "email")
}
func (this *EmailController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
emailId := this.GetString("email_id", "")
name := strings.TrimSpace(this.GetString("name", ""))
senderAddress := strings.TrimSpace(this.GetString("sender_address", ""))
senderName := strings.TrimSpace(this.GetString("sender_name", ""))
senderTitlePrefix := strings.TrimSpace(this.GetString("sender_title_prefix", ""))
host := strings.TrimSpace(this.GetString("host", ""))
port := strings.TrimSpace(this.GetString("port", ""))
username := strings.TrimSpace(this.GetString("username", ""))
password := strings.TrimSpace(this.GetString("password", ""))
isSsl := strings.TrimSpace(this.GetString("is_ssl", "0"))
if emailId == "" {
this.jsonError("邮件服务器不存在!")
}
if name == "" {
this.jsonError("邮件服务器名称不能为空!")
}
if host == "" {
this.jsonError("邮件服务器主机不能为空!")
}
if validation.Validate(host, is.Host) != nil {
this.jsonError("邮件服务器主机格式不正确!")
}
if port == "" {
this.jsonError("邮件服务器端口不能为空!")
}
if validation.Validate(port, is.Port) != nil {
this.jsonError("邮件服务器端口格式不正确!")
}
if senderAddress == "" {
this.jsonError("发件人邮箱不能为空!")
}
if username == "" {
this.jsonError("发件用户名不能为空!")
}
if password == "" {
this.jsonError("发件人密码不能为空!")
}
email, err := models.EmailModel.GetEmailByEmailId(emailId)
if err != nil {
this.ErrorLog("修改邮件服务器 " + emailId + " 失败: " + err.Error())
this.jsonError("修改邮件服务器失败!")
}
if len(email) == 0 {
this.jsonError("邮件服务器不存在!")
}
ok, _ := models.EmailModel.HasSameName(emailId, name)
if ok {
this.jsonError("邮件服务器名称已经存在!")
}
_, err = models.EmailModel.Update(emailId, map[string]interface{}{
"name": name,
"sender_address": senderAddress,
"sender_name": senderName,
"sender_title_prefix": senderTitlePrefix,
"host": host,
"port": port,
"username": username,
"password": password,
"is_ssl": isSsl,
})
if err != nil {
this.ErrorLog("修改邮件服务器 " + emailId + " 失败:" + err.Error())
this.jsonError("修改邮件服务器失败")
}
this.InfoLog("修改邮件服务器 " + emailId + " 成功")
this.jsonSuccess("修改邮件服务器成功", nil, "/system/email/list")
}
func (this *EmailController) Used() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
emailId := this.GetString("email_id", "")
if emailId == "" {
this.jsonError("没有选择邮件服务器!")
}
email, err := models.EmailModel.GetEmailByEmailId(emailId)
if err != nil {
this.ErrorLog("邮件服务器 " + emailId + " 启用失败: " + err.Error())
this.jsonError("邮件服务器启用失败")
}
if len(email) == 0 {
this.jsonError("邮件服务器不存在")
}
_, err = models.EmailModel.SetEmailUsed(emailId)
if err != nil {
this.ErrorLog("邮件服务器 " + emailId + " 启用失败: " + err.Error())
this.jsonError("邮件服务器启用失败")
}
this.InfoLog("启用邮件服务器 " + emailId + " 成功")
this.jsonSuccess("启用邮件服务器成功", nil, "/system/email/list")
}
func (this *EmailController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
emailId := this.GetString("email_id", "")
if emailId == "" {
this.jsonError("没有选择邮件服务器!")
}
email, err := models.EmailModel.GetEmailByEmailId(emailId)
if err != nil {
this.ErrorLog("删除邮件服务器 " + emailId + " 失败: " + err.Error())
this.jsonError("删除邮件服务器失败")
}
if len(email) == 0 {
this.jsonError("邮件服务器不存在")
}
err = models.EmailModel.Delete(emailId)
if err != nil {
this.ErrorLog("删除邮件服务器 " + emailId + " 失败: " + err.Error())
this.jsonError("删除邮件服务器失败")
}
this.InfoLog("删除邮件服务器 " + emailId + " 成功")
this.jsonSuccess("删除邮件服务器成功", nil, "/system/email/list")
}
func (this *EmailController) Test() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/email/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
senderAddress := strings.TrimSpace(this.GetString("sender_address", ""))
senderName := strings.TrimSpace(this.GetString("sender_name", ""))
senderTitlePrefix := strings.TrimSpace(this.GetString("sender_title_prefix", ""))
host := strings.TrimSpace(this.GetString("host", ""))
port := strings.TrimSpace(this.GetString("port", "25"))
username := strings.TrimSpace(this.GetString("username", ""))
password := strings.TrimSpace(this.GetString("password", ""))
isSsl := strings.TrimSpace(this.GetString("is_ssl", "0"))
emails := strings.TrimSpace(this.GetString("emails", ""))
if name == "" {
this.jsonError("邮件服务器名称不能为空!")
}
if host == "" {
this.jsonError("邮件服务器主机不能为空!")
}
if validation.Validate(host, is.Host) != nil {
this.jsonError("邮件服务器主机格式不正确!")
}
if port == "" {
this.jsonError("邮件服务器端口不能为空!")
}
if validation.Validate(port, is.Port) != nil {
this.jsonError("邮件服务器端口格式不正确!")
}
if senderAddress == "" {
this.jsonError("发件人邮箱不能为空!")
}
if username == "" {
this.jsonError("发件用户名不能为空!")
}
if password == "" {
this.jsonError("发件人密码不能为空!")
}
if emails == "" {
this.jsonError("要发送的邮件地址不能为空!")
}
emailConfig := map[string]string{
"sender_address": senderAddress,
"port": port,
"password": password,
"host": host,
"sender_name": senderName,
"username": username,
"sender_title_prefix": senderTitlePrefix,
"is_ssl": isSsl,
}
to := strings.Split(emails, ";")
documentValue := map[string]string{
"name": "MM-Wiki测试邮件",
"username": this.User["username"],
"update_time": fmt.Sprintf("%d", time.Now().Unix()),
"comment": "",
"document_url": "",
"content": "欢迎使用 <a href='https://github.com/phachon/mm-wiki'>MM-Wiki</a>,这是一封测试邮件,请勿回复!",
}
emailTemplate := beego.BConfig.WebConfig.ViewsPath + "/system/email/template_test.html"
body, err := utils.Email.MakeDocumentHtmlBody(documentValue, emailTemplate)
if err != nil {
this.ErrorLog("发送测试邮件失败:" + err.Error())
this.jsonError("发送测试邮件失败!")
}
// start send email
err = utils.Email.Send(emailConfig, to, "测试邮件", body)
if err != nil {
this.ErrorLog("发送测试邮件失败:" + err.Error())
this.jsonError("发送测试邮件失败!")
}
this.jsonSuccess("发送测试邮件成功", nil)
}
+182
View File
@@ -0,0 +1,182 @@
package controllers
import (
"strings"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
valid "github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
)
type LinkController struct {
BaseController
}
func (this *LinkController) Add() {
this.viewLayout("link/form", "link")
}
func (this *LinkController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/link/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
url := strings.TrimSpace(this.GetString("url", ""))
sequence := strings.TrimSpace(this.GetString("sequence", "0"))
if name == "" {
this.jsonError("链接名称不能为空!")
}
if url == "" {
this.jsonError("链接地址不能为空!")
}
if valid.Validate(url, is.URL) != nil {
this.jsonError("链接地址格式不正确!")
}
ok, err := models.LinkModel.HasLinkName(name)
if err != nil {
this.ErrorLog("添加链接失败:" + err.Error())
this.jsonError("添加链接失败!")
}
if ok {
this.jsonError("链接名已经存在!")
}
linkId, err := models.LinkModel.Insert(map[string]interface{}{
"name": name,
"url": url,
"sequence": sequence,
})
if err != nil {
this.ErrorLog("添加链接失败:" + err.Error())
this.jsonError("添加链接失败")
}
this.InfoLog("添加链接 " + utils.Convert.IntToString(linkId, 10) + " 成功")
this.jsonSuccess("添加链接成功", nil, "/system/link/list")
}
func (this *LinkController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var links []map[string]string
if keyword != "" {
count, err = models.LinkModel.CountLinksByKeyword(keyword)
links, err = models.LinkModel.GetLinksByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.LinkModel.CountLinks()
links, err = models.LinkModel.GetLinksByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取链接列表失败: " + err.Error())
this.ViewError("获取链接列表失败", "/system/main/index")
}
this.Data["links"] = links
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("link/list", "link")
}
func (this *LinkController) Edit() {
linkId := this.GetString("link_id", "")
if linkId == "" {
this.ViewError("链接不存在", "/system/link/list")
}
link, err := models.LinkModel.GetLinkByLinkId(linkId)
if err != nil {
this.ViewError("链接不存在", "/system/link/list")
}
this.Data["link"] = link
this.viewLayout("link/form", "link")
}
func (this *LinkController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/link/list")
}
linkId := this.GetString("link_id", "")
name := strings.TrimSpace(this.GetString("name", ""))
url := strings.TrimSpace(this.GetString("url", ""))
sequence := strings.TrimSpace(this.GetString("sequence", ""))
if linkId == "" {
this.jsonError("链接不存在!")
}
if name == "" {
this.jsonError("链接名称不能为空!")
}
if url == "" {
this.jsonError("链接地址不能为空!")
}
if valid.Validate(url, is.URL) != nil {
this.jsonError("链接地址格式不正确!")
}
link, err := models.LinkModel.GetLinkByLinkId(linkId)
if err != nil {
this.ErrorLog("修改链接 " + linkId + " 失败: " + err.Error())
this.jsonError("修改链接失败!")
}
if len(link) == 0 {
this.jsonError("链接不存在!")
}
ok, _ := models.LinkModel.HasSameName(linkId, name)
if ok {
this.jsonError("链接名已经存在!")
}
_, err = models.LinkModel.Update(linkId, map[string]interface{}{
"name": name,
"url": url,
"sequence": sequence,
})
if err != nil {
this.ErrorLog("修改链接 " + linkId + " 失败:" + err.Error())
this.jsonError("修改链接失败")
}
this.InfoLog("修改链接 " + linkId + " 成功")
this.jsonSuccess("修改链接成功", nil, "/system/link/list")
}
func (this *LinkController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/link/list")
}
linkId := this.GetString("link_id", "")
if linkId == "" {
this.jsonError("没有选择链接!")
}
link, err := models.LinkModel.GetLinkByLinkId(linkId)
if err != nil {
this.ErrorLog("删除链接 " + linkId + " 失败: " + err.Error())
this.jsonError("删除链接失败")
}
if len(link) == 0 {
this.jsonError("链接不存在")
}
err = models.LinkModel.Delete(linkId)
if err != nil {
this.ErrorLog("删除链接 " + linkId + " 失败: " + err.Error())
this.jsonError("删除链接失败")
}
this.InfoLog("删除链接 " + linkId + " 成功")
this.jsonSuccess("删除链接成功", nil, "/system/link/list")
}
+134
View File
@@ -0,0 +1,134 @@
package controllers
import (
"github.com/phachon/mm-wiki/app/models"
"strings"
)
type LogController struct {
BaseController
}
func (this *LogController) System() {
page, _ := this.GetInt("page", 1)
number, _ := this.GetRangeInt("number", 20, 10, 100)
level := strings.TrimSpace(this.GetString("level", ""))
message := strings.TrimSpace(this.GetString("message", ""))
username := strings.TrimSpace(this.GetString("username", ""))
limit := (page - 1) * number
var err error
var count int64
var logs []map[string]string
if level != "" || message != "" || username != "" {
count, err = models.LogModel.CountLogsByKeyword(level, message, username)
logs, err = models.LogModel.GetLogsByKeywordAndLimit(level, message, username, limit, number)
} else {
count, err = models.LogModel.CountLogs()
logs, err = models.LogModel.GetLogsByLimit(limit, number)
}
if err != nil {
this.ErrorLog("查找系统日志出错:" + err.Error())
this.ViewError("查找系统日志出错", "/system/main/index")
}
this.Data["logs"] = logs
this.Data["username"] = username
this.Data["level"] = level
this.Data["message"] = message
this.SetPaginator(number, count)
this.viewLayout("log/system", "log")
}
func (this *LogController) Info() {
logId := this.GetString("log_id", "")
if logId == "" {
this.ViewError("日志不存在", "/system/log/system")
}
log, err := models.LogModel.GetLogByLogId(logId)
if err != nil {
this.ViewError("日志不存在", "/system/log/system")
}
this.Data["log"] = log
this.viewLayout("log/info", "log")
}
func (this *LogController) Document() {
page, _ := this.GetInt("page", 1)
number, _ := this.GetRangeInt("number", 20, 10, 100)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
userId := strings.TrimSpace(this.GetString("user_id", ""))
limit := (page - 1) * number
var logDocuments = []map[string]string{}
var err error
var count int64
if keyword != "" && userId != "" {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByUserIdKeywordAndLimit(userId, keyword, limit, number)
count, err = models.LogDocumentModel.CountLogDocumentsByUserIdAndKeyword(userId, keyword)
} else if userId != "" {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByUserIdAndLimit(userId, limit, number)
count, err = models.LogDocumentModel.CountLogDocumentsByUserId(userId)
} else if keyword != "" {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByKeywordAndLimit(keyword, limit, number)
count, err = models.LogDocumentModel.CountLogDocumentsByKeyword(userId)
} else {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByLimit(this.UserId, limit, number)
count, err = models.LogDocumentModel.CountLogDocuments()
}
if err != nil {
this.ErrorLog("文档日志查找失败:" + err.Error())
this.ViewError("文档日志查找失败!", "/system/main/index")
}
userIds := []string{}
docIds := []string{}
for _, logDocument := range logDocuments {
userIds = append(userIds, logDocument["user_id"])
docIds = append(docIds, logDocument["document_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("文档日志查找失败:" + err.Error())
this.ViewError("文档日志查找失败!", "/system/main/index")
}
docs, err := models.DocumentModel.GetAllDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("文档日志查找失败:" + err.Error())
this.ViewError("文档日志查找失败!", "/system/main/index")
}
for _, logDocument := range logDocuments {
logDocument["username"] = ""
for _, user := range users {
if logDocument["user_id"] == user["user_id"] {
logDocument["username"] = user["username"]
logDocument["given_name"] = user["given_name"]
break
}
}
for _, doc := range docs {
if logDocument["document_id"] == doc["document_id"] {
logDocument["document_name"] = doc["name"]
logDocument["document_type"] = doc["type"]
break
}
}
}
users, err = models.UserModel.GetUsers()
if err != nil {
this.ErrorLog("文档日志查找失败:" + err.Error())
this.ViewError("文档日志查找失败!", "/system/main/index")
}
this.Data["logDocuments"] = logDocuments
this.Data["keyword"] = keyword
this.Data["userId"] = userId
this.Data["users"] = users
this.SetPaginator(number, count)
this.viewLayout("log/document", "log")
}
+54
View File
@@ -0,0 +1,54 @@
package controllers
import (
"fmt"
"github.com/phachon/mm-wiki/app/models"
)
type MainController struct {
BaseController
}
func (this *MainController) Index() {
var err error
var menus = []map[string]string{}
var controllers = []map[string]string{}
user, err := models.UserModel.GetUserByUserId(this.UserId)
if err != nil {
this.ViewError("查找用户失败!")
}
if len(user) == 0 {
this.ViewError("用户不存在!")
}
roleId := user["role_id"]
if roleId == fmt.Sprintf("%d", models.Role_Root_Id) {
menus, controllers, err = models.PrivilegeModel.GetTypePrivilegesByDisplay(models.Privilege_DisPlay_True)
if err != nil {
this.ViewError("查找用户权限失败!")
}
} else {
rolePrivileges, err := models.RolePrivilegeModel.GetRolePrivilegesByRoleId(roleId)
if err != nil {
this.ViewError("查找用户权限出错")
}
var privilegeIds = []string{}
for _, rolePrivilege := range rolePrivileges {
privilegeIds = append(privilegeIds, rolePrivilege["privilege_id"])
}
menus, controllers, err = models.PrivilegeModel.GetTypePrivilegesByDisplayPrivilegeIds(models.Privilege_DisPlay_True, privilegeIds)
if err != nil {
this.ViewError("查找用户权限失败!")
}
}
this.Data["menus"] = menus
this.Data["controllers"] = controllers
this.viewLayout("main/index", "main")
}
func (this *MainController) Default() {
this.viewLayout("main/default", "default")
}
+98
View File
@@ -0,0 +1,98 @@
package controllers
import (
"encoding/json"
"github.com/phachon/mm-wiki/app/models"
"strings"
)
type PluginController struct {
BaseController
}
func (this *PluginController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var plugins []map[string]string
if keyword != "" {
count, err = models.PluginModel.CountPluginsByKeyword(keyword)
plugins, err = models.PluginModel.GetPluginsByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.PluginModel.CountPlugins()
plugins, err = models.PluginModel.GetPluginsByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取插件列表失败: " + err.Error())
this.ViewError("获取插件列表失败", "/system/main/index")
}
this.Data["plugins"] = plugins
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("plugin/list", "plugin")
}
func (this *PluginController) Config() {
pluginId := this.GetString("plugin_id", "")
if pluginId == "" {
this.ViewError("参数错误", "/system/plugin/list")
}
plugin, err := models.PluginModel.GetPluginByPluginId(pluginId)
if err != nil {
this.ErrorLog("查找插件错误:" + err.Error())
this.ViewError("查找插件错误", "/system/plugin/list")
}
if len(plugin) == 0 {
this.ViewError("插件不存在", "/system/plugin/list")
}
pluginKey, ok := plugin["plugin_key"]
if !ok || pluginKey == "" {
this.ViewError("插件数据不完整 Key 不存在", "/system/plugin/list")
}
configValue := make(map[string]string)
configValueStr, ok := plugin["conf_value"]
if ok && configValueStr != "" {
json.Unmarshal([]byte(configValueStr), &configValue)
}
// 根据不同的插件,显示不同的配置页面
this.Data["plugin_config"] = configValue
this.Data["plugin"] = plugin
this.viewLayout("plugin/"+pluginKey, "plugin")
}
func (this *PluginController) ConfigModify() {
pluginId := this.GetString("plugin_id", "")
confValue := this.GetString("conf_value", "")
if pluginId == "" {
this.jsonError("参数错误")
}
if confValue == "" {
this.jsonError("配置参数为空")
}
plugin, err := models.PluginModel.GetPluginByPluginId(pluginId)
if err != nil {
this.ErrorLog("查找插件错误:" + err.Error())
this.jsonError("查找插件错误")
}
if len(plugin) == 0 {
this.jsonError("插件不存在")
}
// 更新插件
_, err = models.PluginModel.UpdateConfValueByPluginId(pluginId, confValue)
if err != nil {
this.ErrorLog("修改插件配置错误:" + err.Error())
this.jsonError("修改插件配置失败")
}
this.jsonSuccess("修改插件配置成功", nil, "/system/plugin/list")
}
+218
View File
@@ -0,0 +1,218 @@
package controllers
import (
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"strings"
)
type PrivilegeController struct {
BaseController
}
func (this *PrivilegeController) Add() {
menus, _, err := models.PrivilegeModel.GetTypePrivileges()
if err != nil {
this.ViewError("查找权限菜单失败!")
}
this.Data["menus"] = menus
this.Data["mode"] = beego.BConfig.RunMode
this.viewLayout("privilege/form", "privilege")
}
func (this *PrivilegeController) Save() {
if !this.IsPost() {
this.ViewError("请求方式错误", "/system/privilege/add")
}
if beego.BConfig.RunMode != "dev" {
this.jsonError("只允许在开发模式下添加权限!")
}
name := strings.TrimSpace(this.GetString("name", ""))
privilegeType := strings.TrimSpace(this.GetString("type", ""))
parentId := strings.TrimSpace(this.GetString("parent_id", "0"))
controller := strings.TrimSpace(this.GetString("controller", ""))
action := strings.TrimSpace(this.GetString("action", ""))
target := strings.TrimSpace(this.GetString("target", ""))
icon := strings.TrimSpace(this.GetString("icon", ""))
isDisplay := strings.TrimSpace(this.GetString("is_display", "0"))
sequence := strings.TrimSpace(this.GetString("sequence", "0"))
if name == "" {
this.jsonError("权限名称不能为空!")
}
if privilegeType == "" {
this.jsonError("没有选择权限类型!")
}
if privilegeType == "controller" {
if parentId == "" {
this.jsonError("控制器必须选择上级菜单!")
}
if controller == "" {
this.jsonError("控制器名称不能为空!")
}
if action == "" {
this.jsonError("方法名称不能为空!")
}
}
privilegeId, err := models.PrivilegeModel.Insert(map[string]interface{}{
"name": name,
"type": privilegeType,
"parent_id": parentId,
"controller": controller,
"action": action,
"target": target,
"icon": icon,
"is_display": isDisplay,
"sequence": sequence,
})
if err != nil {
this.ErrorLog("添加权限失败:" + err.Error())
this.jsonError("添加权限失败")
}
this.InfoLog("添加权限 " + utils.Convert.IntToString(privilegeId, 10) + " 成功")
this.jsonSuccess("添加权限成功", nil, "/system/privilege/list")
}
func (this *PrivilegeController) List() {
menus, controllers, err := models.PrivilegeModel.GetTypePrivileges()
if err != nil {
this.ViewError("查找权限失败!")
}
this.Data["menus"] = menus
this.Data["controllers"] = controllers
this.Data["mode"] = beego.BConfig.RunMode
this.viewLayout("privilege/list", "privilege")
}
func (this *PrivilegeController) Edit() {
privilegeId := this.GetString("privilege_id", "")
if privilegeId == "" {
this.ViewError("没有选择权限!", "/system/privilege/list")
}
privilege, err := models.PrivilegeModel.GetPrivilegeByPrivilegeId(privilegeId)
if err != nil {
this.ErrorLog("查找权限失败:" + err.Error())
this.ViewError("查找权限失败!", "/system/privilege/list")
}
if len(privilege) == 0 {
this.ViewError("权限不存在!", "/system/privilege/list")
}
menus, _, err := models.PrivilegeModel.GetTypePrivileges()
if err != nil {
this.ViewError("查找权限失败!", "/system/privilege/list")
}
this.Data["menus"] = menus
this.Data["privilege"] = privilege
this.Data["mode"] = beego.BConfig.RunMode
this.viewLayout("privilege/form", "privilege")
}
func (this *PrivilegeController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式错误", "/system/privilege/list")
}
if beego.BConfig.RunMode != "dev" {
this.jsonError("只允许在开发模式下修改权限!")
}
privilegeId := strings.TrimSpace(this.GetString("privilege_id", ""))
name := strings.TrimSpace(this.GetString("name", ""))
privilegeType := strings.TrimSpace(this.GetString("type", ""))
parentId := strings.TrimSpace(this.GetString("parent_id", "0"))
controller := strings.TrimSpace(this.GetString("controller", ""))
action := strings.TrimSpace(this.GetString("action", ""))
target := strings.TrimSpace(this.GetString("target", ""))
icon := strings.TrimSpace(this.GetString("icon", "glyphicon-list"))
isDisplay := strings.TrimSpace(this.GetString("is_display", "0"))
sequence := strings.TrimSpace(this.GetString("sequence", "0"))
if name == "" {
this.jsonError("权限名称不能为空!")
}
if privilegeType == "" {
this.jsonError("没有选择权限类型!")
}
if privilegeType == "controller" {
if parentId == "" {
this.jsonError("控制器必须选择上级菜单!")
}
if controller == "" {
this.jsonError("控制器名称不能为空!")
}
if action == "" {
this.jsonError("方法名称不能为空!")
}
}
_, err := models.PrivilegeModel.Update(privilegeId, map[string]interface{}{
"name": name,
"type": privilegeType,
"parent_id": parentId,
"controller": controller,
"action": action,
"target": target,
"icon": icon,
"is_display": isDisplay,
"sequence": sequence,
})
if err != nil {
this.ErrorLog("修改权限 " + privilegeId + " 失败:" + err.Error())
this.jsonError("修改权限失败!")
}
this.InfoLog("修改权限 " + privilegeId + " 成功")
this.jsonSuccess("修改权限成功", nil, "/system/privilege/list")
}
func (this *PrivilegeController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/privilege/list")
}
if beego.BConfig.RunMode != "dev" {
this.jsonError("只允许在开发模式下删除权限!")
}
privilegeId := this.GetString("privilege_id", "")
if privilegeId == "" {
this.jsonError("没有选择权限!")
}
privilege, err := models.PrivilegeModel.GetPrivilegeByPrivilegeId(privilegeId)
if err != nil {
this.ErrorLog("删除权限 " + privilegeId + " 失败: " + err.Error())
this.jsonError("删除权限失败")
}
if len(privilege) == 0 {
this.jsonError("权限不存在")
}
// delete role_privilege by privilegeId
err = models.RolePrivilegeModel.DeleteByPrivilegeId(privilegeId)
if err != nil {
this.ErrorLog("删除角色权限 " + privilegeId + " 失败: " + err.Error())
this.jsonError("删除权限失败")
}
// delete privilege
err = models.PrivilegeModel.Delete(privilegeId)
if err != nil {
this.ErrorLog("删除权限 " + privilegeId + " 失败: " + err.Error())
this.jsonError("删除权限失败")
}
this.InfoLog("删除权限 " + privilegeId + " 成功")
this.jsonSuccess("删除权限成功", nil, "/system/privilege/list")
}
+318
View File
@@ -0,0 +1,318 @@
package controllers
import (
"github.com/astaxie/beego/validation"
"github.com/phachon/mm-wiki/app/models"
"strings"
)
type ProfileController struct {
BaseController
}
func (this *ProfileController) Info() {
user, err := models.UserModel.GetUserByUserId(this.UserId)
if err != nil {
this.ErrorLog("获取我的资料失败: " + err.Error())
this.ViewError("获取资料失败")
}
logDocuments, err := models.LogDocumentModel.GetLogDocumentsByUserIdAndLimit(this.UserId, 0, 10)
if err != nil {
this.ErrorLog("查找用户活动出错:" + err.Error())
this.ViewError("查找用户活动出错!", "/main/index")
}
docIds := []string{}
for _, logDocument := range logDocuments {
docIds = append(docIds, logDocument["document_id"])
}
documents, err := models.DocumentModel.GetAllDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("查找用户活动出错: " + err.Error())
this.ViewError("查找用户活动出错", "/main/index")
}
for _, logDocument := range logDocuments {
for _, document := range documents {
if document["document_id"] == logDocument["document_id"] {
logDocument["document_id"] = document["document_id"]
logDocument["document_name"] = document["name"]
logDocument["document_type"] = document["type"]
logDocument["update_time"] = document["update_time"]
}
}
}
this.Data["logDocuments"] = logDocuments
this.Data["count"] = len(logDocuments)
this.Data["user"] = user
this.viewLayout("profile/info", "profile")
}
func (this *ProfileController) Edit() {
user, err := models.UserModel.GetUserByUserId(this.UserId)
if err != nil {
this.ErrorLog("获取我的资料失败: " + err.Error())
this.ViewError("获取资料失败")
}
this.Data["user"] = user
this.viewLayout("profile/edit", "profile")
}
func (this *ProfileController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/profile/info")
}
givenName := strings.TrimSpace(this.GetString("given_name", ""))
email := strings.TrimSpace(this.GetString("email", ""))
mobile := strings.TrimSpace(this.GetString("mobile", ""))
phone := strings.TrimSpace(this.GetString("phone", ""))
department := strings.TrimSpace(this.GetString("department", ""))
position := strings.TrimSpace(this.GetString("position", ""))
location := strings.TrimSpace(this.GetString("location", ""))
im := strings.TrimSpace(this.GetString("im", ""))
v := validation.Validation{}
if givenName == "" {
this.jsonError("姓名不能为空!")
}
if email == "" {
this.jsonError("邮箱不能为空!")
}
if !v.Email(email, "email").Ok {
this.jsonError("邮箱格式不正确!")
}
if mobile == "" {
this.jsonError("手机号不能为空!")
}
//if !v.Mobile(mobile, "mobile").Ok {
// this.jsonError("手机号格式不正确!")
//}
//if phone != "" && !v.Phone(phone, "phone").Ok {
// this.jsonError("电话格式不正确!")
//}
_, err := models.UserModel.Update(this.UserId, map[string]interface{}{
"given_name": givenName,
"email": email,
"mobile": mobile,
"phone": phone,
"department": department,
"position": position,
"location": location,
"im": im,
})
if err != nil {
this.ErrorLog("修改我的资料失败:" + err.Error())
this.jsonError("修改我的资料失败")
}
this.InfoLog("修改我的资料成功")
this.jsonSuccess("我的资料修改成功", nil, "/system/profile/info")
}
func (this *ProfileController) FollowUser() {
// follow users
followUsers, err := models.FollowModel.GetFollowsByUserIdAndType(this.UserId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取我的关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/system/profile/info")
}
userIds := []string{}
for _, followUser := range followUsers {
userIds = append(userIds, followUser["object_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("获取我的关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/system/profile/info")
}
for _, user := range users {
user["follow_id"] = "0"
for _, followUser := range followUsers {
if followUser["object_id"] == user["user_id"] {
user["follow_id"] = followUser["follow_id"]
break
}
}
}
// fans users
followedUsers, err := models.FollowModel.GetFollowsByObjectIdAndType(this.UserId, models.Follow_Type_User)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/system/profile/info")
}
followedUserIds := []string{}
for _, followedUser := range followedUsers {
followedUserIds = append(followedUserIds, followedUser["user_id"])
}
fansUsers, err := models.UserModel.GetUsersByUserIds(followedUserIds)
if err != nil {
this.ErrorLog("获取关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/system/profile/info")
}
this.Data["users"] = users
this.Data["fansUsers"] = fansUsers
this.Data["followCount"] = len(users)
this.Data["fansCount"] = len(fansUsers)
this.Data["user"] = this.User
this.viewLayout("profile/follow_user", "profile")
}
func (this *ProfileController) FollowDoc() {
page, _ := this.GetInt("page", 1)
number, _ := this.GetRangeInt("number", 10, 10, 100)
limit := (page - 1) * number
// follow docs limit
followDocuments, err := models.FollowModel.GetFollowsByUserIdTypeAndLimit(this.UserId, models.Follow_Type_Doc, limit, number)
if err != nil {
this.ErrorLog("获取关注文档列表失败: " + err.Error())
this.ViewError("获取关注文档列表失败", "/system/profile/info")
}
count, err := models.FollowModel.CountFollowsByUserIdAndType(this.UserId, models.Follow_Type_Doc)
if err != nil {
this.ErrorLog("获取关注文档列表失败: " + err.Error())
this.ViewError("获取关注文档列表失败", "/system/profile/info")
}
docIds := []string{}
for _, followDocument := range followDocuments {
docIds = append(docIds, followDocument["object_id"])
}
documents, err := models.DocumentModel.GetDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("获取我的关注用户列表失败: " + err.Error())
this.ViewError("获取关注用户列表失败", "/system/profile/info")
}
for _, followDocument := range followDocuments {
for _, document := range documents {
if document["document_id"] == followDocument["object_id"] {
followDocument["document_id"] = document["document_id"]
followDocument["document_name"] = document["name"]
followDocument["update_time"] = document["update_time"]
}
}
}
autoFollowDoc := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyAutoFollowdoc, "0")
this.Data["followDocuments"] = followDocuments
this.Data["count"] = len(documents)
this.Data["user"] = this.User
this.Data["autoFollowDoc"] = autoFollowDoc
this.SetPaginator(number, count)
this.viewLayout("profile/follow_doc", "profile")
}
func (this *ProfileController) Activity() {
page, _ := this.GetInt("page", 1)
number, _ := this.GetRangeInt("number", 15, 10, 100)
limit := (page - 1) * number
keyword := strings.TrimSpace(this.GetString("keyword", ""))
var logDocuments = []map[string]string{}
var err error
var count int64
if keyword != "" {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByUserIdKeywordAndLimit(this.UserId, keyword, limit, number)
count, err = models.LogDocumentModel.CountLogDocumentsByUserIdAndKeyword(this.UserId, keyword)
} else {
logDocuments, err = models.LogDocumentModel.GetLogDocumentsByUserIdAndLimit(this.UserId, limit, number)
count, err = models.LogDocumentModel.CountLogDocumentsByUserId(this.UserId)
}
if err != nil {
this.ErrorLog("我的活动查找失败:" + err.Error())
this.ViewError("我的活动查找失败!", "/system/main/index")
}
userIds := []string{}
docIds := []string{}
for _, logDocument := range logDocuments {
userIds = append(userIds, logDocument["user_id"])
docIds = append(docIds, logDocument["document_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("我的活动查找失败:" + err.Error())
this.ViewError("我的活动查找失败!", "/system/main/index")
}
docs, err := models.DocumentModel.GetAllDocumentsByDocumentIds(docIds)
if err != nil {
this.ErrorLog("我的活动查找失败:" + err.Error())
this.ViewError("我的活动查找失败!", "/system/main/index")
}
for _, logDocument := range logDocuments {
logDocument["username"] = ""
for _, user := range users {
if logDocument["user_id"] == user["user_id"] {
logDocument["username"] = user["username"]
logDocument["given_name"] = user["given_name"]
break
}
}
for _, doc := range docs {
if logDocument["document_id"] == doc["document_id"] {
logDocument["document_name"] = doc["name"]
logDocument["document_type"] = doc["type"]
break
}
}
}
this.Data["logDocuments"] = logDocuments
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("profile/activity", "profile")
}
func (this *ProfileController) Password() {
this.viewLayout("profile/password", "profile")
}
func (this *ProfileController) SavePass() {
pwd := strings.TrimSpace(this.GetString("pwd", ""))
pwdNew := strings.TrimSpace(this.GetString("pwd_new", ""))
pwdConfirm := strings.TrimSpace(this.GetString("pwd_confirm", ""))
if (pwd == "") || (pwdNew == "") || (pwdConfirm == "") {
this.jsonError("密码不能为空!")
}
p := models.UserModel.EncodePassword(pwd)
if p != this.User["password"] {
this.jsonError("当前密码错误")
}
if pwdConfirm != pwdNew {
this.jsonError("确认密码和新密码不一致")
}
_, err := models.UserModel.Update(this.UserId, map[string]interface{}{
"password": models.UserModel.EncodePassword(pwdNew),
})
// 阻止日志记录 password
this.Ctx.Request.PostForm.Del("pwd")
this.Ctx.Request.PostForm.Del("pwd_new")
this.Ctx.Request.PostForm.Del("pwd_confirm")
if err != nil {
this.ErrorLog("修改密码失败:" + err.Error())
this.jsonError("修改密码失败")
}
this.InfoLog("修改密码成功")
this.jsonSuccess("修改密码成功, 下次登录时生效", nil, "/system/profile/password")
}
+357
View File
@@ -0,0 +1,357 @@
package controllers
import (
"fmt"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"strings"
)
type RoleController struct {
BaseController
}
func (this *RoleController) Add() {
this.viewLayout("role/form", "role")
}
func (this *RoleController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/role/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
if name == "" {
this.jsonError("角色名称不能为空!")
}
ok, err := models.RoleModel.HasRoleName(name)
if err != nil {
this.ErrorLog("添加角色失败:" + err.Error())
this.jsonError("添加角色失败!")
}
if ok {
this.jsonError("角色名已经存在!")
}
roleId, err := models.RoleModel.Insert(map[string]interface{}{
"name": name,
})
if err != nil {
this.ErrorLog("添加角色失败:" + err.Error())
this.jsonError("添加角色失败")
}
this.InfoLog("添加角色 " + utils.Convert.IntToString(roleId, 10) + " 成功")
this.jsonSuccess("添加角色成功", nil, "/system/role/list")
}
func (this *RoleController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var roles []map[string]string
if keyword != "" {
count, err = models.RoleModel.CountRolesByKeyword(keyword)
roles, err = models.RoleModel.GetRolesByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.RoleModel.CountRoles()
roles, err = models.RoleModel.GetRolesByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取角色列表失败: " + err.Error())
this.ViewError("获取角色列表失败", "/system/main/index")
}
this.Data["roles"] = roles
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("role/list", "role")
}
func (this *RoleController) Edit() {
roleId := this.GetString("role_id", "")
if roleId == "" {
this.ViewError("角色不存在", "/system/role/list")
}
if roleId == fmt.Sprintf("%d", models.Role_Root_Id) {
this.ViewError("不能修改超级管理员", "/system/role/list")
}
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("查找角色错误:" + err.Error())
this.ViewError("查找角色错误", "/system/role/list")
}
if len(role) == 0 {
this.ViewError("角色不存在", "/system/role/list")
}
this.Data["role"] = role
this.viewLayout("role/form", "role")
}
func (this *RoleController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/role/list")
}
roleId := this.GetString("role_id", "")
name := strings.TrimSpace(this.GetString("name", ""))
if roleId == "" {
this.jsonError("角色不存在!")
}
if roleId == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("超级管理员不能修改!")
}
if name == "" {
this.jsonError("角色名称不能为空!")
}
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("修改角色 " + roleId + " 失败: " + err.Error())
this.jsonError("修改角色失败!")
}
if len(role) == 0 {
this.jsonError("角色不存在!")
}
if role["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("超级管理员角色不能修改!")
}
ok, _ := models.RoleModel.HasSameName(roleId, name)
if ok {
this.jsonError("角色名已经存在!")
}
_, err = models.RoleModel.Update(roleId, map[string]interface{}{
"name": name,
})
if err != nil {
this.ErrorLog("修改角色 " + roleId + " 失败:" + err.Error())
this.jsonError("修改角色" + roleId + "失败")
}
this.InfoLog("修改角色 " + roleId + " 成功")
this.jsonSuccess("修改角色成功", nil, "/system/role/list")
}
func (this *RoleController) User() {
keywords := map[string]string{}
page, _ := this.GetInt("page", 1)
roleId := strings.TrimSpace(this.GetString("role_id", ""))
if roleId == "" {
this.ViewError("没有选择角色!")
}
keywords["role_id"] = roleId
number, _ := this.GetRangeInt("number", 15, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var users []map[string]string
count, err = models.UserModel.CountUsersByKeywords(keywords)
if err != nil {
this.ErrorLog("获取角色用户列表失败: " + err.Error())
this.ViewError("获取角色用户列表失败!", "/system/role/list")
}
users, err = models.UserModel.GetUsersByKeywordsAndLimit(keywords, limit, number)
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取用户列表失败!", "/system/role/list")
}
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取角色用户列表失败!", "/system/main/index")
}
for _, user := range users {
user["role_name"] = role["name"]
}
this.Data["users"] = users
this.Data["roleId"] = roleId
this.SetPaginator(number, count)
this.viewLayout("role/user", "role")
}
func (this *RoleController) Privilege() {
roleId := this.GetString("role_id", "")
if roleId == "" {
this.ViewError("角色不存在", "/system/role/list")
}
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("查找角色权限失败:" + err.Error())
this.ViewError("查看角色权限失败!", "/system/role/list")
}
if len(role) == 0 {
this.ViewError("角色不存在", "/system/role/list")
}
menus, controllers, err := models.PrivilegeModel.GetTypePrivileges()
if err != nil {
this.ViewError("查找角色权限失败!")
}
var rolePrivileges = []map[string]string{}
if role["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
rolePrivileges, err = models.RolePrivilegeModel.GetRootRolePrivileges()
} else {
rolePrivileges, err = models.RolePrivilegeModel.GetRolePrivilegesByRoleId(roleId)
}
if err != nil {
this.ViewError("查找用户权限出错")
}
this.Data["role"] = role
this.Data["menus"] = menus
this.Data["controllers"] = controllers
this.Data["rolePrivileges"] = rolePrivileges
this.Data["disabledPrivilegeIds"] = models.Privilege_Default_Ids
this.viewLayout("role/privilege", "role")
}
func (this *RoleController) GrantPrivilege() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/role/list")
}
privilegeIds := this.GetStrings("privilege_id", []string{})
roleId := this.GetString("role_id", "")
if roleId == "" {
this.jsonError("没有选择角色!")
}
//if len(privilegeIds) == 0 {
// this.jsonError("没有选择权限!")
//}
// add default privileges
privilegeIds = append(privilegeIds, models.Privilege_Default_Ids...)
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("角色 " + roleId + " 授权失败:" + err.Error())
this.jsonError("角色不存在")
}
if len(role) == 0 {
this.jsonError("角色不存在")
}
if role["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("超级管理员不需要授权!")
}
res, err := models.RolePrivilegeModel.GrantRolePrivileges(roleId, privilegeIds)
if err != nil {
this.ErrorLog("角色 " + roleId + " 授权失败:" + err.Error())
this.jsonError("角色授权失败!")
}
if !res {
this.jsonError("角色授权失败")
}
this.InfoLog("角色 " + roleId + " 授权成功")
this.jsonSuccess("角色授权成功", nil, "/system/role/list")
}
func (this *RoleController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/role/list")
}
roleId := this.GetString("role_id", "")
if roleId == "" {
this.jsonError("没有选择角色!")
}
if roleId == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("超级管理员不能删除!")
}
role, err := models.RoleModel.GetRoleByRoleId(roleId)
if err != nil {
this.ErrorLog("删除角色 " + roleId + " 失败: " + err.Error())
this.jsonError("删除角色失败")
}
if len(role) == 0 {
this.jsonError("角色不存在")
}
if role["type"] == fmt.Sprintf("%d", models.Role_Type_System) {
this.jsonError("系统角色不能删除!")
}
// check role user
users, err := models.UserModel.GetUsersByRoleId(roleId)
if err != nil {
this.ErrorLog("删除角色 " + roleId + " 失败: " + err.Error())
this.jsonError("删除角色失败")
}
if len(users) > 0 {
this.jsonError("不能删除角色,请先移除该角色下用户!")
}
// delete role privilege by role id
err = models.RolePrivilegeModel.DeleteByRoleId(roleId)
if err != nil {
this.ErrorLog("删除角色 " + roleId + " 权限失败: " + err.Error())
this.jsonError("删除角色失败")
}
// delete role by role id
err = models.RoleModel.Delete(roleId)
if err != nil {
this.ErrorLog("删除角色 " + roleId + " 失败: " + err.Error())
this.jsonError("删除角色失败")
}
this.InfoLog("删除角色 " + roleId + " 成功")
this.jsonSuccess("删除角色成功", nil, "/system/role/list")
}
func (this *RoleController) ResetUser() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/role/list")
}
userId := this.GetString("user_id", "")
if userId == "" {
this.jsonError("用户不存在")
}
if this.UserId == "1" {
this.jsonError("root 用户不能重置角色!")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("重置用户 " + userId + " 角色失败: " + err.Error())
this.jsonError("重置用户角色失败")
}
if len(user) == 0 {
this.jsonError("用户不存在")
}
_, err = models.UserModel.Update(userId, map[string]interface{}{
"role_id": models.Role_Default_Id,
})
if err != nil {
this.ErrorLog("重置用户 " + userId + " 角色失败: " + err.Error())
this.jsonError("重置用户角色失败")
}
this.InfoLog("重置用户 " + userId + " 角色成功")
this.jsonSuccess("重置用户角色成功", nil, "/system/role/list")
}
+400
View File
@@ -0,0 +1,400 @@
package controllers
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
)
type SpaceController struct {
BaseController
}
func (this *SpaceController) Add() {
this.viewLayout("space/form", "space")
}
func (this *SpaceController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
name := strings.TrimSpace(this.GetString("name", ""))
description := strings.TrimSpace(this.GetString("description", ""))
tags := strings.TrimSpace(this.GetString("tags", ""))
visitLevel := strings.TrimSpace(this.GetString("visit_level", "public"))
isShare := strings.TrimSpace(this.GetString("is_share", "0"))
isExport := strings.TrimSpace(this.GetString("is_export", "0"))
if name == "" {
this.jsonError("空间名称不能为空!")
}
match, err := regexp.MatchString(`[\\\\/:*?\"<>、|]`, name)
if err != nil {
this.jsonError("空间名称格式不正确!")
}
if match {
this.jsonError("空间名称格式不正确!")
}
ok, err := models.SpaceModel.HasSpaceName(name)
if err != nil {
this.ErrorLog("添加空间失败:" + err.Error())
this.jsonError("添加空间失败!")
}
if ok {
this.jsonError("空间名已经存在!")
}
// create space database
spaceId, err := models.SpaceModel.Insert(map[string]interface{}{
"name": name,
"description": description,
"tags": tags,
"visit_level": strings.ToLower(visitLevel),
"is_share": isShare,
"is_export": isExport,
})
if err != nil {
this.ErrorLog("添加空间失败:" + err.Error())
this.jsonError("添加空间失败")
}
// create space document
spaceDocument := map[string]interface{}{
"space_id": fmt.Sprintf("%d", spaceId),
"parent_id": "0",
"name": name,
"type": models.Document_Type_Dir,
"path": "0",
"create_user_id": this.UserId,
"edit_user_id": this.UserId,
}
_, err = models.DocumentModel.Insert(spaceDocument)
if err != nil {
// delete space
models.SpaceModel.Delete(fmt.Sprintf("%d", spaceId))
this.ErrorLog("添加空间文档失败:" + err.Error())
this.jsonError("添加空间失败!")
}
// add space member
insertValue := map[string]interface{}{
"user_id": this.UserId,
"space_id": spaceId,
"privilege": models.SpaceUser_Privilege_Manager,
}
_, err = models.SpaceUserModel.Insert(insertValue)
if err != nil {
// delete space
models.SpaceModel.Delete(fmt.Sprintf("%d", spaceId))
this.ErrorLog("添加空间添加空间成员失败: " + err.Error())
this.jsonError("添加空间失败!")
}
this.InfoLog("添加空间 " + utils.Convert.IntToString(spaceId, 10) + " 成功")
this.jsonSuccess("添加空间成功", nil, "/system/space/list")
}
func (this *SpaceController) List() {
page, _ := this.GetInt("page", 1)
keyword := strings.TrimSpace(this.GetString("keyword", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
limit := (page - 1) * number
var err error
var count int64
var spaces []map[string]string
if keyword != "" {
count, err = models.SpaceModel.CountSpacesByKeyword(keyword)
spaces, err = models.SpaceModel.GetSpacesByKeywordAndLimit(keyword, limit, number)
} else {
count, err = models.SpaceModel.CountSpaces()
spaces, err = models.SpaceModel.GetSpacesByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取空间列表失败: " + err.Error())
this.ViewError("获取空间列表失败", "/system/main/index")
}
this.Data["spaces"] = spaces
this.Data["keyword"] = keyword
this.SetPaginator(number, count)
this.viewLayout("space/list", "space")
}
func (this *SpaceController) Edit() {
spaceId := this.GetString("space_id", "")
if spaceId == "" {
this.ViewError("空间不存在", "/system/space/list")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找空间失败: " + err.Error())
this.ViewError("查找空间失败", "/system/space/list")
}
if len(space) == 0 {
this.ViewError("空间不存在", "/system/space/list")
}
this.Data["space"] = space
this.viewLayout("space/form", "space")
}
func (this *SpaceController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
spaceId := this.GetString("space_id", "")
name := strings.TrimSpace(this.GetString("name", ""))
description := strings.TrimSpace(this.GetString("description", ""))
tags := strings.TrimSpace(this.GetString("tags", ""))
visitLevel := strings.TrimSpace(this.GetString("visit_level", "public"))
isShare := strings.TrimSpace(this.GetString("is_share", "0"))
isExport := strings.TrimSpace(this.GetString("is_export", "0"))
if spaceId == "" {
this.jsonError("空间不存在!")
}
if name == "" {
this.jsonError("空间名称不能为空!")
}
match, err := regexp.MatchString(`[\\\\/:*?\"<>、|]`, name)
if err != nil {
this.jsonError("空间名称格式不正确!")
}
if match {
this.jsonError("空间名称格式不正确!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("修改空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("修改空间失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
ok, _ := models.SpaceModel.HasSameName(spaceId, name)
if ok {
this.jsonError("空间名已经存在!")
}
spaceValue := map[string]interface{}{
"name": name,
"description": description,
"tags": tags,
"visit_level": visitLevel,
"is_share": isShare,
"is_export": isExport,
}
// update space document dir name if name update
_, err = models.SpaceModel.UpdateDBAndSpaceFileName(spaceId, spaceValue, space["name"])
if err != nil {
this.ErrorLog("修改空间 " + spaceId + " 失败:" + err.Error())
this.jsonError("修改空间失败")
}
this.InfoLog("修改空间 " + spaceId + " 成功")
this.jsonSuccess("修改空间成功", nil, "/system/space/list")
}
func (this *SpaceController) Member() {
page, _ := this.GetInt("page", 1)
spaceId := strings.TrimSpace(this.GetString("space_id", ""))
number, _ := this.GetRangeInt("number", 15, 10, 100)
if spaceId == "" {
this.ViewError("没有选择空间!")
}
limit := (page - 1) * number
count, err := models.SpaceUserModel.CountSpaceUsersBySpaceId(spaceId)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/system/space/list")
}
spaceUsers, err := models.SpaceUserModel.GetSpaceUsersBySpaceIdAndLimit(spaceId, limit, number)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/system/space/list")
}
var userIds = []string{}
for _, spaceUser := range spaceUsers {
userIds = append(userIds, spaceUser["user_id"])
}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/system/main/index")
}
for _, user := range users {
for _, spaceUser := range spaceUsers {
if spaceUser["user_id"] == user["user_id"] {
user["space_privilege"] = spaceUser["privilege"]
user["space_user_id"] = spaceUser["space_user_id"]
}
}
}
// 获取当前空间下的所有user
spaceAllUsers, err := models.SpaceUserModel.GetSpaceUsersBySpaceId(spaceId);
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间所有成员列表失败!", "/system/space/list")
}
var allUserIds = []string{}
for _, spaceUser := range spaceAllUsers {
allUserIds = append(allUserIds, spaceUser["user_id"])
}
var otherUsers = []map[string]string{}
if len(allUserIds) > 0 {
otherUsers, err = models.UserModel.GetUserByNotUserIds(allUserIds)
} else {
otherUsers, err = models.UserModel.GetUsers()
}
if err != nil {
this.ErrorLog("获取空间 " + spaceId + " 成员列表失败: " + err.Error())
this.ViewError("获取空间成员列表失败!", "/system/main/index")
}
this.Data["users"] = users
this.Data["space_id"] = spaceId
this.Data["otherUsers"] = otherUsers
this.SetPaginator(number, count)
this.viewLayout("space/member", "space")
}
func (this *SpaceController) Delete() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
spaceId := this.GetString("space_id", "")
if spaceId == "" {
this.jsonError("没有选择空间!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("删除空间失败")
}
if len(space) == 0 {
this.jsonError("空间不存在")
}
// check space documents
documents, err := models.DocumentModel.GetDocumentsBySpaceId(spaceId)
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("删除空间失败")
}
if len(documents) > 1 {
this.jsonError("不能删除空间,请先删除该空间下文档!")
} else if len(documents) == 1 {
if documents[0]["name"] != space["name"] {
this.jsonError("不能删除空间,请先删除该空间下文档!")
} else {
// delete space dir and documentId
_, pageFile, err := models.DocumentModel.GetParentDocumentsByDocument(documents[0])
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 获取空间文件失败: " + err.Error())
this.jsonError("删除空间失败")
}
err = models.DocumentModel.DeleteDBAndFile(documents[0]["document_id"], spaceId, this.UserId,
pageFile, fmt.Sprintf("%d", models.Document_Type_Dir))
// delete space document attachments
_ = models.AttachmentModel.DeleteAttachmentsDBFileByDocumentId(documents[0]["document_id"])
}
} else {
// delete space dir
err = utils.Document.DeleteSpace(space["name"])
}
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("删除空间失败")
}
// delete space user
err = models.SpaceUserModel.DeleteBySpaceId(spaceId)
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("删除空间失败")
}
// delete space and space document
err = models.SpaceModel.Delete(spaceId)
if err != nil {
this.ErrorLog("删除空间 " + spaceId + " 失败: " + err.Error())
this.jsonError("删除空间失败")
}
this.InfoLog("删除空间 " + spaceId + " 成功")
this.jsonSuccess("删除空间成功", nil, "/system/space/list")
}
func (this *SpaceController) Download() {
spaceId := this.GetString("space_id", "")
if spaceId == "" {
this.ViewError("空间不存在", "/system/space/list")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找空间失败: " + err.Error())
this.ViewError("查找空间失败", "/system/space/list")
}
if len(space) == 0 {
this.ViewError("空间不存在", "/system/space/list")
}
spaceName := space["name"]
spacePath := utils.Document.GetAbsPageFileByPageFile(spaceName)
packFiles := []*utils.CompressFileInfo{}
// pack space all markdown file
packFiles = append(packFiles, &utils.CompressFileInfo{
File: spacePath,
PrefixPath: "",
})
// get space all document attachments
attachments, err := models.AttachmentModel.GetAttachmentsBySpaceId(spaceId)
if err != nil {
this.ErrorLog("查找空间文档附件失败:" + err.Error())
this.ViewError("查找空间文档附件失败!")
}
for _, attachment := range attachments {
if attachment["path"] == "" {
continue
}
path := attachment["path"]
attachmentFile := filepath.Join(app.DocumentAbsDir, path)
packFile := &utils.CompressFileInfo{
File: attachmentFile,
PrefixPath: filepath.Dir(path),
}
packFiles = append(packFiles, packFile)
}
var dest = fmt.Sprintf("%s/mm_wiki/%s.zip", os.TempDir(), spaceName)
err = utils.Zipx.PackFile(packFiles, dest)
if err != nil {
this.ErrorLog("下载空间文档失败:" + err.Error())
this.ViewError("下载空间文档失败!")
}
this.Ctx.Output.Download(dest, spaceName+".zip")
}
@@ -0,0 +1,121 @@
package controllers
import (
"github.com/phachon/mm-wiki/app/models"
"strings"
"time"
)
type Space_UserController struct {
BaseController
}
func (this *Space_UserController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
spaceId := strings.TrimSpace(this.GetString("space_id", ""))
userId := this.GetString("user_id", "")
privilege := strings.TrimSpace(this.GetString("privilege", "0"))
if spaceId == "" {
this.jsonError("空间不存在!")
}
if userId == "" {
this.jsonError("没有选择用户!")
}
if privilege == "" {
this.jsonError("没有选择用户空间权限!")
}
space, err := models.SpaceModel.GetSpaceBySpaceId(spaceId)
if err != nil {
this.ErrorLog("添加空间 " + spaceId + " 成员 " + userId + " 失败: " + err.Error())
this.jsonError("添加空间成员失败!")
}
if len(space) == 0 {
this.jsonError("空间不存在!")
}
spaceUser, err := models.SpaceUserModel.GetSpaceUserBySpaceIdAndUserId(spaceId, userId)
if err != nil {
this.ErrorLog("添加空间 " + spaceId + " 成员 " + userId + " 失败: " + err.Error())
this.jsonError("添加空间成员失败!")
}
if len(spaceUser) > 0 {
this.jsonError("该用户已经是空间成员!")
}
insertValue := map[string]interface{}{
"user_id": userId,
"space_id": spaceId,
"privilege": privilege,
}
_, err = models.SpaceUserModel.Insert(insertValue)
if err != nil {
this.ErrorLog("空间 " + spaceId + " 添加成员 " + userId + " 失败: " + err.Error())
this.jsonError("添加成员失败!")
}
this.InfoLog("空间 " + spaceId + " 添加成员 " + userId + " 成功")
this.jsonSuccess("添加成员成功!", nil, "/system/space/member?space_id="+spaceId)
}
func (this *Space_UserController) Remove() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
spaceId := this.GetString("space_id", "")
userId := this.GetString("user_id", "")
spaceUserId := this.GetString("space_user_id", "")
if spaceUserId == "" {
this.jsonError("空间成员不存在!")
}
if spaceId == "" {
this.jsonError("空间不存在!")
}
if userId == "" {
this.jsonError("用户不存在!")
}
err := models.SpaceUserModel.Delete(spaceUserId)
if err != nil {
this.ErrorLog("移除空间 " + spaceId + " 下成员 " + userId + " 失败:" + err.Error())
this.jsonError("移除成员失败!")
}
this.InfoLog("移除空间 " + spaceId + " 下成员 " + userId + " 成功")
this.jsonSuccess("移除成员成功!", nil, "/system/space/member?space_id="+spaceId)
}
func (this *Space_UserController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/space/list")
}
spaceUserId := this.GetString("space_user_id", "")
privilege := this.GetString("privilege", "0")
userId := this.GetString("user_id", "")
spaceId := this.GetString("space_id", "")
if spaceUserId == "" {
this.jsonError("更新权限错误!")
}
if privilege == "" {
this.jsonError("没有选择权限!")
}
_, err := models.SpaceUserModel.Update(spaceUserId, map[string]interface{}{
"privilege": privilege,
"update_time": time.Now().Unix(),
})
if err != nil {
this.ErrorLog("更新空间 " + spaceId + " 下成员 " + userId + " 权限失败:" + err.Error())
this.jsonError("更新权限失败!")
}
this.InfoLog("更新空间 " + spaceId + " 下成员 " + userId + " 权限成功")
this.jsonSuccess("更新权限成功!", nil)
}
+291
View File
@@ -0,0 +1,291 @@
package controllers
import (
"fmt"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/mem"
"time"
)
type StaticController struct {
BaseController
}
func (this *StaticController) Default() {
normalUserCount, err := models.UserModel.CountNormalUsers()
if err != nil {
this.ErrorLog("查找正常用户数出错:" + err.Error())
this.jsonError("查找数据出错")
}
forbiddenUserCount, err := models.UserModel.CountForbiddenUsers()
if err != nil {
this.ErrorLog("查找屏蔽用户数出错:" + err.Error())
this.jsonError("查找数据出错")
}
spaceCount, err := models.SpaceModel.CountSpaces()
if err != nil {
this.ErrorLog("查找空间总数出错:" + err.Error())
this.jsonError("查找数据出错")
}
documentCount, err := models.DocumentModel.CountDocuments()
if err != nil {
this.ErrorLog("查找文档总数出错:" + err.Error())
this.jsonError("查找数据出错")
}
time.Now().Unix()
today := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Local).Unix()
todayLoginUserCount, err := models.UserModel.CountUsersByLastTime(today)
if err != nil {
this.ErrorLog("查找今日登录用户数出错:" + err.Error())
this.jsonError("查找数据出错")
}
createUserId := "0"
createUserIds, err := models.DocumentModel.GetDocumentGroupCreateUserId()
if err != nil {
this.ErrorLog("查找创建文档最多用户出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(createUserIds) > 0 {
createUserId = createUserIds[0]["create_user_id"]
}
editUserId := "0"
editUserIds, err := models.DocumentModel.GetDocumentGroupEditUserId()
if err != nil {
this.ErrorLog("查找修改文档最多用户出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(editUserIds) > 0 {
editUserId = editUserIds[0]["edit_user_id"]
}
collectUserId := "0"
collectUserIds, err := models.CollectionModel.GetCollectionGroupUserId(models.Collection_Type_Doc)
if err != nil {
this.ErrorLog("查找收藏文档最多用户出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(collectUserIds) > 0 {
collectUserId = collectUserIds[0]["user_id"]
}
fansUserId := "0"
fansUserIds, err := models.FollowModel.GetFansUserGroupUserId()
if err != nil {
this.ErrorLog("查找粉丝数最多用户出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(fansUserIds) > 0 {
fansUserId = fansUserIds[0]["object_id"]
}
userIds := []string{createUserId, editUserId, collectUserId, fansUserId}
users, err := models.UserModel.GetUsersByUserIds(userIds)
if err != nil {
this.ErrorLog("查找文档总数出错:" + err.Error())
this.jsonError("查找数据出错")
}
var createMaxUser = map[string]string{"user_id": createUserId, "username": ""}
var editMaxUser = map[string]string{"user_id": editUserId, "username": ""}
var collectMaxUser = map[string]string{"user_id": collectUserId, "username": ""}
var fansMaxUser = map[string]string{"user_id": fansUserId, "username": ""}
for _, user := range users {
if user["user_id"] == createUserId {
createMaxUser["username"] = user["username"]
}
if user["user_id"] == editUserId {
editMaxUser["username"] = user["username"]
}
if user["user_id"] == collectUserId {
collectMaxUser["username"] = user["username"]
}
if user["user_id"] == fansUserId {
fansMaxUser["username"] = user["username"]
}
}
this.Data["normalUserCount"] = normalUserCount
this.Data["forbiddenUserCount"] = forbiddenUserCount
this.Data["spaceCount"] = spaceCount
this.Data["documentCount"] = documentCount
this.Data["todayLoginUserCount"] = todayLoginUserCount
this.Data["createMaxUser"] = createMaxUser
this.Data["editMaxUser"] = editMaxUser
this.Data["collectMaxUser"] = collectMaxUser
this.Data["fansMaxUser"] = fansMaxUser
this.viewLayout("static/default", "static")
}
func (this *StaticController) SpaceDocsRank() {
number, _ := this.GetInt("number", 15)
spaceDocsRank := []map[string]string{}
spaceDocCountIds, err := models.DocumentModel.GetSpaceIdsOrderByCountDocumentLimit(number)
if err != nil {
this.ErrorLog("查找空间文档排行出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(spaceDocCountIds) > 0 {
spaceIds := []string{}
for _, spaceDocCountId := range spaceDocCountIds {
spaceIds = append(spaceIds, spaceDocCountId["space_id"])
}
spaces, err := models.SpaceModel.GetSpaceBySpaceIds(spaceIds)
if err != nil {
this.ErrorLog("查找空间文档排行出错:" + err.Error())
this.jsonError("查找数据出错")
}
for _, spaceDocCountId := range spaceDocCountIds {
spaceDocCount := map[string]string{
"space_name": "",
"total": spaceDocCountId["total"],
}
for _, space := range spaces {
if spaceDocCountId["space_id"] == space["space_id"] {
spaceDocCount["space_name"] = space["name"]
break
}
}
spaceDocsRank = append(spaceDocsRank, spaceDocCount)
}
}
this.jsonSuccess("ok", spaceDocsRank)
}
func (this *StaticController) CollectDocRank() {
number, _ := this.GetInt("number", 10)
collectDocsRank := []map[string]string{}
collectionDocIds, err := models.CollectionModel.GetResourceIdsOrderByCountLimit(number, models.Collection_Type_Doc)
if err != nil {
this.ErrorLog("查找收藏文档排行出错:" + err.Error())
this.jsonError("查找数据出错")
}
if len(collectionDocIds) > 0 {
documentIds := []string{}
for _, collectionDocId := range collectionDocIds {
documentIds = append(documentIds, collectionDocId["resource_id"])
}
documents, err := models.DocumentModel.GetDocumentsByDocumentIds(documentIds)
if err != nil {
this.ErrorLog("查找收藏文档排行出错:" + err.Error())
this.jsonError("查找数据出错")
}
for _, collectionDocId := range collectionDocIds {
collectDocCount := map[string]string{
"document_name": "",
"total": collectionDocId["total"],
}
for _, document := range documents {
if collectionDocId["resource_id"] == document["document_id"] {
collectDocCount["document_name"] = document["name"]
break
}
}
collectDocsRank = append(collectDocsRank, collectDocCount)
}
}
this.jsonSuccess("ok", collectDocsRank)
}
func (this *StaticController) DocCountByTime() {
limitDay, _ := this.GetInt("limit_day", 10)
startTime := time.Now().Unix() - int64(limitDay*3600*24)
documentCountDate, err := models.DocumentModel.GetCountGroupByCreateTime(startTime)
if err != nil {
this.ErrorLog("查找文档数量增长趋势出错:" + err.Error())
this.jsonError("查找文档数量增长趋势出错")
}
this.jsonSuccess("ok", documentCountDate)
}
func (this *StaticController) Monitor() {
hostInfo, err := host.Info()
if err != nil {
this.ErrorLog("获取服务器数据错误")
}
serverInfo := map[string]string{
"localIp": utils.Misc.GetLocalIp(),
"hostname": hostInfo.Hostname,
"os": hostInfo.OS,
"platform": hostInfo.Platform,
"platformFamily": hostInfo.PlatformFamily,
}
errorLogCount, err := models.LogModel.CountLogsByLevel(models.Log_Level_Error)
if err != nil {
this.ErrorLog("获取数据错误")
}
errLogs, err := models.LogModel.GetLogsByKeywordAndLimit(fmt.Sprintf("%d", models.Log_Level_Error), "", "", 0, 5)
if err != nil {
this.ErrorLog("获取数据错误")
}
this.Data["serverInfo"] = serverInfo
this.Data["errorLogCount"] = errorLogCount
this.Data["errLogs"] = errLogs
this.viewLayout("static/monitor", "static")
}
func (this *StaticController) ServerStatus() {
memoryUsedPercent := 0
cpuUsedPercent := 0
diskUsedPercent := 0
vm, err := mem.VirtualMemory()
if err != nil {
logs.Error("get memory err=%s", err.Error())
}
if vm != nil {
memoryUsedPercent = int(vm.UsedPercent)
}
cpuPercent, _ := cpu.Percent(0, false)
if len(cpuPercent) > 0 {
cpuUsedPercent = int(cpuPercent[0])
}
d, err := disk.Usage("/")
if err != nil {
logs.Error("get disk err=%s", err.Error())
}
if d != nil {
diskUsedPercent = int(d.UsedPercent)
}
data := map[string]interface{}{
"memory_used_percent": memoryUsedPercent,
"cpu_used_percent": cpuUsedPercent,
"disk_used_percent": diskUsedPercent,
}
this.jsonSuccess("ok", data)
}
func (this *StaticController) ServerTime() {
data := map[string]interface{}{
"server_time": time.Now().Unix(),
"run_time": time.Now().Unix() - app.StartTime,
}
this.jsonSuccess("ok", data)
}
+395
View File
@@ -0,0 +1,395 @@
package controllers
import (
"fmt"
"github.com/astaxie/beego/validation"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/utils"
"strings"
)
type UserController struct {
BaseController
}
func (this *UserController) Add() {
roles := []map[string]string{}
var err error
if this.IsRoot() {
roles, err = models.RoleModel.GetRoles()
} else {
roles, err = models.RoleModel.GetRolesNotContainRoot()
}
if err != nil {
this.ErrorLog("获取用户角色失败:" + err.Error())
this.ViewError("获取用户角色失败!")
}
this.Data["roles"] = roles
this.viewLayout("user/form", "user")
}
func (this *UserController) Save() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/user/add")
}
username := strings.TrimSpace(this.GetString("username", ""))
givenName := strings.TrimSpace(this.GetString("given_name", ""))
password := strings.TrimSpace(this.GetString("password", ""))
email := strings.TrimSpace(this.GetString("email", ""))
mobile := strings.TrimSpace(this.GetString("mobile", ""))
roleId := strings.TrimSpace(this.GetString("role_id", ""))
phone := strings.TrimSpace(this.GetString("phone", ""))
department := strings.TrimSpace(this.GetString("department", ""))
position := strings.TrimSpace(this.GetString("position", ""))
location := strings.TrimSpace(this.GetString("location", ""))
im := strings.TrimSpace(this.GetString("im", ""))
this.Ctx.Request.PostForm.Del("password")
v := validation.Validation{}
if username == "" {
this.jsonError("用户名不能为空!")
}
if !v.AlphaNumeric(username, "username").Ok {
this.jsonError("用户名格式不正确!")
}
if givenName == "" {
this.jsonError("姓名不能为空!")
}
if password == "" {
this.jsonError("密码不能为空!")
}
if email == "" {
this.jsonError("邮箱不能为空!")
}
if !v.Email(email, "email").Ok {
this.jsonError("邮箱格式不正确!")
}
if mobile == "" {
this.jsonError("手机号不能为空!")
}
//if !v.Mobile(mobile, "mobile").Ok {
// this.jsonError("手机号格式不正确!")
//}
if roleId == "" {
this.jsonError("没有选择角色!")
}
//if phone != "" && !v.Phone(phone, "phone").Ok {
// this.jsonError("电话格式不正确!")
//}
ok, err := models.UserModel.HasUsername(username)
if err != nil {
this.ErrorLog("添加用户失败:" + err.Error())
this.jsonError("添加用户失败!")
}
if ok {
this.jsonError("用户名已经存在!")
}
if !this.IsRoot() && roleId == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("没有权限添加超级管理员!")
}
userId, err := models.UserModel.Insert(map[string]interface{}{
"username": username,
"given_name": givenName,
"password": models.UserModel.EncodePassword(password),
"email": email,
"mobile": mobile,
"phone": phone,
"department": department,
"position": position,
"location": location,
"im": im,
"role_id": roleId,
})
if err != nil {
this.ErrorLog("添加用户失败:" + err.Error())
this.jsonError("添加用户失败")
}
this.InfoLog("添加用户 " + utils.Convert.IntToString(userId, 10) + " 成功")
this.jsonSuccess("添加用户成功", nil, "/system/user/list")
}
func (this *UserController) List() {
keywords := map[string]string{}
page, _ := this.GetInt("page", 1)
username := strings.TrimSpace(this.GetString("username", ""))
roleId := strings.TrimSpace(this.GetString("role_id", ""))
number, _ := this.GetRangeInt("number", 20, 10, 100)
if username != "" {
keywords["username"] = username
}
if roleId != "" {
keywords["role_id"] = roleId
}
limit := (page - 1) * number
var err error
var count int64
var users []map[string]string
if len(keywords) != 0 {
count, err = models.UserModel.CountUsersByKeywords(keywords)
users, err = models.UserModel.GetUsersByKeywordsAndLimit(keywords, limit, number)
} else {
count, err = models.UserModel.CountUsers()
users, err = models.UserModel.GetUsersByLimit(limit, number)
}
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取用户列表失败", "/system/main/index")
}
var roleIds = []string{}
if roleId != "" {
roleIds = append(roleIds, roleId)
} else {
for _, user := range users {
roleIds = append(roleIds, user["role_id"])
}
}
roles, err := models.RoleModel.GetRoleByRoleIds(roleIds)
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取用户列表失败!", "/system/main/index")
}
var roleUsers = []map[string]string{}
for _, user := range users {
roleUser := user
for _, role := range roles {
if role["role_id"] == user["role_id"] {
roleUser["role_name"] = role["name"]
break
}
}
roleUsers = append(roleUsers, roleUser)
}
allRoles, err := models.RoleModel.GetRoles()
if err != nil {
this.ErrorLog("获取用户列表失败: " + err.Error())
this.ViewError("获取用户列表失败!", "/system/main/index")
}
this.Data["users"] = roleUsers
this.Data["username"] = username
this.Data["roleId"] = roleId
this.Data["roles"] = allRoles
this.SetPaginator(number, count)
this.viewLayout("user/list", "user")
}
func (this *UserController) Edit() {
userId := this.GetString("user_id", "")
if userId == "" {
this.ViewError("用户不存在!", "/system/user/list")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("查找用户出错:" + err.Error())
this.ViewError("查找用户出错!", "/system/user/list")
}
if len(user) == 0 {
this.ViewError("用户不存在!", "/system/user/list")
}
// 登录非 root 用户不能修改 root 用户信息
if user["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) && !this.IsRoot() {
this.ViewError("没有权限修改!", "/system/user/list")
}
roles := []map[string]string{}
if this.IsRoot() {
roles, err = models.RoleModel.GetRoles()
} else {
roles, err = models.RoleModel.GetRolesNotContainRoot()
}
if err != nil {
this.ErrorLog("获取用户角色失败:" + err.Error())
this.ViewError("获取用户角色失败!")
}
this.Data["user"] = user
this.Data["roles"] = roles
this.viewLayout("user/edit", "user")
}
func (this *UserController) Modify() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/user/list")
}
userId := strings.TrimSpace(this.GetString("user_id", ""))
givenName := strings.TrimSpace(this.GetString("given_name", ""))
email := strings.TrimSpace(this.GetString("email", ""))
mobile := strings.TrimSpace(this.GetString("mobile", ""))
roleId := strings.TrimSpace(this.GetString("role_id", ""))
phone := strings.TrimSpace(this.GetString("phone", ""))
department := strings.TrimSpace(this.GetString("department", ""))
position := strings.TrimSpace(this.GetString("position", ""))
location := strings.TrimSpace(this.GetString("location", ""))
im := strings.TrimSpace(this.GetString("im", ""))
password := strings.TrimSpace(this.GetString("password", ""))
this.Ctx.Request.PostForm.Del("password")
v := validation.Validation{}
if givenName == "" {
this.jsonError("姓名不能为空!")
}
if email == "" {
this.jsonError("邮箱不能为空!")
}
if !v.Email(email, "email").Ok {
this.jsonError("邮箱格式不正确!")
}
if mobile == "" {
this.jsonError("手机号不能为空!")
}
//if !v.Mobile(mobile, "mobile").Ok {
// this.jsonError("手机号格式不正确!")
//}
//if roleId == "" {
// this.jsonError("没有选择角色!")
//}
//if phone != "" && !v.Phone(phone, "phone").Ok {
// this.jsonError("电话格式不正确!")
//}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("修改用户 " + userId + " 失败:" + err.Error())
this.jsonError("修改用户出错!")
}
if len(user) == 0 {
this.jsonError("用户不存在!")
}
if user["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
roleId = fmt.Sprintf("%d", models.Role_Root_Id)
}
// 登录非 root 用户不能修改 root 用户信息
if user["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) && !this.IsRoot() {
this.jsonError("没有权限修改!")
}
updateUser := map[string]interface{}{
"given_name": givenName,
"email": email,
"mobile": mobile,
"phone": phone,
"department": department,
"position": position,
"location": location,
"im": im,
}
// 超级管理员才可以修改其他用户密码
if password != "" && this.IsRoot() {
updateUser["password"] = models.UserModel.EncodePassword(password)
}
if roleId != "" {
updateUser["role_id"] = roleId
}
_, err = models.UserModel.Update(userId, updateUser)
if err != nil {
this.ErrorLog("修改用户 " + userId + " 失败:" + err.Error())
this.jsonError("修改用户失败")
}
this.InfoLog("修改用户 " + userId + " 成功")
this.jsonSuccess("修改用户成功", nil, "/system/user/list")
}
func (this *UserController) Forbidden() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/user/list")
}
userId := this.GetString("user_id", "")
if userId == "" {
this.jsonError("用户不存在")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("屏蔽用户 " + userId + " 失败: " + err.Error())
this.jsonError("屏蔽用户失败")
}
if len(user) == 0 {
this.jsonError("用户不存在")
}
if user["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("不能操作超级管理员")
}
_, err = models.UserModel.Update(userId, map[string]interface{}{
"is_forbidden": models.User_Forbidden_True,
})
if err != nil {
this.ErrorLog("屏蔽用户 " + userId + " 失败: " + err.Error())
this.jsonError("屏蔽用户失败")
}
this.InfoLog("屏蔽用户 " + userId + " 成功")
this.jsonSuccess("屏蔽用户成功", nil, "/system/user/list")
}
func (this *UserController) Recover() {
if !this.IsPost() {
this.ViewError("请求方式有误!", "/system/user/list")
}
userId := this.GetString("user_id", "")
if userId == "" {
this.jsonError("用户不存在")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("恢复用户 " + userId + " 失败: " + err.Error())
this.jsonError("恢复用户失败")
}
if len(user) == 0 {
this.jsonError("用户不存在")
}
if user["role_id"] == fmt.Sprintf("%d", models.Role_Root_Id) {
this.jsonError("不能操作超级管理员")
}
_, err = models.UserModel.Update(userId, map[string]interface{}{
"is_forbidden": models.User_Is_Forbidden_False,
})
if err != nil {
this.ErrorLog("恢复用户 " + userId + " 失败: " + err.Error())
this.jsonError("恢复用户失败")
}
this.InfoLog("恢复用户 " + userId + " 成功")
this.jsonSuccess("恢复用户成功", nil, "/system/user/list")
}
func (this *UserController) Info() {
userId := this.GetString("user_id", "")
if userId == "" {
this.ViewError("用户不存在!", "/system/user/list")
}
user, err := models.UserModel.GetUserByUserId(userId)
if err != nil {
this.ErrorLog("查找用户出错:" + err.Error())
this.ViewError("查找用户出错!", "/system/user/list")
}
if len(user) == 0 {
this.ViewError("用户不存在!", "/system/user/list")
}
role, err := models.RoleModel.GetRoleByRoleId(user["role_id"])
if err != nil {
this.ErrorLog("查找用户角色出错:" + err.Error())
this.ViewError("查找用户出错!", "/system/user/list")
}
this.Data["user"] = user
this.Data["role"] = role
this.viewLayout("user/info", "user")
}
+110
View File
@@ -0,0 +1,110 @@
package services
import (
"fmt"
"github.com/phachon/mm-wiki/app/models"
"net/url"
)
// AuthLoginResponse auth login response result
type AuthLoginResponse struct {
GivenName string `json:"given_name"`
Email string `json:"email"`
Mobile string `json:"mobile"`
Phone string `json:"phone"`
Department string `json:"department"`
Position string `json:"position"`
Location string `json:"location"`
Im string `json:"im"`
}
const (
AuthLoginProtocolHttp = "http"
AuthLoginProtocolHttps = "https"
AuthLoginProtocolLdap = "ldap"
AuthLoginProtocolLdaps = "ldaps"
)
// AuthLoginService auth login service
type AuthLoginService interface {
// Init init login config
InitConf(url string, conf string) error
// GetServiceName get auth login service name
GetServiceName() string
// AuthLogin auth login request
AuthLogin(username string, password string) (*AuthLoginResponse, error)
}
var AuthLogin = NewAuthLoginManager()
// AuthLoginManager auth login manager
type AuthLoginManager struct {
AuthLoginServices map[string]AuthLoginService
}
// NewAuthLoginManager new a auth login manager
func NewAuthLoginManager() *AuthLoginManager {
authLoginManager := &AuthLoginManager{
AuthLoginServices: make(map[string]AuthLoginService),
}
return authLoginManager
}
// RegisterService register a auth login service
func (am *AuthLoginManager) RegisterService(serviceName string, authLoginService AuthLoginService) {
if authLoginService == nil {
return
}
if _, ok := am.AuthLoginServices[serviceName]; ok {
panic(fmt.Sprintf("[AuthLoginManager] RegisterService '%s' already exists", serviceName))
}
am.AuthLoginServices[serviceName] = authLoginService
}
func (am *AuthLoginManager) UrlIsSupport(serviceName string) bool {
if _, ok := am.AuthLoginServices[serviceName]; ok {
return true
}
return false
}
// AuthLogin start auth login
func (am *AuthLoginManager) AuthLogin(username, password string) (*AuthLoginResponse, error) {
// get auth login config
authLogin, err := models.AuthModel.GetUsedAuth()
if err != nil {
return nil, fmt.Errorf("查找登录配置失败")
}
if len(authLogin) == 0 {
return nil, fmt.Errorf("没有可用的统一登录配置")
}
// parse url protocol
authUrl, ok := authLogin["url"]
if !ok || authUrl == "" {
return nil, fmt.Errorf("登录配置 url 无效")
}
u, err := url.Parse(authUrl)
if err != nil {
return nil, fmt.Errorf("登录配置 url 不合法:%s", err.Error())
}
serviceName := u.Scheme
authLoginService, ok := am.AuthLoginServices[serviceName]
if !ok {
return nil, fmt.Errorf("登录配置 url 协议不支持")
}
serviceConf := ""
if extData, ok := authLogin["ext_data"]; ok {
serviceConf = extData
}
// init auth login service config
err = authLoginService.InitConf(authUrl, serviceConf)
if err != nil {
return nil, fmt.Errorf("登录配置初始化失败:%s", err.Error())
}
// start auth login
return authLoginService.AuthLogin(username, password)
}
+71
View File
@@ -0,0 +1,71 @@
package services
import (
"encoding/json"
"fmt"
"github.com/phachon/mm-wiki/app/utils"
)
type AuthLoginHttpRes struct {
Message string `json:"message"`
Data *AuthLoginResponse `json:"data"`
}
// AuthLoinHttpService http auth login
type AuthLoinHttpService struct {
url string
extData string
}
// NewAuthLoginHttpService
func NewAuthLoginHttpService() AuthLoginService {
return &AuthLoinHttpService{}
}
// InitConf init http auth login config
func (ah *AuthLoinHttpService) InitConf(url string, conf string) error {
ah.url = url
ah.extData = conf
return nil
}
// AuthLogin send http request
func (ah *AuthLoinHttpService) AuthLogin(username string, password string) (*AuthLoginResponse, error) {
if ah.url == "" {
return nil, fmt.Errorf("authLogin url is empty")
}
queryValue := map[string]string{
"username": username,
"password": password,
"ext_data": ah.extData,
}
// request auth login api
body, code, err := utils.Request.HttpPost(ah.url, queryValue, nil)
if err != nil {
return nil, err
}
if len(body) == 0 {
return nil, fmt.Errorf("登录认证失败, httpCode=%d", code)
}
v := &AuthLoginHttpRes{}
err = json.Unmarshal(body, &v)
if err != nil {
return nil, fmt.Errorf("登录认证失败,返回结果不合法 err=%s", err.Error())
}
if v.Message != "" {
return nil, fmt.Errorf("登录认证失败, message=%s", v.Message)
}
return v.Data, nil
}
// GetServiceName http
func (ah *AuthLoinHttpService) GetServiceName() string {
return AuthLoginProtocolHttp
}
func init() {
// http://xxx
AuthLogin.RegisterService(AuthLoginProtocolHttp, NewAuthLoginHttpService())
// https://xxx
AuthLogin.RegisterService(AuthLoginProtocolHttps, NewAuthLoginHttpService())
}
+163
View File
@@ -0,0 +1,163 @@
package services
import (
"encoding/json"
"errors"
"fmt"
"github.com/go-ldap/ldap/v3"
)
const (
LdapDefaultAccountPattern = "(&(objectClass=User)(userPrincipalName=%s))"
LdapDefaultAttributeGivenName = "displayName"
)
var (
LdapUserSearchNotFoundErr = errors.New("用户不存在或密码错误")
)
type AuthLoginConfig struct {
BaseDn string `json:"basedn"`
BindUsername string `json:"bind_username"`
BindPassword string `json:"bind_password"`
AccountPattern string `json:"account_pattern"`
GivenNameKey string `json:"given_name_key"`
EmailKey string `json:"email_key"`
MobileKey string `json:"mobile_key"`
PhoneKey string `json:"phone_key"`
DepartmentKey string `json:"department_key"`
PositionKey string `json:"position_key"`
LocationKey string `json:"location_key"`
ImKey string `json:"im_key"`
}
// AuthLoginLdapService ldap auth login
type AuthLoginLdapService struct {
url string
conf string
config *AuthLoginConfig
}
// NewAuthLoginLdapService
func NewAuthLoginLdapService() AuthLoginService {
return &AuthLoginLdapService{}
}
// InitConf init ldap auth login config
func (al *AuthLoginLdapService) InitConf(url string, conf string) error {
al.url = url
al.conf = conf
authLoginConfig := &AuthLoginConfig{}
err := json.Unmarshal([]byte(conf), &authLoginConfig)
if err != nil {
return err
}
al.config = authLoginConfig
if al.config.AccountPattern == "" {
al.config.AccountPattern = LdapDefaultAccountPattern
}
if al.config.GivenNameKey == "" {
al.config.GivenNameKey = LdapDefaultAttributeGivenName
}
return nil
}
// AuthLogin ldap auth
func (al *AuthLoginLdapService) AuthLogin(username string, password string) (*AuthLoginResponse, error) {
if al.url == "" {
return nil, fmt.Errorf("LDAP URL is empty")
}
if al.config == nil || al.conf == "" {
return nil, fmt.Errorf("LDAP 配置数据错误")
}
if al.config.GivenNameKey == "" {
return nil, fmt.Errorf("LDAP 配置 given_name_key 错误")
}
lc, err := ldap.DialURL(al.url)
if err != nil {
return nil, fmt.Errorf("连接 LDAP 服务失败, err=%s", err.Error())
}
defer lc.Close()
// bind 用户
if al.config.BindPassword != "" {
err = lc.Bind(al.config.BindUsername, al.config.BindPassword)
} else {
err = lc.UnauthenticatedBind(al.config.BindUsername)
}
if err != nil {
return nil, fmt.Errorf("绑定 LDAP 用户失败, err=%s", err.Error())
}
// 搜索下用户信息
searchRequest := ldap.NewSearchRequest(
al.config.BaseDn,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
fmt.Sprintf(al.config.AccountPattern, username),
al.GetAttributes(),
nil,
)
searchResult, err := lc.Search(searchRequest)
if err != nil {
return nil, fmt.Errorf("查找 LDAP 用户失败, err=%s", err.Error())
}
if len(searchResult.Entries) != 1 {
return nil, LdapUserSearchNotFoundErr
}
// 验证下用户密码
userDN := searchResult.Entries[0].DN
err = lc.Bind(userDN, password)
if err != nil {
return nil, err
}
result := &AuthLoginResponse{
GivenName: searchResult.Entries[0].GetAttributeValue(al.config.GivenNameKey),
Email: searchResult.Entries[0].GetAttributeValue(al.config.EmailKey),
Mobile: searchResult.Entries[0].GetAttributeValue(al.config.MobileKey),
Phone: searchResult.Entries[0].GetAttributeValue(al.config.PhoneKey),
Department: searchResult.Entries[0].GetAttributeValue(al.config.DepartmentKey),
Position: searchResult.Entries[0].GetAttributeValue(al.config.PositionKey),
Location: searchResult.Entries[0].GetAttributeValue(al.config.LocationKey),
Im: searchResult.Entries[0].GetAttributeValue(al.config.ImKey),
}
return result, nil
}
// GetAttributes get config attribute name
func (al *AuthLoginLdapService) GetAttributes() []string {
attributes := []string{"dn"}
confAttributes := []string{
"dn", al.config.GivenNameKey, al.config.EmailKey,
al.config.MobileKey, al.config.PhoneKey, al.config.DepartmentKey,
al.config.PositionKey, al.config.LocationKey, al.config.ImKey,
}
for _, confAttribute := range confAttributes {
if confAttribute == "" {
continue
}
attributes = append(attributes, confAttribute)
}
return attributes
}
// GetServiceName ldap
func (al *AuthLoginLdapService) GetServiceName() string {
return AuthLoginProtocolLdap
}
func init() {
// ldap://xxx
AuthLogin.RegisterService(AuthLoginProtocolLdap, NewAuthLoginLdapService())
// ldaps://xxx
AuthLogin.RegisterService(AuthLoginProtocolLdaps, NewAuthLoginLdapService())
}
+140
View File
@@ -0,0 +1,140 @@
package services
import (
"sync"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app/models"
)
var DocIndexService = NewDocIndexService()
type DocIndex struct {
}
func NewDocIndexService() *DocIndex {
return &DocIndex{}
}
func (di *DocIndex) IsUpdateDocIndex() bool {
//fulltextSearchOpen := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyFulltextSearch, "0")
//if fulltextSearchOpen == "1" {
// return true
//}
return false
}
// ForceDelDocIdIndex 强制删除索引
func (di *DocIndex) ForceDelDocIdIndex(docId string) {
if docId == "" {
return
}
if !di.IsUpdateDocIndex() {
return
}
// todo add search index
}
// UpdateDocIndex 更新单个文件的索引
func (di *DocIndex) ForceUpdateDocIndexByDocId(docId string) error {
if docId == "" {
return nil
}
if !di.IsUpdateDocIndex() {
return nil
}
doc, err := models.DocumentModel.GetDocumentByDocumentId(docId)
if err != nil {
return err
}
_, _, err = models.DocumentModel.GetDocumentContentByDocument(doc)
if err != nil {
return err
}
// todo add search index
return nil
}
// UpdateDocIndex 更新单个文件的索引
func (di *DocIndex) UpdateDocIndex(doc map[string]string) {
docId, ok := doc["document_id"]
if !ok || docId == "" {
return
}
if !di.IsUpdateDocIndex() {
return
}
_, _, err := models.DocumentModel.GetDocumentContentByDocument(doc)
if err != nil {
logs.Error("[UpdateDocIndex] get documentId=%s content err: %s", docId, err.Error())
return
}
// todo add search index
}
// UpdateDocsIndex 批量更新多个文件的索引
func (di *DocIndex) UpdateDocsIndex(docs []map[string]string) {
if len(docs) == 0 {
return
}
wait := sync.WaitGroup{}
for _, doc := range docs {
if len(doc) == 0 {
continue
}
wait.Add(1)
go func(doc map[string]string) {
docId, _ := doc["document_id"]
defer func() {
if e := recover(); e != nil {
logs.Error("[UpdateAllDocIndex] get documentId=%s content panic: %v", docId, e)
}
wait.Done()
}()
di.UpdateDocIndex(doc)
}(doc)
}
wait.Wait()
}
// UpdateAllDocIndex 更新所有的文档
func (di *DocIndex) UpdateAllDocIndex(batchNum int) {
if !di.IsUpdateDocIndex() {
return
}
allDocs, err := models.DocumentModel.GetAllDocuments()
if err != nil {
logs.Error("[UpdateAllDocIndex] getAllDocuments err: %s", err.Error())
return
}
batchDocs := di.getBatchDocs(allDocs, batchNum)
for _, docs := range batchDocs {
di.UpdateDocsIndex(docs)
}
}
// 获取分批文档
func (di *DocIndex) getBatchDocs(allDocs []map[string]string, n int) [][]map[string]string {
groupNum := len(allDocs) / n
remainder := len(allDocs) % n
res := [][]map[string]string{}
if groupNum == 0 {
res = append(res, allDocs)
return res
}
for i := 0; i < groupNum; i++ {
offset := i * n
resItem := allDocs[offset : n+offset]
res = append(res, resItem)
}
if remainder > 0 {
res = append(res, allDocs[len(allDocs)-remainder:])
}
return res
}
// FlushIndex 所有索引
func (di *DocIndex) Flush() {
}
+84
View File
@@ -0,0 +1,84 @@
package utils
import (
"fmt"
"reflect"
"strconv"
)
var Convert = NewConvert()
type convert struct{}
func NewConvert() *convert {
return &convert{}
}
// bool 转化为字符串
func (c *convert) BoolToString(boolValue bool) string {
if boolValue == true {
return "true"
} else {
return "false"
}
}
//bool 转化为 int
func (c *convert) BoolToInt(boolValue bool) int {
if boolValue == true {
return 1
} else {
return 0
}
}
//int 转化为 bool
func (c *convert) IntToBool(number int) bool {
if number == 0 {
return false
} else {
return true
}
}
//int 转化为字符串
//base 范围 2-32 进制
func (c *convert) IntToString(number int64, base int) string {
return strconv.FormatInt(number, base)
}
//string to int(10进制)
func (c *convert) StringToInt(str string) int {
intValue, _ := strconv.Atoi(str)
return intValue
}
// string to int64(10进制)
func (c *convert) StringToInt64(str string) int64 {
intValue, _ := strconv.ParseInt(str, 10, 64)
return intValue
}
// int 转化为10进制字符串 IntToString(number, 10)
func (c *convert) IntToTenString(number int) string {
return strconv.Itoa(number)
}
// float 转化为字符串
func (c *convert) FloatToString(f float64, fmt byte, prec, bitSize int) string {
return strconv.FormatFloat(f, fmt, prec, bitSize)
}
// 转化任何的数为 int64
func (c *convert) ToInt64(value interface{}) (d int64, err error) {
val := reflect.ValueOf(value)
switch value.(type) {
case int, int8, int16, int32, int64:
d = val.Int()
case uint, uint8, uint16, uint32, uint64:
d = int64(val.Uint())
default:
err = fmt.Errorf("ToInt64 need numeric not `%T`", value)
}
return
}
+33
View File
@@ -0,0 +1,33 @@
package utils
import (
"github.com/astaxie/beego"
"time"
)
var Date = NewDate()
type date struct{}
func NewDate() *date {
return &date{}
}
//格式化 unix 时间戳
func (date *date) Format(unixTime interface{}, format string) string {
convert := NewConvert()
var convertTime int64
switch unixTime.(type) {
case string:
convertTime = convert.StringToInt64(unixTime.(string))
case int:
convertTime = int64(unixTime.(int))
case int8:
convertTime = int64(unixTime.(int8))
case int16:
convertTime = int64(unixTime.(int16))
case int32:
convertTime = int64(unixTime.(int32))
}
return beego.Date(time.Unix(convertTime, 0), format)
}
+214
View File
@@ -0,0 +1,214 @@
package utils
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
)
var Document = NewDocument("./data", "./data/markdowns")
const (
Document_Default_FileName = "README"
Document_Page_Suffix = ".md"
)
const (
Document_Type_Page = 1
Document_Type_Dir = 2
)
func NewDocument(documentAbsDir string, markdownAbsDir string) *document {
return &document{
DocumentAbsDir: documentAbsDir,
MarkdownAbsDir: markdownAbsDir,
}
}
type document struct {
DocumentAbsDir string
MarkdownAbsDir string
lock sync.Mutex
}
// get document page file by parentPath
func (d *document) GetPageFileByParentPath(name string, docType int, parentPath string) (pageFile string) {
if docType == Document_Type_Page {
pageFile = fmt.Sprintf("%s/%s%s", parentPath, name, Document_Page_Suffix)
} else {
pageFile = fmt.Sprintf("%s/%s/%s%s", parentPath, name, Document_Default_FileName, Document_Page_Suffix)
}
return
}
//get document path by spaceName
func (d *document) GetDefaultPageFileBySpaceName(name string) string {
return fmt.Sprintf("%s/%s%s", name, Document_Default_FileName, Document_Page_Suffix)
}
// get document abs pageFile
func (d *document) GetAbsPageFileByPageFile(pageFile string) string {
return d.MarkdownAbsDir + "/" + pageFile
}
// get document content by pageFile
func (d *document) GetContentByPageFile(pageFile string) (content string, err error) {
return File.GetFileContents(d.GetAbsPageFileByPageFile(pageFile))
}
// create document
func (d *document) Create(pageFile string) error {
if pageFile == "" {
return nil
}
d.lock.Lock()
absFilePath := d.GetAbsPageFileByPageFile(pageFile)
absDir := filepath.Dir(absFilePath)
err := os.MkdirAll(absDir, 0777)
if err != nil {
d.lock.Unlock()
return err
}
d.lock.Unlock()
return File.CreateFile(absFilePath)
}
// create and write document
func (d *document) CreateAndWrite(pageFile string, content string) error {
if pageFile == "" {
return nil
}
d.lock.Lock()
absFilePath := d.GetAbsPageFileByPageFile(pageFile)
absDir := filepath.Dir(absFilePath)
err := os.MkdirAll(absDir, 0777)
if err != nil {
d.lock.Unlock()
return err
}
d.lock.Unlock()
return File.WriteFile(absFilePath, content)
}
// replace document content
func (d *document) Replace(pageFile string, content string) error {
if pageFile == "" {
return nil
}
d.lock.Lock()
absFilePath := d.GetAbsPageFileByPageFile(pageFile)
absDir := filepath.Dir(absFilePath)
err := os.MkdirAll(absDir, 0777)
if err != nil {
d.lock.Unlock()
return err
}
d.lock.Unlock()
return ioutil.WriteFile(absFilePath, []byte(content), os.ModePerm)
}
// update document
func (d *document) Update(oldPageFile string, name string, content string, docType int, nameIsChange bool) (err error) {
d.lock.Lock()
defer d.lock.Unlock()
absOldPageFile := d.GetAbsPageFileByPageFile(oldPageFile)
err = ioutil.WriteFile(absOldPageFile, []byte(content), os.ModePerm)
if err != nil {
return
}
if nameIsChange {
filePath := filepath.Dir(absOldPageFile)
if docType == Document_Type_Page {
err = os.Rename(absOldPageFile, filePath+"/"+name+Document_Page_Suffix)
} else {
err = os.Rename(filePath, filepath.Dir(filePath)+"/"+name)
}
if err != nil {
return
}
}
return nil
}
func (d *document) UpdateSpaceName(oldSpaceName string, newName string) error {
d.lock.Lock()
defer d.lock.Unlock()
spaceOldDir := d.GetAbsPageFileByPageFile(oldSpaceName)
spaceNewDir := d.GetAbsPageFileByPageFile(newName)
if spaceNewDir == spaceOldDir {
return nil
}
err := os.Rename(spaceOldDir, spaceNewDir)
return err
}
// delete document
func (d *document) Delete(path string, docType int) error {
d.lock.Lock()
defer d.lock.Unlock()
absPageFile := d.GetAbsPageFileByPageFile(path)
ok, _ := File.PathIsExists(absPageFile)
if !ok {
return nil
}
if docType == Document_Type_Page {
return os.Remove(absPageFile)
}
return os.RemoveAll(filepath.Dir(absPageFile))
}
func (d *document) DeleteSpace(name string) error {
d.lock.Lock()
defer d.lock.Unlock()
absSpaceDir := d.GetAbsPageFileByPageFile(name)
ok, _ := File.PathIsExists(absSpaceDir)
if !ok {
return nil
}
return os.RemoveAll(absSpaceDir)
}
func (d *document) Move(movePath string, targetPath string, docType int) error {
d.lock.Lock()
defer d.lock.Unlock()
absOldPageFile := d.GetAbsPageFileByPageFile(movePath)
absTargetPageFile := d.GetAbsPageFileByPageFile(targetPath)
if docType == Document_Type_Page {
return os.Rename(absOldPageFile, absTargetPageFile)
}
return os.Rename(filepath.Dir(absOldPageFile), filepath.Dir(absTargetPageFile))
}
// delete document attachment
func (d *document) DeleteAttachment(attachments []map[string]string) error {
d.lock.Lock()
defer d.lock.Unlock()
if len(attachments) == 0 {
return nil
}
// delete attachment file
for _, attachment := range attachments {
if len(attachment) == 0 || attachment["path"] == "" {
continue
}
file := filepath.Join(d.DocumentAbsDir, attachment["path"])
_ = os.Remove(file)
}
return nil
}
+82
View File
@@ -0,0 +1,82 @@
package utils
import (
"crypto/tls"
"fmt"
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/global"
"gopkg.in/gomail.v2"
"gopkg.in/russross/blackfriday.v2"
"net/smtp"
"strconv"
"strings"
"time"
)
var Email = NewEmail()
type email struct {
}
func NewEmail() *email {
return &email{}
}
func (e *email) Send(emailConf map[string]string, toList []string, subject string, body string) error {
from := emailConf["sender_address"]
if emailConf["sender_name"] != "" {
from = fmt.Sprintf("%s <%s>", emailConf["sender_name"], emailConf["sender_address"])
}
var tt []*gomail.Message
for _, toAddress := range toList {
m := gomail.NewMessage()
m.SetHeader("From", from)
m.SetHeader("To", toAddress)
m.SetHeader("Subject", emailConf["sender_title_prefix"]+subject)
m.SetBody("text/html", body)
tt = append(tt, m)
}
portInt, _ := strconv.Atoi(emailConf["port"])
d := gomail.NewDialer(emailConf["host"], portInt, emailConf["username"], emailConf["password"])
if emailConf["is_ssl"] == "1" {
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
return d.DialAndSend(tt...)
}
func (e *email) SendByEmail(email map[string]string, to []string, subject string, body string, contentType string) error {
userEmail := email["sender_address"]
addr := fmt.Sprintf("%s:%s", email["host"], email["port"])
auth := smtp.PlainAuth("", userEmail, email["password"], email["host"])
user := email["username"]
nickname := email["sender_name"]
subject = email["sender_title_prefix"] + subject
msg := fmt.Sprintf("To: %s \r\nFrom: %s <%s>\r\nSubject: %s \r\nContent-Type: text/%s; charset=UTF-8\r\n\r\n%s",
strings.Join(to, ","), nickname, user, subject, contentType, body)
err := smtp.SendMail(addr, auth, user, to, []byte(msg))
return err
}
func (e *email) MakeDocumentHtmlBody(document map[string]string, view string) (body string, err error) {
viewTemplate, err := File.GetFileContents(view)
if err != nil {
return
}
body = strings.Replace(viewTemplate, "{{.now_time}}", beego.Date(time.Now(), "Y-m-d H:i:s"), 1)
body = strings.Replace(body, "{{.document_name}}", document["name"], 1)
body = strings.Replace(body, "{{.username}}", document["username"], 1)
body = strings.Replace(body, "{{.update_time}}", Date.Format(document["update_time"], "Y-m-d H:i:s"), 1)
body = strings.Replace(body, "{{.comment}}", document["comment"], 1)
body = strings.Replace(body, "{{.document_url}}", document["url"], 1)
body = strings.Replace(body, "{{.copyright}}", global.SYSTEM_COPYRIGHT, 1)
content := string(blackfriday.Run([]byte(document["content"])))
body = strings.Replace(body, "{{.document_content}}", content, 1)
return
}
+53
View File
@@ -0,0 +1,53 @@
package utils
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
)
var Encrypt = NewEncrypt()
const (
BASE_64_TABLE = "1234567890poiuytreqwasdfghjklmnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM-_"
)
type encrypt struct{}
func NewEncrypt() *encrypt {
return &encrypt{}
}
//base64 加密
func (encrypt *encrypt) Base64Encode(str string) string {
var coder = base64.NewEncoding(BASE_64_TABLE)
var src []byte = []byte(str)
return string([]byte(coder.EncodeToString(src)))
}
//base64 加密
func (encrypt *encrypt) Base64EncodeBytes(bytes []byte) []byte {
var coder = base64.NewEncoding(BASE_64_TABLE)
return []byte(coder.EncodeToString(bytes))
}
//base64 解密
func (encrypt *encrypt) Base64Decode(str string) (string, error) {
var src []byte = []byte(str)
var coder = base64.NewEncoding(BASE_64_TABLE)
by, err := coder.DecodeString(string(src))
return string(by), err
}
//base64 解密
func (encrypt *encrypt) Base64DecodeBytes(str string) ([]byte, error) {
var coder = base64.NewEncoding(BASE_64_TABLE)
return coder.DecodeString(str)
}
//md5加密
func (encrypt *encrypt) Md5Encode(str string) string {
hash := md5.New()
hash.Write([]byte(str))
return hex.EncodeToString(hash.Sum(nil))
}
+146
View File
@@ -0,0 +1,146 @@
package utils
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var File = NewFile()
func NewFile() *file {
return &file{}
}
type file struct {
}
// get file contents
func (f *file) GetFileContents(filePath string) (content string, err error) {
defer func(err *error) {
e := recover()
if e != nil {
*err = fmt.Errorf("%s", e)
}
}(&err)
bytes, err := ioutil.ReadFile(filePath)
content = string(bytes)
return
}
// file or path is exists
func (f *file) PathIsExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
// path is empty
func (f *file) PathIsEmpty(path string) bool {
fs, e := filepath.Glob(filepath.Join(path, "*"))
if e != nil {
return false
}
if len(fs) > 0 {
return false
}
return true
}
// is write permission
func (f *file) IsWritable(filename string) error {
file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
if err != nil {
if os.IsPermission(err) {
return errors.New("Error: Write permission denied.")
} else {
return err
}
}
file.Close()
return nil
}
// is read permission
func (f *file) IsReadable(filename string) error {
file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
if err != nil {
if os.IsPermission(err) {
return errors.New("Error: Read permission denied.")
} else {
return err
}
}
file.Close()
return nil
}
// is read and write permission
func (f *file) IsWriterReadable(file string) error {
err := f.IsWritable(file)
if err != nil {
return err
}
err = f.IsReadable(file)
if err != nil {
return err
}
return nil
}
// read file data
func (f *file) ReadAll(path string) (data string, err error) {
fi, err := os.Open(path)
if err != nil {
return
}
defer fi.Close()
fd, err := ioutil.ReadAll(fi)
return string(fd), nil
}
// write file
func (f *file) WriteFile(filename string, data string) (err error) {
var dataByte = []byte(data)
err = ioutil.WriteFile(filename, dataByte, 0666)
if err != nil {
return
}
return
}
// create file
func (f *file) CreateFile(filename string) error {
newFile, err := os.Create(filename)
defer newFile.Close()
return err
}
// get dir all files
func (f *file) WalkDir(dirPth, suffix string) (files []string, err error) {
files = make([]string, 0, 30)
suffix = strings.ToUpper(suffix)
err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
if fi.IsDir() {
return nil
}
if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
files = append(files, filename)
}
return nil
})
return files, err
}
+37
View File
@@ -0,0 +1,37 @@
package utils
import "strconv"
func MapInterface2String(inputData map[string]interface{}) map[string]string {
outputData := map[string]string{}
for key, value := range inputData {
switch value.(type) {
case string:
outputData[key] = value.(string)
case int:
tmp := value.(int)
outputData[key] = strconv.Itoa(tmp)
case int64:
tmp := value.(int64)
outputData[key] = strconv.FormatInt(tmp, 10)
}
}
return outputData
}
func MapString2Interface(fromMaps []map[string]string) (toMaps []map[string]interface{}) {
var dest []map[string]interface{}
for fromIndex := range fromMaps {
fromMap := fromMaps[fromIndex]
toMap := make(map[string]interface{})
for key, value := range fromMap {
toMap[key] = interface{}(value)
}
dest = append(dest, toMap)
}
return dest
}
+211
View File
@@ -0,0 +1,211 @@
package utils
import (
"fmt"
"math"
"math/rand"
"net"
"strings"
"time"
)
var Misc = NewMisc()
type misc struct{}
func NewMisc() *misc {
return &misc{}
}
// get map default
func (m *misc) GetMapDefault(mapValue map[string]interface{}, key string, def interface{}) interface{} {
value, ok := mapValue[key]
if ok {
return value
} else {
return def
}
}
// rand string
func (m *misc) RandString(strlen int) string {
codes := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
codeLen := len(codes)
data := make([]byte, strlen)
rand.Seed(time.Now().UnixNano() + rand.Int63() + rand.Int63() + rand.Int63() + rand.Int63())
for i := 0; i < strlen; i++ {
idx := rand.Intn(codeLen)
data[i] = byte(codes[idx])
}
return string(data)
}
// rand int
func (m *misc) RandInt(strLen int) string {
codes := "0123456789"
codeLen := len(codes)
data := make([]byte, strLen)
rand.Seed(time.Now().UnixNano() + rand.Int63() + rand.Int63() + rand.Int63() + rand.Int63())
for i := 0; i < strLen; i++ {
idx := rand.Intn(codeLen)
data[i] = byte(codes[idx])
}
return string(data)
}
// get local ip
func (m *misc) GetLocalIp() string {
addrSlice, err := net.InterfaceAddrs()
if nil != err {
return "localhost"
}
for _, addr := range addrSlice {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if nil != ipnet.IP.To4() {
return ipnet.IP.String()
}
}
}
return "localhost"
}
// 分页方法
// total: 一共多少记录
// page: 当前是第几页
// pagesize: 每页多少
// url: url里面的{page}会被替换成页码
// args:
// order 分页条的组成,是一个数组,可以按着1-6的序号,选择分页条组成部分和每个部分的顺序
// a_count 分页条中a页码链接的总数量,不包含当前页的a标签,默认10个。
//
func (m *misc) Page(total, page, pagesize int, url string, args ...interface{}) string {
order := []int{1, 2, 3, 4, 5, 6}
a_count := 10
if len(args) >= 1 {
order = args[0].([]int)
}
if len(args) >= 2 {
a_count = args[1].(int)
}
a_num := a_count
first := "首页"
last := "尾页"
pre := "上页"
next := "下页"
if a_num%2 == 0 {
a_num++
}
pages := int(math.Ceil(float64(total) / float64(pagesize)))
curpage := page
if curpage > pages || curpage <= 0 {
curpage = 1
}
body := `<span class="page_body">`
prefix := ""
subfix := ""
start := curpage - ((a_num - 1) / 2)
end := curpage + ((a_num - 1) / 2)
if start <= 0 {
start = 1
}
if end > pages {
end = pages
}
if pages >= a_num {
if curpage <= (a_num-1)/2 {
end = a_num
}
if end-curpage <= (a_num-1)/2 {
start -= int(math.Floor(float64(a_num)/float64(2))) - (end - curpage)
}
}
for i := start; i <= end; i++ {
if i == curpage {
body += fmt.Sprintf(`<a class="page_cur_page" href="javascript:void(0);"><b>%d</b></a>`, i)
} else {
body += fmt.Sprintf(`<a href="%s">%d</a>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", i), 1), i)
}
}
body += "</span>"
if curpage > 1 {
prefix = fmt.Sprintf(`<span class="page_bar_prefix"><a href="%s">%s</a><a href="%s">%s</a></span>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", 1), 1), first, strings.Replace(url, "{page}", fmt.Sprintf("%d", curpage-1), 1), pre)
}
if curpage != pages {
subfix = fmt.Sprintf(`<span class="page_bar_subfix"><a href="%s">%s</a><a href="%s">%s</a></span>`, strings.Replace(url, "{page}", fmt.Sprintf("%d", curpage+1), 1), next, strings.Replace(url, "{page}", fmt.Sprintf("%d", pages), 1), last)
}
info := fmt.Sprintf(`<span class="page_cur">第%d/%d页</span>`, curpage, pages)
id := fmt.Sprintf("gsd09fhas9d%d%d%d", rand.Intn(1000), rand.Intn(1000), rand.Intn(1000))
gostr := fmt.Sprintf(`<script>function ekup(){if(event.keyCode==13){clkyup();}}function clkyup(){var num=document.getElementById('%s').value;if(!/^\d+$/.test(num)||num<=0||num>%d){alert('请输入正确页码!');return;};location='%s'.replace(/\{page\}/,document.getElementById('%s').value);}</script><span class="page_input_num"><input onkeyup="ekup()" type="text" id="%s" style="width:40px;vertical-align:text-baseline;padding:0 2px;font-size:10px;border:1px solid gray;"/></span><span class="page_btn_go" onclick="clkyup();" style="cursor:pointer;">转到</span>`, id, pages, url, id, id)
totalstr := fmt.Sprintf(`<span class="page_total">共%d条</span>`, total)
pagenation := []string{totalstr, info, prefix, body, subfix, gostr}
output := []string{}
for _, v := range order {
if v-1 < len(pagenation) && v-1 >= 0 {
output = append(output, pagenation[v-1])
}
}
if pages > 1 {
return strings.Join(output, "")
}
return ""
}
// 获取字符串子串的位置
func (m *misc) GetStrUnicodeIndex(str string, substr string) int {
// 子串在字符串的字节位置
result := strings.Index(str, substr)
if result >= 0 {
return m.GetStrUnicodeIndexByByteIndex(str, result)
}
return -1
}
// 根据字符串字节位置获取字符串位置
func (m *misc) GetStrUnicodeIndexByByteIndex(str string, subStrByteIndex int) int {
if subStrByteIndex > len(str)-1 {
return -1
}
// 获得子串之前的字符串并转换成[]byte
prefix := []byte(str)[0:subStrByteIndex]
// 将子串之前的字符串转换成[]rune
rs := []rune(string(prefix))
// 获得子串之前的字符串的长度,便是子串在字符串的字符位置
result := len(rs)
return result
}
// 截取包含子字符串的一段字符串,前后截取
func (m *misc) SubStrUnicode(str string, subStr string, preLen int, sufLen int) string {
subStrRune := []rune(subStr)
strRune := []rune(str)
count := len(strRune)
subStrUnicodeIndex := m.GetStrUnicodeIndex(str, subStr)
startIndex := 0
endIndex := count - 1
if subStrUnicodeIndex-preLen > 0 {
startIndex = subStrUnicodeIndex - preLen
}
if subStrUnicodeIndex+len(subStrRune)+sufLen < count-1 {
endIndex = subStrUnicodeIndex + len(subStrRune) + sufLen
}
return string(strRune[startIndex:endIndex])
}
// 截取包含子字符串的一段字符串,前后截取
// subStrIndex 已只子串的字节位置
func (m *misc) SubStrUnicodeBySubStrIndex(str string, subStr string, subStrIndex int, preLen int, sufLen int) string {
subStrRune := []rune(subStr)
strRune := []rune(str)
count := len(strRune)
subStrUnicodeIndex := m.GetStrUnicodeIndexByByteIndex(str, subStrIndex)
startIndex := 0
endIndex := count - 1
if subStrUnicodeIndex-preLen > 0 {
startIndex = subStrUnicodeIndex - preLen
}
if subStrUnicodeIndex+len(subStrRune)+sufLen < count-1 {
endIndex = subStrUnicodeIndex + len(subStrRune) + sufLen
}
return string(strRune[startIndex:endIndex])
}
+212
View File
@@ -0,0 +1,212 @@
// Copyright 2013 wetalk authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package utils
import (
"math"
"net/http"
"net/url"
"strconv"
)
// 默认的每页条数的选择范围
var defaultPerPageNumsSelect = []int{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 100}
type Paginator struct {
Request *http.Request
PerPageNums int
PerPageNumsSelect []int
MaxPages int
nums int64
pageRange []int
pageNums int
page int
pageParamName string
perPageNumParamName string
}
func (p *Paginator) PageNums() int {
if p.pageNums != 0 {
return p.pageNums
}
pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums))
if p.MaxPages > 0 {
pageNums = math.Min(pageNums, float64(p.MaxPages))
}
p.pageNums = int(pageNums)
return p.pageNums
}
func (p *Paginator) Nums() int64 {
return p.nums
}
func (p *Paginator) SetNums(nums interface{}) {
p.nums, _ = NewConvert().ToInt64(nums)
}
func (p *Paginator) SetPrePageNumsSelect(selectNums []int) {
p.PerPageNumsSelect = selectNums
}
func (p *Paginator) SetPerPageNums(perPageNums int) {
if perPageNums < p.PerPageNumsSelect[0] {
perPageNums = p.PerPageNumsSelect[0]
}
if perPageNums > p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1] {
perPageNums = p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1]
}
p.PerPageNums = perPageNums
}
func (p *Paginator) Page() int {
if p.page != 0 {
return p.page
}
if p.Request.Form == nil {
p.Request.ParseForm()
}
p.page, _ = strconv.Atoi(p.Request.Form.Get(p.pageParamName))
if p.page > p.PageNums() {
p.page = p.PageNums()
}
if p.page <= 0 {
p.page = 1
}
return p.page
}
func (p *Paginator) Pages() []int {
if p.pageRange == nil && p.nums > 0 {
var pages []int
pageNums := p.PageNums()
page := p.Page()
switch {
case page >= pageNums-4 && pageNums > 9:
start := pageNums - 9 + 1
pages = make([]int, 9)
for i, _ := range pages {
pages[i] = start + i
}
case page >= 5 && pageNums > 9:
start := page - 5 + 1
pages = make([]int, int(math.Min(9, float64(page+4+1))))
for i, _ := range pages {
pages[i] = start + i
}
default:
pages = make([]int, int(math.Min(9, float64(pageNums))))
for i, _ := range pages {
pages[i] = i + 1
}
}
p.pageRange = pages
}
return p.pageRange
}
func (p *Paginator) PageLink(page int) string {
link, _ := url.ParseRequestURI(p.Request.RequestURI)
values := link.Query()
if page == 1 {
values.Del(p.pageParamName)
} else {
values.Set(p.pageParamName, strconv.Itoa(page))
}
if p.PerPageNums < p.PerPageNumsSelect[0] {
p.PerPageNums = p.PerPageNumsSelect[0]
}
if p.PerPageNums > p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1] {
p.PerPageNums = p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1]
}
values.Set(p.perPageNumParamName, strconv.Itoa(p.PerPageNums))
link.RawQuery = values.Encode()
return link.String()
}
func (p *Paginator) PrePageNumLink(perPageNum int) string {
link, _ := url.ParseRequestURI(p.Request.RequestURI)
values := link.Query()
if perPageNum < p.PerPageNumsSelect[0] {
perPageNum = p.PerPageNumsSelect[0]
}
if perPageNum > p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1] {
perPageNum = p.PerPageNumsSelect[len(p.PerPageNumsSelect)-1]
}
values.Set(p.perPageNumParamName, strconv.Itoa(perPageNum))
link.RawQuery = values.Encode()
return link.String()
}
func (p *Paginator) PageLinkPrev() (link string) {
if p.HasPrev() {
link = p.PageLink(p.Page() - 1)
}
return
}
func (p *Paginator) PageLinkNext() (link string) {
if p.HasNext() {
link = p.PageLink(p.Page() + 1)
}
return
}
func (p *Paginator) PageLinkFirst() (link string) {
return p.PageLink(1)
}
func (p *Paginator) PageLinkLast() (link string) {
return p.PageLink(p.PageNums())
}
func (p *Paginator) HasPrev() bool {
return p.Page() > 1
}
func (p *Paginator) HasNext() bool {
return p.Page() < p.PageNums()
}
func (p *Paginator) IsActive(page int) bool {
return p.Page() == page
}
func (p *Paginator) Offset() int {
return (p.Page() - 1) * p.PerPageNums
}
func (p *Paginator) HasPages() bool {
return p.PageNums() > 1
}
func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator {
p := Paginator{}
p.Request = req
// 翻页参数名,默认为 page
p.pageParamName = "page"
// 每页条数参数名,默认为 "number"
p.perPageNumParamName = "number"
if per <= 0 {
per = 10
}
p.SetPrePageNumsSelect(defaultPerPageNumsSelect)
p.SetPerPageNums(per)
p.SetNums(nums)
return &p
}
+113
View File
@@ -0,0 +1,113 @@
package utils
import (
"io/ioutil"
"net/http"
"net/url"
"strings"
)
var Request = NewRequest()
func NewRequest() *request {
return &request{}
}
type request struct {
}
// http get request
func (r *request) HttpGet(queryUrl string, queryValues map[string]string, headerValues map[string]string) (body []byte, code int, err error) {
req, err := http.NewRequest("GET", r.QueryBuilder(queryUrl, queryValues), nil)
if err != nil {
return
}
if (headerValues != nil) && (len(headerValues) > 0) {
for key, value := range headerValues {
req.Header.Set(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}
code = resp.StatusCode
defer resp.Body.Close()
bodyByte, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
return bodyByte, code, nil
}
// http post request
func (r *request) HttpPost(queryUrl string, queryValues map[string]string, headerValues map[string]string) (body []byte, code int, err error) {
if !strings.Contains(queryUrl, "?") {
queryUrl += "?"
}
queryString := ""
for queryKey, queryValue := range queryValues {
queryString = queryString + "&" + queryKey + "=" + url.QueryEscape(queryValue)
}
queryString = strings.Replace(queryString, "&", "", 1)
req, err := http.NewRequest("POST", queryUrl, strings.NewReader(queryString))
if err != nil {
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if (headerValues != nil) && (len(headerValues) > 0) {
for key, value := range headerValues {
req.Header.Set(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}
code = resp.StatusCode
defer resp.Body.Close()
bodyByte, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
return bodyByte, code, nil
}
// build query params
func (r *request) QueryBuilder(queryUrl string, queryValues map[string]string) string {
if !strings.Contains(queryUrl, "?") {
queryUrl += "?"
}
queryString := ""
for queryKey, queryValue := range queryValues {
queryString = queryString + "&" + queryKey + "=" + url.QueryEscape(queryValue)
}
queryString = strings.Replace(queryString, "&", "", 1)
queryUrl += queryString
return queryUrl
}
// parse params(name=nick&pass=123)
func (r *request) ParseString(params string) map[string]string {
paramsMap := map[string]string{}
for _, param := range strings.Split(params, "&") {
if !strings.Contains(param, "=") {
continue
}
paramList := strings.Split(param, "=")
paramsMap[paramList[0]] = paramList[1]
}
return paramsMap
}
+97
View File
@@ -0,0 +1,97 @@
package utils
import (
"strconv"
"strings"
)
// version compare
// version example: v0.1.1
var (
defaultPrefix = "v"
VersionCompare = NewVersionCompare(defaultPrefix)
)
// struct
type versionCompare struct {
prefix string
}
// new versionCompare
func NewVersionCompare(prefix string) *versionCompare {
return &versionCompare{
prefix: prefix,
}
}
// version1 == version2
func (vc *versionCompare) Eq(version1 string, version2 string) bool {
return version1 == version2
}
// version1 != version2
func (vc *versionCompare) Neq(version1 string, version2 string) bool {
return version1 != version2
}
// version1 > version2
func (vc *versionCompare) Gt(version1 string, version2 string) bool {
v1Number := vc.ConvertIntList(version1)
v2Number := vc.ConvertIntList(version2)
for i, v := range v1Number {
if v > v2Number[i] {
return true
}
if v == v2Number[i] {
continue
}
if v < v2Number[i] {
return false
}
}
return false
}
// version1 < version2
func (vc *versionCompare) Lt(version1 string, version2 string) bool {
return vc.Gt(version2, version1)
}
// version1 >= version2
func (vc *versionCompare) Gte(version1 string, version2 string) bool {
v1Number := vc.ConvertIntList(version1)
v2Number := vc.ConvertIntList(version2)
for i, v := range v1Number {
if v > v2Number[i] {
return true
}
if v == v2Number[i] {
continue
}
if v < v2Number[i] {
return false
}
}
return true
}
// version1 <= version2
func (vc *versionCompare) Lte(version1 string, version2 string) bool {
return vc.Gte(version2, version1)
}
// version string convert int list
func (vc *versionCompare) ConvertIntList(version string) []int {
var realVersion = version
if version[0:len(vc.prefix)] == vc.prefix {
realVersion = version[len(vc.prefix):]
}
versionList := strings.Split(realVersion, ".")
var l = make([]int, len(versionList))
for i, v := range versionList {
intValue, _ := strconv.Atoi(v)
l[i] = intValue
}
return l
}
+74
View File
@@ -0,0 +1,74 @@
package utils
import (
"fmt"
"testing"
)
func TestNewVersionCompare(t *testing.T) {
}
func TestVersionCompare_ConvertIntList(t *testing.T) {
vc := NewVersionCompare("v")
l := vc.ConvertIntList("v3.25.10")
fmt.Println(l)
}
func TestVersionCompare_Eq(t *testing.T) {
vc := NewVersionCompare("v")
if vc.Eq("v3.25.10", "v1.10.9") {
t.Fail()
}
if !vc.Eq("v1.10.9", "v1.10.9") {
t.Fail()
}
}
func TestVersionCompare_Neq(t *testing.T) {
vc := NewVersionCompare("v")
if !vc.Neq("v3.25.10", "v1.10.9") {
t.Fail()
}
if vc.Neq("v1.10.9", "v1.10.9") {
t.Fail()
}
}
func TestVersionCompare_Gt(t *testing.T) {
vc := NewVersionCompare("v")
if !vc.Gt("v3.25.10", "v1.10.9") {
t.Fatal()
}
if !vc.Gt("v3.25.10", "v3.10.9") {
t.Fatal()
}
if !vc.Gt("v3.25.10", "v3.25.9") {
t.Fatal()
}
if vc.Gt("v3.25.10", "v3.25.10") {
t.Fatal()
}
if vc.Gt("v3.25.10", "v3.75.10") {
t.Fail()
}
}
func TestVersionCompare_Gte(t *testing.T) {
vc := NewVersionCompare("v")
if !vc.Gte("v3.25.10", "v1.10.9") {
t.Fatal()
}
if !vc.Gte("v3.25.10", "v3.10.9") {
t.Fatal()
}
if !vc.Gte("v3.25.10", "v3.25.9") {
t.Fatal()
}
if !vc.Gte("v3.25.10", "v3.25.10") {
t.Fatal()
}
if vc.Gte("v3.25.10", "v3.75.10") {
t.Fail()
}
}
+230
View File
@@ -0,0 +1,230 @@
package utils
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
"sync"
)
var Zipx = NewZipx()
type zipx struct {
lock sync.Mutex
}
func NewZipx() *zipx {
return &zipx{}
}
type CompressFileInfo struct {
File string
PrefixPath string
osFile *os.File
}
func (z *zipx) PackFile(files []*CompressFileInfo, dest string) error {
z.lock.Lock()
defer z.lock.Unlock()
// create dest file
destDir := filepath.Dir(dest)
err := os.RemoveAll(destDir)
if err != nil {
return err
}
err = os.MkdirAll(destDir, 0777)
if err != nil {
return err
}
d, err := os.Create(dest)
if err != nil {
return err
}
defer d.Close()
// file handle
for _, f := range files {
f3, err := os.Open(f.File)
if err != nil {
continue
}
f.osFile = f3
}
defer func() {
for _, f := range files {
if f.osFile == nil {
continue
}
_ = f.osFile.Close()
}
}()
// zip writer
w := zip.NewWriter(d)
defer w.Close()
for _, file := range files {
err := z.compress(file.osFile, file.PrefixPath, w)
if err != nil {
return err
}
}
return nil
}
func (z *zipx) Compress(files []*os.File, dest string) error {
d, _ := os.Create(dest)
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
for _, file := range files {
err := z.compress(file, "images/1/4", w)
if err != nil {
return err
}
}
return nil
}
func (z *zipx) compress(file *os.File, prefix string, zw *zip.Writer) error {
info, err := file.Stat()
if err != nil {
return err
}
if info.IsDir() {
prefix = prefix + "/" + info.Name()
fileInfos, err := file.Readdir(-1)
if err != nil {
return err
}
for _, fi := range fileInfos {
f, err := os.Open(file.Name() + "/" + fi.Name())
if err != nil {
return err
}
err = z.compress(f, prefix, zw)
if err != nil {
return err
}
}
} else {
header, err := zip.FileInfoHeader(info)
header.Name = prefix + "/" + header.Name
if err != nil {
return err
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(writer, file)
file.Close()
if err != nil {
return err
}
}
return nil
}
//解压
func (z *zipx) DeCompress(zipFile, dest string) error {
reader, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer reader.Close()
for _, file := range reader.File {
rc, err := file.Open()
if err != nil {
return err
}
defer rc.Close()
filename := dest + file.Name
err = os.MkdirAll(z.getDir(filename), 0755)
if err != nil {
return err
}
w, err := os.Create(filename)
if err != nil {
return err
}
defer w.Close()
_, err = io.Copy(w, rc)
if err != nil {
return err
}
w.Close()
rc.Close()
}
return nil
}
func (z *zipx) getDir(path string) string {
return z.subString(path, 0, strings.LastIndex(path, "/"))
}
func (z *zipx) subString(str string, start, end int) string {
rs := []rune(str)
length := len(rs)
if start < 0 || start > length {
panic("start is wrong")
}
if end < start || end > length {
panic("end is wrong")
}
return string(rs[start:end])
}
// srcFile could be a single file or a directory
func (z *zipx) Zip(srcFile string, destZip string) error {
zipfile, err := os.Create(destZip)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
_ = filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile)+"/")
// header.Name = path
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if !info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
}
return err
})
return err
}
+30
View File
@@ -0,0 +1,30 @@
package utils
import (
"os"
"testing"
)
func TestZipx_Zip(t *testing.T) {
err := Zipx.Zip("~/Code/data/mm_wiki/attachment/1/4/", "/Users/phachon/Downloads/test.zip")
if err != nil {
t.Error(err)
}
}
func TestZipx_Compress(t *testing.T) {
osFiles := []*os.File{}
f3, err := os.Open("/Users/phachon/Code/data/mm_wiki/images/1/4/redis2.jpeg")
if err != nil {
t.Error(err)
}
defer f3.Close()
osFiles = append(osFiles, f3)
err = Zipx.Compress(osFiles, "/Users/phachon/Downloads/demo.zip")
if err != nil {
t.Error(err)
}
}
+131
View File
@@ -0,0 +1,131 @@
package work
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/phachon/mm-wiki/app/models"
"github.com/phachon/mm-wiki/app/services"
"github.com/phachon/mm-wiki/app/utils"
"sync"
"time"
)
var (
DocSearchWorker = NewDocSearchWork()
)
const (
// work 未启动或已停止
RunStatusStop = 0
// work 运行中
RunStatusRunning = 1
)
type DocSearch struct {
// 并发锁,理论上不存在并发的情况,为了安全
lock sync.RWMutex
// work 运行状态
runStatus int
// work 中是否有任务正在运行
isTaskRunning bool
// work 退出信号
quit chan bool
}
func NewDocSearchWork() *DocSearch {
return &DocSearch{
runStatus: RunStatusStop,
isTaskRunning: false,
quit: make(chan bool, 1),
}
}
// Start 开始 work
func (d *DocSearch) Start() {
// 已经在运行
if d.runStatus == RunStatusRunning {
return
}
timer, ok := d.getFullTextSearchConf()
if !ok {
return
}
d.updateAllDocIndex()
go func(d *DocSearch, t time.Duration) {
defer func() {
e := recover()
if e != nil {
logs.Info("[DocSearchWork] load all doc index panic: %v", e)
}
d.lock.Lock()
d.runStatus = RunStatusStop
d.isTaskRunning = false
d.lock.Unlock()
}()
d.lock.Lock()
d.runStatus = RunStatusRunning
d.lock.Unlock()
for {
select {
case <-time.Tick(t):
if !d.isTaskRunning {
d.updateAllDocIndex()
}
case <-d.quit:
logs.Info("[DocSearchWork] stop doc index")
return
}
}
}(d, time.Duration(timer)*time.Second)
}
// Restart 重新启动 work
func (d *DocSearch) Restart() {
d.Stop()
time.Sleep(time.Millisecond)
d.Start()
}
// Stop 停止 work
func (d *DocSearch) Stop() {
d.quit <- true
}
// 查找是否开启全文索引并获取配置
func (d *DocSearch) getFullTextSearchConf() (timer int64, isOpen bool) {
fulltextSearchOpen := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyFulltextSearch, "0")
docSearchTimer := models.ConfigModel.GetConfigValueByKey(models.ConfigKeyDocSearchTimer, "3600")
timer = utils.Convert.StringToInt64(docSearchTimer)
// 默认 3600 s
if timer <= 0 {
timer = int64(3600)
}
if fulltextSearchOpen == "1" {
return timer, true
}
return timer, false
}
func (d *DocSearch) updateAllDocIndex() {
logs.Info("[DocSearchWork] start load all doc index")
d.lock.Lock()
d.isTaskRunning = true
d.lock.Unlock()
// 分批次更新,每批次 100
batchUpdateDocNum, _ := beego.AppConfig.Int("search::batch_update_doc_num")
if batchUpdateDocNum <= 0 {
batchUpdateDocNum = 100
}
services.DocIndexService.UpdateAllDocIndex(batchUpdateDocNum)
services.DocIndexService.Flush()
d.lock.Lock()
d.isTaskRunning = false
d.lock.Unlock()
logs.Info("[DocSearchWork] finish all doc index flush")
}
Executable
+85
View File
@@ -0,0 +1,85 @@
#!/bin/sh
# start go mod
export GO111MODULE=on
# set goproxy
export GOPROXY=https://goproxy.cn
PROJECT_NAME="mm-wiki"
INSTALL_NAME="install"
BUILD_DIR="release"
ROOT_DIR=$(pwd)
# windows .exe
if [ "${GOOS}" = "" ]; then
UNAME=$( command -v uname)
case $( "${UNAME}" | tr '[:upper:]' '[:lower:]') in
msys*|cygwin*|mingw*|nt|win*)
PROJECT_NAME=${PROJECT_NAME}".exe"
INSTALL_NAME=${INSTALL_NAME}".exe"
;;
esac
elif [ "${GOOS}" = "windows" ]; then
PROJECT_NAME=${PROJECT_NAME}".exe"
INSTALL_NAME=${INSTALL_NAME}".exe"
fi
rm -rf ${BUILD_DIR}
build_app() {
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/conf
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/logs
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/static
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/views
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/docs
/bin/cp -r "${ROOT_DIR}"/conf/default.conf "${ROOT_DIR}"/${BUILD_DIR}/conf/
/bin/cp -r "${ROOT_DIR}"/conf/template.conf "${ROOT_DIR}"/${BUILD_DIR}/conf/
/bin/cp -r "${ROOT_DIR}"/scripts/* "${ROOT_DIR}"/${BUILD_DIR}/
/bin/cp -r "${ROOT_DIR}"/docs/* "${ROOT_DIR}"/${BUILD_DIR}/docs/
/bin/cp -r "${ROOT_DIR}"/views/* "${ROOT_DIR}"/${BUILD_DIR}/views/
/bin/cp -r "${ROOT_DIR}"/static/* "${ROOT_DIR}"/${BUILD_DIR}/static/
/bin/cp -r "${ROOT_DIR}"/CHANGELOG.md "${ROOT_DIR}"/${BUILD_DIR}
/bin/cp -r "${ROOT_DIR}"/README.md "${ROOT_DIR}"/${BUILD_DIR}
/bin/cp -r "${ROOT_DIR}"/README_eng.md "${ROOT_DIR}"/${BUILD_DIR}
/bin/cp -r "${ROOT_DIR}"/LICENSE "${ROOT_DIR}"/${BUILD_DIR}
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/conf/
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/logs/
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/static/
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/views/
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/*.sh
go build -o ${PROJECT_NAME} ./
if [ -f "${ROOT_DIR}/${PROJECT_NAME}" ]; then
mv "${ROOT_DIR}"/${PROJECT_NAME} "${ROOT_DIR}"/${BUILD_DIR}/
fi
return
}
build_install() {
mkdir -p "${ROOT_DIR}"/${BUILD_DIR}/install
# Todo: 目录切换失败时输出错误信息
cd "${ROOT_DIR}"/install || exit
go build -o ${INSTALL_NAME} ./
chmod -R 755 "${ROOT_DIR}"/${BUILD_DIR}/install/
if [ -f "${ROOT_DIR}/install/${INSTALL_NAME}" ]; then
mv "${ROOT_DIR}"/install/${INSTALL_NAME} "${ROOT_DIR}"/${BUILD_DIR}/install
fi
cd ../
return
}
build() {
echo ">> MM-Wiki start build!"
build_app
build_install
return
}
build
+100
View File
@@ -0,0 +1,100 @@
# MM-Wiki 配置文件
# ----------------------------------------------------------------------
# 由 MM-Wiki 安装向导配置生成
# beego 参数配置请参考:https://beego.me/docs/mvc/controller/config.md
# 安装说明
# ----------------------------------------------------------------------
# 在 install 目录,执行安装向导程序
# ./install --port=8090
# 浏览器访问 http://ip:8090 进入安装界面,完成安装配置
# 运行说明
# ----------------------------------------------------------------------
# 无论是 Linux 或 Windows, MM-Wiki 启动的默认的配置文件为 conf/mm-wiki.conf
# 若要从命令行运行服务器,请在命令行运行
# ./mm-wiki 或指定文件运行
# ./mm-wiki --conf conf/mm-wiki.conf
#
# 后台运行
# ----------------------------------------------------------------------
# 如果你想关闭 shell 窗口后台运行 mm-wikiLinux 执行命令
# nohup ./mm-wiki --conf conf/mm-wiki.conf &
# 全局配置
# ----------------------------------------------------------------------
# 运行模式,可选值为 prod(生产模式), dev(开发模式) 或者 test(测试模式). 默认是 prod, 为生产模式
runmode = "prod"
# 软件名称
appname = mm-wiki
# httpaddr mm-wiki 程序监听的 ip
# 0.0.0.0 是对外开放,通过服务域名、ip 可以访问的端口
# 127.0.0.1 只能对本机 localhost访问,可以保护此端口安全性
httpaddr = "0.0.0.0"
# mm-wiki 程序监听的端口
httpport = 8081
# session 配置
# ----------------------------------------------------------------------
# 开启 session
sessionon=true
# 客户端存储 cookie 的名字
sessionname="mmwikissid"
# session 的引擎,默认是 file,支持 file, memory, memcache, redis, redis_cluster
sessionprovider="file"
# session 引擎的配置,
# file: sessionproviderconfig=".mmwiki.sessions" 是指保存 session 数据文件的目录
# memory: sessionproviderconfig="" 为空
# memcache: sessionproviderconfig="127.0.0.1:7080" memcache 服务的 ip:端口
# redis: sessionproviderconfig="127.0.0.1:6379" redis 实例的 ip:端口
# redis_cluster: sessionproviderconfig="127.0.0.1:6379;127.0.0.1:6380,100,test,0"(addr..., pool size, password, dbnum)
sessionproviderconfig=".mmwiki.sessions"
# session 过期时间,单位秒
sessiongcmaxlifetime=72000
# cookie 配置
# ----------------------------------------------------------------------
[author]
# 保存 cookie 的 passport
passport="mmwikipassport"
# cookie 的过期时间,单位秒
cookie_expired=72000
# mysql 数据库配置
# ----------------------------------------------------------------------
[db]
host="127.0.0.1"
port="3306"
name="mm_wiki"
user="root"
pass="123456"
table_prefix="mw_"
conn_max_idle=30
conn_max_connection=200
# 日志配置
# ----------------------------------------------------------------------
[log]
console="{"level":7, "color":true}"
file="{"level":7, "filename":"logs/mm-wiki.log"}"
# 文档配置
# ----------------------------------------------------------------------
[document]
# 文档的根目录,最好写绝对路径
root_dir="./data"
# 搜索配置
# ----------------------------------------------------------------------
[search]
# 搜索索引更新间隔时间(单位秒),默认为 30;如果文档数过多,建议增加时长
interval_time=30
# 每批次更新的文档数,默认 100,不能太大,一次更新占用内存和链接数过多
batch_update_doc_num=100
+100
View File
@@ -0,0 +1,100 @@
# MM-Wiki 配置文件
# ----------------------------------------------------------------------
# 由 MM-Wiki 安装向导配置生成
# beego 参数配置请参考:https://beego.me/docs/mvc/controller/config.md
# 安装说明
# ----------------------------------------------------------------------
# 在 install 目录,执行安装向导程序
# ./install --port=8090
# 浏览器访问 http://ip:8090 进入安装界面,完成安装配置
# 运行说明
# ----------------------------------------------------------------------
# 无论是 Linux 或 Windows, MM-Wiki 启动的默认的配置文件为 conf/mm-wiki.conf
# 若要从命令行运行服务器,请在命令行运行
# ./mm-wiki 或指定文件运行
# ./mm-wiki --conf conf/mm-wiki.conf
#
# 后台运行
# ----------------------------------------------------------------------
# 如果你想关闭 shell 窗口后台运行 mm-wikiLinux 执行命令
# nohup ./mm-wiki --conf conf/mm-wiki.conf &
# 全局配置
# ----------------------------------------------------------------------
# 运行模式,可选值为 prod(生产模式), dev(开发模式) 或者 test(测试模式). 默认是 prod, 为生产模式
runmode = "prod"
# 软件名称
appname = mm-wiki
# httpaddr mm-wiki 程序监听的 ip
# 0.0.0.0 是对外开放,通过服务域名、ip 可以访问的端口
# 127.0.0.1 只能对本机 localhost访问,可以保护此端口安全性
httpaddr = "#httpaddr#"
# mm-wiki 程序监听的端口
httpport = #httpport#
# session 配置
# ----------------------------------------------------------------------
# 开启 session
sessionon=true
# 客户端存储 cookie 的名字
sessionname="mmwikissid"
# session 的引擎,默认是 file,支持 file, memory, memcache, redis, redis_cluster
sessionprovider="file"
# session 引擎的配置,
# file: sessionproviderconfig=".mmwiki.sessions" 是指保存 session 数据文件的目录
# memory: sessionproviderconfig="" 为空
# memcache: sessionproviderconfig="127.0.0.1:7080" memcache 服务的 ip:端口
# redis: sessionproviderconfig="127.0.0.1:6379" redis 实例的 ip:端口
# redis_cluster: sessionproviderconfig="127.0.0.1:6379;127.0.0.1:6380,100,test,0"(addr..., pool size, password, dbnum)
sessionproviderconfig=".mmwiki.sessions"
# session 过期时间,单位秒
sessiongcmaxlifetime=72000
# cookie 配置
# ----------------------------------------------------------------------
[author]
# 保存 cookie 的 passport
passport="mmwikipassport"
# cookie 的过期时间,单位秒
cookie_expired=72000
# mysql 数据库配置
# ----------------------------------------------------------------------
[db]
host="#db.host#"
port="#db.port#"
name="#db.name#"
user="#db.user#"
pass="#db.pass#"
table_prefix="mw_"
conn_max_idle=#db.conn_max_idle#
conn_max_connection=#db.conn_max_connection#
# 日志配置
# ----------------------------------------------------------------------
[log]
console="{"level":7, "color":true}"
file="{"level":7, "filename":"#log.filename#"}"
# 文档配置
# ----------------------------------------------------------------------
[document]
# 文档的根目录,最好写绝对路径
root_dir="#document_dir#"
# 搜索配置
# ----------------------------------------------------------------------
[search]
# 搜索索引更新间隔时间(单位秒),默认为 30;如果文档数过多,建议增加时长
interval_time=30
# 每批次更新的文档数,默认 100,不能太大,一次更新占用内存和链接数过多
batch_update_doc_num=100
+168
View File
@@ -0,0 +1,168 @@
-- --------------------------------------
-- MM-Wiki 安装数据
-- warning:执行前需保证表里没有任何数据
-- author: phachon
-- --------------------------------------
-- --------------------------------------
-- 系统用户(root, password123456, 自动安装不需要插入,手动安装时需要插入该数据
-- --------------------------------------
-- INSERT INTO `mw_user` (`user_id`, `username`, `password`, `given_name`, `email`, `mobile`, `role_id`, `is_delete`, `create_time`, `update_time`)
-- VALUES ('1', 'root', 'e10adc3949ba59abbe56e057f20f883e', 'root', 'root@123456.com', '1102222', '1', '0', unix_timestamp(now()), unix_timestamp(now()));
-- --------------------------------------
-- 系统角色 1 超级管理员,2 管理员,3 普通用户
-- --------------------------------------
INSERT INTO `mw_role` (`role_id`, `name`, `type`, `is_delete`, `create_time`, `update_time`) VALUES ('1', '超级管理员', '1', '0', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_role` (`role_id`, `name`, `type`, `is_delete`, `create_time`, `update_time`) VALUES ('2', '管理员', '1', '0', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_role` (`role_id`, `name`, `type`, `is_delete`, `create_time`, `update_time`) VALUES ('3', '普通用户', '1', '0', unix_timestamp(now()), unix_timestamp(now()));
-- --------------------------------------
-- 系统权限
-- --------------------------------------
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (1, '个人中心', 0, 'menu', '', '', 'glyphicon-leaf', '', 1, 1, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (2, '个人资料', 1, 'controller', 'profile', 'info', 'glyphicon-list', '', 1, 11, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (3, '修改资料', 1, 'controller', 'profile', 'edit', 'glyphicon-list', '', 0, 12, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (4, '修改资料保存', 1, 'controller', 'profile', 'modify', 'glyphicon-list', '', 0, 13, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (5, '关注用户列表', 1, 'controller', 'profile', 'followUser', 'glyphicon-list', '', 0, 14, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (6, '关注文档列表', 1, 'controller', 'profile', 'followDoc', 'glyphicon-list', '', 0, 15, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (7, '我的活动', 1, 'controller', 'profile', 'activity', 'glyphicon-list', '', 1, 16, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (8, '修改密码', 1, 'controller', 'profile', 'password', 'glyphicon-list', '', 1, 17, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (9, '修改密码保存', 1, 'controller', 'profile', 'savePass', 'glyphicon-list', '', 0, 18, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (10, '用户管理', 1, 'menu', '', '', 'glyphicon-user', '', 1, 2, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (11, '添加用户', 10, 'controller', 'user', 'add', 'glyphicon-list', '', 1, 21, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (12, '添加用户保存', 10, 'controller', 'user', 'save', 'glyphicon-list', '', 0, 22, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (13, '用户列表', 10, 'controller', 'user', 'list', 'glyphicon-list', '', 1, 23, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (14, '修改用户', 10, 'controller', 'user', 'edit', 'glyphicon-list', '', 0, 24, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (15, '修改用户保存', 10, 'controller', 'user', 'modify', 'glyphicon-list', '', 0, 25, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (16, '屏蔽用户', 10, 'controller', 'user', 'forbidden', 'glyphicon-list', '', 0, 26, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (17, '恢复用户', 10, 'controller', 'user', 'recover', 'glyphicon-list', '', 0, 27, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (18, '用户详情', 10, 'controller', 'user', 'info', 'glyphicon-list', '', 0, 28, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (19, '角色管理', 1, 'menu', '', '', 'glyphicon-gift', '', 1, 3, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (20, '添加角色', 19, 'controller', 'role', 'add', 'glyphicon-list', '', 1, 31, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (21, '添加角色保存', 19, 'controller', 'role', 'save', 'glyphicon-list', '', 0, 32, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (22, '角色列表', 19, 'controller', 'role', 'list', 'glyphicon-list', '', 1, 33, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (23, '修改角色', 19, 'controller', 'role', 'edit', 'glyphicon-list', '', 0, 34, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (24, '修改角色保存', 19, 'controller', 'role', 'modify', 'glyphicon-list', '', 0, 35, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (25, '角色用户列表', 19, 'controller', 'role', 'user', 'glyphicon-list', '', 0, 36, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (26, '角色权限', 19, 'controller', 'role', 'privilege', 'glyphicon-list', '', 0, 37, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (27, '角色权限保存', 19, 'controller', 'role', 'grantPrivilege', 'glyphicon-list', '', 0, 38, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (28, '删除角色', 19, 'controller', 'role', 'delete', 'glyphicon-list', '', 0, 29, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (29, '重置用户角色', 19, 'controller', 'role', 'resetUser', 'glyphicon-list', '', 0, 310, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (30, '权限管理', 1, 'menu', '', '', 'glyphicon-lock', '', 1, 4, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (31, '添加权限', 30, 'controller', 'privilege', 'add', 'glyphicon-list', '', 1, 41, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (32, '添加权限保存', 30, 'controller', 'privilege', 'save', 'glyphicon-list', '', 0, 42, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (33, '权限列表', 30, 'controller', 'privilege', 'list', 'glyphicon-list', '', 1, 43, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (34, '修改权限', 30, 'controller', 'privilege', 'edit', 'glyphicon-list', '', 0, 44, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (35, '修改权限保存', 30, 'controller', 'privilege', 'modify', 'glyphicon-list', '', 0, 45, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (36, '删除权限', 30, 'controller', 'privilege', 'delete', 'glyphicon-list', '', 0, 46, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (37, '空间管理', 1, 'menu', '', '', 'glyphicon-th-large', '', 1, 5, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (38, '添加空间', 37, 'controller', 'space', 'add', 'glyphicon-list', '', 1, 51, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (39, '添加空间保存', 37, 'controller', 'space', 'save', 'glyphicon-list', '', 0, 52, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (40, '空间列表', 37, 'controller', 'space', 'list', 'glyphicon-list', '', 1, 53, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (41, '修改空间', 37, 'controller', 'space', 'edit', 'glyphicon-list', '', 0, 54, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (42, '修改空间保存', 37, 'controller', 'space', 'modify', 'glyphicon-list', '', 0, 55, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (43, '空间成员列表', 37, 'controller', 'space', 'member', 'glyphicon-list', '', 0, 56, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (44, '添加空间成员', 37, 'controller', 'space_user', 'save', 'glyphicon-list', '', 0, 57, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (45, '移除空间成员', 37, 'controller', 'space_user', 'remove', 'glyphicon-list', '', 0, 58, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (46, '更新空间成员权限', 37, 'controller', 'space_user', 'modify', 'glyphicon-list', '', 0, 59, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (47, '删除空间', 37, 'controller', 'space', 'delete', 'glyphicon-list', '', 0, 510, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (48, '空间备份', 37, 'controller', 'space', 'download', 'glyphicon-list', '', 0, 512, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (49, '日志管理', 1, 'menu', '', '', 'glyphicon-list-alt', '', 1, 6, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (50, '系统日志', 49, 'controller', 'log', 'system', 'glyphicon-list', '', 1, 61, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (51, '系统日志详情', 49, 'controller', 'log', 'info', 'glyphicon-list', '', 0, 62, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (52, '文档日志', 49, 'controller', 'log', 'document', 'glyphicon-list', '', 1, 63, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (53, '配置管理', 1, 'menu', '', '', 'glyphicon-cog', '', 1, 7, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (54, '全局配置', 53, 'controller', 'config', 'global', 'glyphicon-list', '', 1, 71, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (55, '全局配置保存', 53, 'controller', 'config', 'modify', 'glyphicon-list', '', 0, 72, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (56, '邮箱配置', 53, 'controller', 'email', 'list', 'glyphicon-list', '', 1, 73, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (57, '添加邮件服务器', 53, 'controller', 'email', 'add', 'glyphicon-list', '', 0, 74, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (58, '添加邮件服务器保存', 53, 'controller', 'email', 'save', 'glyphicon-list', '', 0, 75, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (59, '修改邮件服务器', 53, 'controller', 'email', 'edit', 'glyphicon-list', '', 0, 76, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (60, '修改邮件服务器保存', 53, 'controller', 'email', 'modify', 'glyphicon-list', '', 0, 77, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (61, '启用邮件服务器', 53, 'controller', 'email', 'used', 'glyphicon-list', '', 0, 78, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (62, '删除邮件服务器', 53, 'controller', 'email', 'delete', 'glyphicon-list', '', 0, 79, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (63, '登录认证', 53, 'controller', 'auth', 'list', 'glyphicon-list', '', 1, 81, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (64, '添加登录认证', 53, 'controller', 'auth', 'add', 'glyphicon-list', '', 0, 82, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (65, '添加登录认证保存', 53, 'controller', 'auth', 'save', 'glyphicon-list', '', 0, 83, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (66, '修改登录认证', 53, 'controller', 'auth', 'edit', 'glyphicon-list', '', 0, 84, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (67, '修改登录认证保存', 53, 'controller', 'auth', 'modify', 'glyphicon-list', '', 0, 85, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (68, '删除登录认证', 53, 'controller', 'auth', 'delete', 'glyphicon-list', '', 0, 86, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (69, '启用登录认证', 53, 'controller', 'auth', 'used', 'glyphicon-list', '', 0, 87, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (70, '登录认证文档', 53, 'controller', 'auth', 'doc', 'glyphicon-list', '', 0, 88, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (71, '系统管理', 1, 'menu', '', '', 'glyphicon-link', '', 1, 8, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (72, '快捷链接', 71, 'controller', 'link', 'list', 'glyphicon-list', '', 1, 81, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (73, '添加链接', 71, 'controller', 'link', 'add', 'glyphicon-list', '', 0, 82, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (74, '添加链接保存', 71, 'controller', 'link', 'save', 'glyphicon-list', '', 0, 83, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (75, '修改链接', 71, 'controller', 'link', 'edit', 'glyphicon-list', '', 0, 84, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (76, '修改链接保存', 71, 'controller', 'link', 'modify', 'glyphicon-list', '', 0, 85, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (77, '删除链接', 71, 'controller', 'link', 'delete', 'glyphicon-list', '', 0, 86, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (78, '系统联系人', 71, 'controller', 'contact', 'list', 'glyphicon-list', '', 1, 91, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (79, '添加联系人', 71, 'controller', 'contact', 'add', 'glyphicon-list', '', 0, 92, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (80, '添加联系人保存', 71, 'controller', 'contact', 'save', 'glyphicon-list', '', 0, 93, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (81, '修改联系人', 71, 'controller', 'contact', 'edit', 'glyphicon-list', '', 0, 94, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (82, '修改联系人保存', 71, 'controller', 'contact', 'modify', 'glyphicon-list', '', 0, 95, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (83, '删除联系人', 71, 'controller', 'contact', 'delete', 'glyphicon-list', '', 0, 96, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (84, '统计管理', 1, 'menu', '', '', 'glyphicon-signal', '', 1, 9, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (85, '数据统计', 84, 'controller', 'static', 'default', 'glyphicon-list', '', 1, 91, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (86, 'ajax获取空间文档排行', 84, 'controller', 'static', 'spaceDocsRank', 'glyphicon-list', '', 0, 92, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (87, 'ajax获取收藏文档排行', 84, 'controller', 'static', 'collectDocRank', 'glyphicon-list', '', 0, 93, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (88, 'ajax获取文档数量增长趋势', 84, 'controller', 'static', 'docCountByTime', 'glyphicon-list', '', 0, 94, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (89, '系统监控', 84, 'controller', 'static', 'monitor', 'glyphicon-list', '', 1, 95, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (90, 'ajax获取服务器状态', 84, 'controller', 'static', 'serverStatus', 'glyphicon-list', '', 0, 96, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (91, 'ajax获取服务器时间', 84, 'controller', 'static', 'serverTime', 'glyphicon-list', '', 0, 97, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (92, '测试邮件服务器', 53, 'controller', 'email', 'test', 'glyphicon-list', '', 0, 80, unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO mw_privilege (privilege_id, name, parent_id, type, controller, action, icon, target, is_display, sequence, create_time, update_time) VALUES (93, '导入联系人', 71, 'controller', 'contact', 'import', 'glyphicon-list', '', 0, 97, unix_timestamp(now()), unix_timestamp(now()));
-- ---------------------------------------------
-- 系统角色权限关系数据
-- ---------------------------------------------
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (1, 3, 1, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (2, 3, 2, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (3, 3, 3, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (4, 3, 4, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (5, 3, 5, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (6, 3, 6, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (7, 3, 7, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (8, 3, 8, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (9, 3, 9, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (10, 2, 1, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (11, 2, 2, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (12, 2, 3, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (13, 2, 4, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (14, 2, 5, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (15, 2, 6, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (16, 2, 7, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (17, 2, 8, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (18, 2, 9, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (19, 2, 37, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (20, 2, 38, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (21, 2, 39, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (22, 2, 40, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (23, 2, 41, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (24, 2, 42, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (25, 2, 43, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (26, 2, 44, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (27, 2, 45, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (28, 2, 46, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (29, 2, 47, unix_timestamp(now()));
INSERT INTO mw_role_privilege (role_privilege_id, role_id, privilege_id, create_time) VALUES (30, 2, 48, unix_timestamp(now()));
-- -------------------------------------------
-- 系统配置
-- -------------------------------------------
INSERT INTO `mw_config` VALUES ('1', '主页标题', 'main_title', '这里可以填写公司名称,例如:欢迎来到 XXXX 科技公司 wiki 平台!', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` VALUES ('2', '主页描述', 'main_description', '这是写一些描述:请使用域账号登录,使用中有任何问题请联系管理员 root@xxx.com', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` VALUES ('3', '是否开启自动关注', 'auto_follow_doc_open', '', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` VALUES ('4', '是否开启邮件通知', 'send_email_open', '', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` VALUES ('5', '是否开启统一登录', 'sso_open', '', unix_timestamp(now()), unix_timestamp(now()));
-- INSERT INTO `mw_config` (name, key, value, create_time, update_time) VALUES ('系统版本号', 'system_version', 'v0.0.0', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('开启全文搜索', 'fulltext_search_open', '1', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('索引更新间隔', 'doc_search_timer', '3600', unix_timestamp(now()), unix_timestamp(now()));
INSERT INTO `mw_config` (name, `key`, value, create_time, update_time) VALUES ('系统名称', 'system_name', 'Markdown Mini Wiki', unix_timestamp(now()), unix_timestamp(now()));
+305
View File
@@ -0,0 +1,305 @@
-- --------------------------------
-- MM-Wiki 表结构
-- author: phachon
-- --------------------------------
-- 手动安装时首先需要创建数据库
-- CREATE DATABASE IF NOT EXISTS mm_wiki DEFAULT CHARSET utf8;
-- --------------------------------
-- 用户表
-- --------------------------------
DROP TABLE IF EXISTS `mw_user`;
CREATE TABLE `mw_user` (
`user_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '用户 id',
`username` varchar(100) NOT NULL DEFAULT '' COMMENT '用户名',
`password` char(32) NOT NULL DEFAULT '' COMMENT '密码',
`given_name` varchar(50) NOT NULL DEFAULT '' COMMENT '姓名',
`mobile` char(13) NOT NULL DEFAULT '' COMMENT '手机号',
`phone` char(13) NOT NULL DEFAULT '' COMMENT '电话',
`email` varchar(50) NOT NULL DEFAULT '' COMMENT '邮箱',
`department` char(50) NOT NULL DEFAULT '' COMMENT '部门',
`position` char(50) NOT NULL DEFAULT '' COMMENT '职位',
`location` char(50) NOT NULL DEFAULT '' COMMENT '位置',
`im` char(50) NOT NULL DEFAULT '' COMMENT '即时聊天工具',
`last_ip` varchar(15) NOT NULL DEFAULT '' COMMENT '最后登录ip',
`last_time` int(11) NOT NULL DEFAULT '0' COMMENT '最后登录时间',
`role_id` tinyint(3) NOT NULL DEFAULT '0' COMMENT '角色 id',
`is_forbidden` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否屏蔽,0 否 1 是',
`is_delete` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否删除,0 否 1 是',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
-- ---------------------------------------------------------------
-- 系统角色表
-- ---------------------------------------------------------------
DROP TABLE IF EXISTS `mw_role`;
CREATE TABLE `mw_role` (
`role_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '角色 id',
`name` char(10) NOT NULL DEFAULT '' COMMENT '角色名称',
`type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '角色类型 0 自定义角色,1 系统角色',
`is_delete` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否删除,0 否 1 是',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统角色表';
-- -------------------------------------------------------
-- 系统权限表
-- -------------------------------------------------------
DROP TABLE IF EXISTS `mw_privilege`;
CREATE TABLE `mw_privilege` (
`privilege_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '权限id',
`name` char(30) NOT NULL DEFAULT '' COMMENT '权限名',
`parent_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上级',
`type` enum('controller','menu') DEFAULT 'controller' COMMENT '权限类型:控制器、菜单',
`controller` char(100) NOT NULL DEFAULT '' COMMENT '控制器',
`action` char(100) NOT NULL DEFAULT '' COMMENT '动作',
`icon` char(100) NOT NULL DEFAULT '' COMMENT '图标(用于展示)',
`target` char(200) NOT NULL DEFAULT '' COMMENT '目标地址',
`is_display` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否显示:0不显示 1显示',
`sequence` int(10) NOT NULL DEFAULT '0' COMMENT '排序(越小越靠前)',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`privilege_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统权限表';
-- ------------------------------------------------------------------
-- 系统角色权限对应关系表
-- ------------------------------------------------------------------
DROP TABLE IF EXISTS `mw_role_privilege`;
CREATE TABLE `mw_role_privilege` (
`role_privilege_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '角色权限关系 id',
`role_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '角色id',
`privilege_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '权限id',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`role_privilege_id`),
KEY (`role_id`),
KEY (`privilege_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统角色权限对应关系表';
-- --------------------------------
-- 空间表
-- --------------------------------
DROP TABLE IF EXISTS `mw_space`;
CREATE TABLE `mw_space` (
`space_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '空间 id',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',
`description` varchar(100) NOT NULL DEFAULT '' COMMENT '描述',
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT '标签',
`visit_level` enum('private','public') NOT NULL DEFAULT 'public' COMMENT '访问级别:private,public',
`is_share` tinyint(3) NOT NULL DEFAULT '1' COMMENT '文档是否允许分享 0 否 1 是',
`is_export` tinyint(3) NOT NULL DEFAULT '1' COMMENT '文档是否允许导出 0 否 1 是',
`is_delete` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否删除 0 否 1 是',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`space_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='空间表';
-- --------------------------------
-- 空间成员表
-- --------------------------------
DROP TABLE IF EXISTS `mw_space_user`;
CREATE TABLE `mw_space_user` (
`space_user_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '用户空间关系 id',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '用户 id',
`space_id` int(10) NOT NULL DEFAULT '0' COMMENT '空间 id',
`privilege` tinyint(3) NOT NULL DEFAULT '0' COMMENT '空间成员操作权限 0 浏览者 1 编辑者 2 管理员',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间',
PRIMARY KEY (`space_user_id`),
UNIQUE KEY (`user_id`, `space_id`),
KEY (`user_id`),
KEY (`space_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='空间成员表';
-- --------------------------------
-- 文档表
-- --------------------------------
DROP TABLE IF EXISTS `mw_document`;
CREATE TABLE `mw_document` (
`document_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '文档 id',
`parent_id` int(10) NOT NULL DEFAULT '0' COMMENT '文档父 id',
`space_id` int(10) NOT NULL DEFAULT '0' COMMENT '空间id',
`name` varchar(150) NOT NULL DEFAULT '' COMMENT '文档名称',
`type` tinyint(3) NOT NULL DEFAULT '1' COMMENT '文档类型 1 page 2 dir',
`path` char(30) NOT NULL DEFAULT '0' COMMENT '存储根文档到父文档的 document_id 值, 格式 0,1,2,...',
`sequence` int(10) NOT NULL DEFAULT '0' COMMENT '排序号(越小越靠前)',
`create_user_id` int(10) NOT NULL DEFAULT '0' COMMENT '创建用户 id',
`edit_user_id` int(10) NOT NULL DEFAULT '0' COMMENT '最后修改用户 id',
`is_delete` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否删除 0 否 1 是',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`document_id`),
KEY (`parent_id`),
KEY (`space_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文档表';
-- --------------------------------
-- 用户收藏表
-- --------------------------------
DROP TABLE IF EXISTS `mw_collection`;
CREATE TABLE `mw_collection` (
`collection_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '用户收藏关系 id',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '用户id',
`type` tinyint(3) NOT NULL DEFAULT '1' COMMENT '收藏类型 1 文档 2 空间',
`resource_id` int(10) NOT NULL DEFAULT '0' COMMENT '收藏资源 id ',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`collection_id`),
KEY (`user_id`),
UNIQUE key (`user_id`, `resource_id`, `type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收藏表';
-- --------------------------------
-- 用户关注表
-- --------------------------------
DROP TABLE IF EXISTS `mw_follow`;
CREATE TABLE `mw_follow` (
`follow_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '关注 id',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '用户id',
`type` tinyint(3) NOT NULL DEFAULT '1' COMMENT '关注类型 1 文档 2 用户',
`object_id` int(10) NOT NULL DEFAULT '0' COMMENT '关注对象 id',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`follow_id`),
KEY (`user_id`),
KEY (`object_id`),
UNIQUE key (`user_id`, `object_id`, `type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户关注表';
-- --------------------------------
-- 文档日志表
-- --------------------------------
DROP TABLE IF EXISTS `mw_log_document`;
CREATE TABLE `mw_log_document` (
`log_document_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '文档日志 id',
`document_id` int(10) NOT NULL DEFAULT '0' COMMENT '文档id',
`space_id` int(10) NOT NULL DEFAULT '0' COMMENT '空间id',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '用户id',
`action` tinyint(3) NOT NULL DEFAULT '1' COMMENT '动作 1 创建 2 修改 3 删除',
`comment` varchar(255) NOT NULL DEFAULT '' COMMENT '备注信息',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`log_document_id`),
KEY (`document_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文档日志表';
-- --------------------------------
-- 系统操作日志表
-- --------------------------------
DROP TABLE IF EXISTS `mw_log`;
CREATE TABLE `mw_log` (
`log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '系统操作日志 id',
`level` tinyint(3) NOT NULL DEFAULT '6' COMMENT '日志级别',
`path` char(100) NOT NULL DEFAULT '' COMMENT '请求路径',
`get` text NOT NULL COMMENT 'get参数',
`post` text NOT NULL COMMENT 'post参数',
`message` varchar(255) NOT NULL DEFAULT '' COMMENT '信息',
`ip` char(100) NOT NULL DEFAULT '' COMMENT 'ip地址',
`user_agent` char(200) NOT NULL DEFAULT '' COMMENT '用户代理',
`referer` char(100) NOT NULL DEFAULT '' COMMENT 'referer',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '用户id',
`username` char(100) NOT NULL DEFAULT '' COMMENT '用户名',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`log_id`),
KEY (`level`, `username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统操作日志表';
-- --------------------------------
-- 邮件服务器表
-- --------------------------------
DROP TABLE IF EXISTS `mw_email`;
CREATE TABLE `mw_email` (
`email_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '邮箱 id',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '邮箱服务器名称',
`sender_address` varchar(100) NOT NULL DEFAULT '' COMMENT '发件人邮件地址',
`sender_name` varchar(100) NOT NULL DEFAULT '' COMMENT '发件人显示名',
`sender_title_prefix` varchar(100) NOT NULL DEFAULT '' COMMENT '发送邮件标题前缀',
`host` char(100) NOT NULL DEFAULT '' COMMENT '服务器主机名',
`port` int(5) NOT NULL DEFAULT '25' COMMENT '服务器端口',
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`is_ssl` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用ssl, 0 默认不使用 1 使用',
`is_used` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否被使用, 0 默认不使用 1 使用',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`email_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件服务器表';
-- --------------------------------
-- 快捷链接表
-- --------------------------------
DROP TABLE IF EXISTS `mw_link`;
CREATE TABLE `mw_link` (
`link_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '链接 id',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '链接名称',
`url` varchar(100) NOT NULL DEFAULT '' COMMENT '链接地址',
`sequence` int(10) NOT NULL DEFAULT '0' COMMENT '排序号(越小越靠前)',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`link_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='快捷链接表';
-- --------------------------------
-- 统一登录认证表
-- --------------------------------
DROP TABLE IF EXISTS `mw_login_auth`;
CREATE TABLE `mw_login_auth` (
`login_auth_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '认证表主键ID',
`name` varchar(30) NOT NULL COMMENT '登录认证名称',
`username_prefix` varchar(30) NOT NULL COMMENT '用户名前缀',
`url` varchar(200) NOT NULL COMMENT '认证接口 url',
`ext_data` varchar(500) NOT NULL DEFAULT '' COMMENT '额外数据: token=aaa&key=bbb',
`is_used` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否被使用, 0 默认不使用 1 使用',
`is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 0 否 1 是',
`create_time` int(11) NOT NULL COMMENT '创建时间',
`update_time` int(11) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`login_auth_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='统一登录认证表';
-- --------------------------------
-- 全局配置表
-- --------------------------------
DROP TABLE IF EXISTS `mw_config`;
CREATE TABLE `mw_config` (
`config_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置表主键Id',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '配置名称',
`key` char(50) NOT NULL DEFAULT '' COMMENT '配置键',
`value` text NOT NULL COMMENT '配置值',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`config_id`),
unique KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='全局配置表';
-- --------------------------------
-- 系统联系人表
-- --------------------------------
DROP TABLE IF EXISTS `mw_contact`;
CREATE TABLE `mw_contact` (
`contact_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '联系人 id',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '联系人名称',
`mobile` char(13) NOT NULL DEFAULT '' COMMENT '联系电话',
`email` varchar(50) NOT NULL DEFAULT '' COMMENT '邮箱',
`position` varchar(100) NOT NULL DEFAULT '' COMMENT '联系人职位',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='联系人表';
-- --------------------------------
-- 附件信息表
-- --------------------------------
DROP TABLE IF EXISTS `mw_attachment`;
CREATE TABLE `mw_attachment` (
`attachment_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '附件 id',
`user_id` int(10) NOT NULL DEFAULT '0' COMMENT '创建用户id',
`document_id` int(10) NOT NULL DEFAULT '0' COMMENT '所属文档id',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '附件名称',
`path` varchar(100) NOT NULL DEFAULT '' COMMENT '附件路径',
`source` tinyint(1) NOT NULL DEFAULT '0' COMMENT '附件来源, 0 默认是附件 1 图片',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`attachment_id`),
KEY (`document_id`, `source`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='附件信息表';
+10
View File
@@ -0,0 +1,10 @@
## 开发日志
准备开发的日志 2020-04-06 21:41:44
1.空间排序, 空间内目录, 文件自由排序, 取消创建文档时的类型选择, 直接在树形中填写文档名称, 后台自动判定, OK 2020-04-07 03:24:48
不需要升级, 无数据库更改
1.1遗留问题, 不能直接拖到其它目录, 移动并自动排序
2.修复首页最近更新文档, 不是自己权限范围内的也能查看
增加字段, alter table mw_log_document add space_id int
同步数据, update mw_log_document as logDocment, mw_document as document set logDocment.space_id = document.space_id WHERE logDocment.document_id = document.document_id
2.文档分享地址加密
+39
View File
@@ -0,0 +1,39 @@
<?php
// 获取数据
$username = isset($_POST["username"]) ? $_POST["username"] : "";
$password = isset($_POST["password"]) ? $_POST["password"] : "";
$extData = isset($_POST["ext_data"]) ? $_POST["ext_data"] : "";
if (!$username || !$password) {
echo json_encode(['message'=>'参数错误', 'data'=>[]], JSON_UNESCAPED_UNICODE);
exit();
}
// 1. ext_data 可用于接口安全验证
if ($extData != "login api token") {
$result = [
'message' => '登录接口验证失败',
'data' => [],
];
echo json_encode($result, JSON_UNESCAPED_UNICODE);
exit();
}
// 2. 验证用户名密码是否正确
// ....
// ....
// 3. 成功返回
$result = [
'message' => '',
'data' => [
'given_name' => '王哈哈',
'mobile' => '111111111111',
'phone' => '010-9929921',
'email' => 'root@mmWiki.com',
'department' => '广告事业部.技术部.系统开发组',
'position' => '高级JAVA开发工程师',
'location' => 'B座32层E区1002',
'im' => 'QQ12211',
],
];
echo json_encode($result, JSON_UNESCAPED_UNICODE);
+3
View File
@@ -0,0 +1,3 @@
dictionary.txt 词典拷贝自 [github.com/fxsjy/jieba](https://github.com/fxsjy/jieba)
stop_tokens.txt 停用词列表来自网络
+589032
View File
File diff suppressed because it is too large Load Diff
+1161
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
package global
import (
//"github.com/go-ego/riot"
)
// 文档搜索
var (
//DocSearcher = riot.Engine{}
)
+6
View File
@@ -0,0 +1,6 @@
package global
const (
SYSTEM_VERSION = "v0.2.2" // system version code
SYSTEM_COPYRIGHT = "2018 - 2022 phachon" // system copyright
)
+27
View File
@@ -0,0 +1,27 @@
module github.com/phachon/mm-wiki
go 1.12
require (
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/astaxie/beego v1.12.0
github.com/fatih/color v1.7.0
github.com/go-ldap/ldap/v3 v3.1.11
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
github.com/go-sql-driver/mysql v1.4.1
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.10 // indirect
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/shirou/gopsutil v2.19.11+incompatible
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/snail007/go-activerecord v0.0.0-20190813031814-2ac2f3d7cff0
github.com/stretchr/testify v1.7.1 // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/russross/blackfriday.v2 v2.0.0
)
+127
View File
@@ -0,0 +1,127 @@
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y=
github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-asn1-ber/asn1-ber v1.5.0 h1:/S4hO/AO6tLMlPX0oftGSOcdGJJN/MuYzfgWRMn199E=
github.com/go-asn1-ber/asn1-ber v1.5.0/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.1.11 h1:EojIR9zHvfQS8LEz+EjvnPSvsfPYS3UioBezeOOskIA=
github.com/go-ldap/ldap/v3 v3.1.11/go.mod h1:dtLsnBXnSLIsMRbCBuRpHflCGaYzZ5jn+x1q7XqMTKU=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/snail007/go-activerecord v0.0.0-20190813031814-2ac2f3d7cff0 h1:zru9A2cEdHTi1ly8KaAMMw8sS93U2nB1LSvc+YwUCc4=
github.com/snail007/go-activerecord v0.0.0-20190813031814-2ac2f3d7cff0/go.mod h1:2oXFU20cqErcrOV0B5VjMDuEZBcT9RUUL89uBR3QjsE=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/russross/blackfriday.v2 v2.0.0 h1:+FlnIV8DSQnT7NZ43hcVKcdJdzZoeCmJj4Ql8gq5keA=
gopkg.in/russross/blackfriday.v2 v2.0.0/go.mod h1:6sSBNz/GtOm/pJTuh5UmBK2ZHfmnxGbl2NZg1UliSOI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+179
View File
@@ -0,0 +1,179 @@
package controllers
import (
"encoding/json"
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/install/storage"
"strings"
)
type BaseController struct {
beego.Controller
}
type JsonResponse struct {
Code int `json:"code"`
Message interface{} `json:"message"`
Data interface{} `json:"data"`
Redirect map[string]interface{} `json:"redirect"`
}
// prepare
func (this *BaseController) Prepare() {
controllerName, actionName := this.GetControllerAndAction()
controllerName = strings.ToLower(controllerName[0 : len(controllerName)-10])
methodName := strings.ToLower(actionName)
if (methodName == "index") || (methodName == "end") || (methodName == "status") {
return
}
if storage.Data.Status == storage.Install_Start {
if methodName == "ready" && this.isPost() {
return
}
this.Redirect("/install/end", 302)
this.StopRun()
}
if storage.Data.Status == storage.Install_End {
if storage.Data.IsSuccess == storage.Install_Failed {
// 重置
storage.Data.IsSuccess = storage.Install_Default
storage.Data.Status = storage.Install_Ready
storage.Data.Result = ""
} else {
this.StopRun()
}
}
}
// view layout title
func (this *BaseController) viewLayoutTitle(title, viewName, layout string) {
this.Layout = "install/layout.html"
this.TplName = viewName + ".html"
this.Data["title"] = title
this.Data["copyright"] = storage.CopyRight
this.Render()
}
// view layout
func (this *BaseController) viewLayout(viewName, layout string) {
this.Layout = "install/layout.html"
this.TplName = viewName + ".html"
this.Data["title"] = ""
this.Data["copyright"] = storage.CopyRight
this.Render()
}
// view
func (this *BaseController) view(viewName string) {
this.Layout = "install/layout.html"
this.TplName = viewName + ".html"
this.Data["title"] = ""
this.Data["copyright"] = storage.CopyRight
this.Render()
}
// error view
func (this *BaseController) viewError(errorMessage string, data ...interface{}) {
this.Layout = "layout/install.html"
redirect := "/"
sleep := 2000
if len(data) > 0 {
redirect = data[0].(string)
}
if len(data) > 1 {
sleep = data[1].(int)
}
_, actionName := this.GetControllerAndAction()
methodName := strings.ToLower(actionName)
this.TplName = "install/error.html"
this.Data["title"] = "error"
this.Data["method"] = methodName
this.Data["message"] = errorMessage
this.Data["redirect"] = redirect
this.Data["sleep"] = sleep
this.Data["copyright"] = storage.CopyRight
this.Render()
}
// view title
func (this *BaseController) viewTitle(title, viewName string) {
this.Layout = "install/layout.html"
this.TplName = viewName + ".html"
this.Data["title"] = title
this.Data["copyright"] = storage.CopyRight
this.Render()
}
// return json success
func (this *BaseController) jsonSuccess(message interface{}, data ...interface{}) {
url := ""
sleep := 300
var _data interface{}
if len(data) > 0 {
_data = data[0]
}
if len(data) > 1 {
url = data[1].(string)
}
if len(data) > 2 {
sleep = data[2].(int)
}
this.Data["json"] = JsonResponse{
Code: 1,
Message: message,
Data: _data,
Redirect: map[string]interface{}{
"url": url,
"sleep": sleep,
},
}
j, err := json.MarshalIndent(this.Data["json"], "", "\t")
if err != nil {
this.Abort(err.Error())
} else {
this.Abort(string(j))
}
}
// return json error
func (this *BaseController) jsonError(message interface{}, data ...interface{}) {
url := ""
sleep := 2000
var _data interface{}
if len(data) > 0 {
_data = data[0]
}
if len(data) > 1 {
url = data[1].(string)
}
if len(data) > 2 {
sleep = data[2].(int)
}
this.Data["json"] = JsonResponse{
Code: 0,
Message: message,
Data: _data,
Redirect: map[string]interface{}{
"url": url,
"sleep": sleep,
},
}
j, err := json.MarshalIndent(this.Data["json"], "", " \t")
if err != nil {
this.Abort(err.Error())
} else {
this.Abort(string(j))
}
}
// get client ip
func (this *BaseController) getClientIp() string {
s := strings.Split(this.Ctx.Request.RemoteAddr, ":")
return s[0]
}
// is post
func (this *BaseController) isPost() bool {
return this.Ctx.Input.IsPost()
}
+368
View File
@@ -0,0 +1,368 @@
package controllers
import (
"github.com/astaxie/beego/validation"
"github.com/phachon/mm-wiki/app/utils"
"github.com/phachon/mm-wiki/global"
"github.com/phachon/mm-wiki/install/storage"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/mem"
"io/ioutil"
"path/filepath"
"runtime"
"strconv"
"strings"
)
type InstallController struct {
BaseController
}
// 安装首页
func (this *InstallController) Index() {
this.view("install/index")
}
// 许可协议
func (this *InstallController) License() {
if this.isPost() {
licenseAgree := this.GetString("license_agree", "")
if licenseAgree == "" || licenseAgree == "0" {
this.jsonError("请先同意协议后再继续")
}
storage.Data.License = storage.License_Agree
this.jsonSuccess("", nil, "/install/env")
} else {
bytes, _ := ioutil.ReadFile(filepath.Join(storage.RootDir, "./LICENSE"))
license := string(bytes)
this.Data["license"] = license
this.Data["license_agree"] = storage.Data.License
this.view("install/license")
}
}
// 环境检测
func (this *InstallController) Env() {
if this.isPost() {
if storage.Data.Env == storage.Env_NotAccess {
this.jsonError("环境检测未通过")
}
storage.Data.Env = storage.Env_Access
this.jsonSuccess("", nil, "/install/config")
}
storage.Data.Env = storage.Env_Access
//获取服务器信息
host := utils.Misc.GetLocalIp()
osSys := runtime.GOOS
server := map[string]string{
"host": host,
"sys": osSys,
"install_dir": storage.RootDir,
"version": global.SYSTEM_VERSION,
}
// 环境检测
vm, _ := mem.VirtualMemory()
vmTotal := vm.Total / 1024 / 1024
cpuCount, _ := cpu.Counts(true)
memData := map[string]interface{}{
"name": "内存",
"require": "400M",
"value": strconv.FormatInt(int64(vmTotal), 10) + "M",
"result": "1",
}
if int(vmTotal) < 400 {
storage.Data.Env = storage.Env_NotAccess
memData["result"] = "0"
}
cpuData := map[string]interface{}{
"name": "CPU",
"require": "1核",
"value": strconv.Itoa(cpuCount) + "核",
"result": "1",
}
if cpuCount < 1 {
storage.Data.Env = storage.Env_NotAccess
cpuData["result"] = "0"
}
envData := []map[string]interface{}{}
envData = append(envData, memData)
envData = append(envData, cpuData)
// 目录文件检测
fileTool := utils.NewFile()
templateConfDir := map[string]string{
"path": "conf/template.conf",
"require": "读/写",
"result": "1",
}
err := fileTool.IsWriterReadable(filepath.Join(storage.RootDir, templateConfDir["path"]))
if err != nil {
storage.Data.Env = storage.Env_NotAccess
templateConfDir["result"] = "0"
}
databaseTable := map[string]string{
"path": "docs/databases/table.sql",
"require": "读/写",
"result": "1",
}
err = fileTool.IsWriterReadable(filepath.Join(storage.RootDir, databaseTable["path"]))
if err != nil {
storage.Data.Env = storage.Env_NotAccess
databaseTable["result"] = "0"
}
databaseData := map[string]string{
"path": "docs/databases/data.sql",
"require": "读/写",
"result": "1",
}
err = fileTool.IsWriterReadable(filepath.Join(storage.RootDir, databaseData["path"]))
if err != nil {
storage.Data.Env = storage.Env_NotAccess
databaseData["result"] = "0"
}
viewsDir := map[string]string{
"path": "views",
"require": "存在且不为空",
"result": "1",
}
isEmpty := utils.File.PathIsEmpty(filepath.Join(storage.RootDir, viewsDir["path"]))
if isEmpty == true {
storage.Data.Env = storage.Env_NotAccess
viewsDir["result"] = "0"
}
staticDir := map[string]string{
"path": "static",
"require": "存在且不为空",
"result": "1",
}
isEmpty = utils.File.PathIsEmpty(filepath.Join(storage.RootDir, staticDir["path"]))
if isEmpty == true {
storage.Data.Env = storage.Env_NotAccess
staticDir["result"] = "0"
}
dirData := []map[string]string{}
dirData = append(dirData, templateConfDir)
dirData = append(dirData, databaseTable)
dirData = append(dirData, databaseData)
dirData = append(dirData, viewsDir)
dirData = append(dirData, staticDir)
this.Data["server"] = server
this.Data["envData"] = envData
this.Data["dirData"] = dirData
this.view("install/env")
}
// 系统配置
func (this *InstallController) Config() {
if this.isPost() {
addr := strings.TrimSpace(this.GetString("addr", ""))
documentDir := strings.TrimSpace(this.GetString("document_dir", ""))
port, _ := this.GetInt32("port", 0)
if addr == "" {
this.jsonError("addr 不能为空,默认请填写 0.0.0.0")
}
if port == 0 {
this.jsonError("启动端口不能为空")
}
if port > int32(65535) {
this.jsonError("端口超出范围")
}
if documentDir == "" {
this.jsonError("文档保存目录不能为空")
}
if !filepath.IsAbs(documentDir) {
this.jsonError("文档保存目录不是绝对路径")
}
docAbsDir, err := filepath.Abs(documentDir)
if err != nil {
this.jsonError("文档保存目录错误!")
}
ok, _ := utils.File.PathIsExists(docAbsDir)
if !ok {
this.jsonError("文档保存目录不存在!")
}
storage.Data.SystemConf = map[string]string{
"addr": addr,
"port": strconv.FormatInt(int64(port), 10),
"document_dir": documentDir,
}
storage.Data.System = storage.Sys_Access
this.jsonSuccess("", nil, "/install/database")
}
sysConf := storage.Data.SystemConf
this.Data["sysConf"] = sysConf
this.view("install/config")
}
// 数据库配置
func (this *InstallController) Database() {
if !this.isPost() {
this.Data["databaseConf"] = storage.Data.DatabaseConf
this.viewLayoutTitle("mm-wiki-安装-数据库配置", "install/database", "install")
return
}
host := strings.TrimSpace(this.GetString("host", ""))
port := strings.TrimSpace(this.GetString("port", ""))
name := strings.TrimSpace(this.GetString("name", ""))
user := strings.TrimSpace(this.GetString("user", ""))
pass := strings.TrimSpace(this.GetString("pass", ""))
connMaxIdle := strings.TrimSpace(this.GetString("conn_max_idle", "0"))
connMaxConn := strings.TrimSpace(this.GetString("conn_max_connection", "0"))
adminName := strings.TrimSpace(this.GetString("admin_name", ""))
adminPass := strings.TrimSpace(this.GetString("admin_pass", ""))
if host == "" {
this.jsonError("数据库 host 不能为空!")
}
if port == "" {
this.jsonError("数据库端口不能为空!")
}
if name == "" {
this.jsonError("数据库名不能为空!")
}
if user == "" {
this.jsonError("数据库用户名不能为空!")
}
if pass == "" {
this.jsonError("数据库密码不能为空!")
}
if connMaxIdle == "0" {
this.jsonError("数据库连接数不能为0")
}
if connMaxConn == "0" {
this.jsonError("最大连接数不能为0")
}
if adminName == "" {
this.jsonError("超级管理员用户名不能为空!")
} else {
v := validation.Validation{}
if !v.AlphaNumeric(adminName, "admin_name").Ok {
this.jsonError("用户名格式不正确!")
}
}
if adminPass == "" {
this.jsonError("超级管理员密码不能为空!")
}
storage.Data.DatabaseConf = map[string]string{
"host": host,
"port": port,
"name": name,
"user": user,
"pass": pass,
"conn_max_idle": connMaxIdle,
"conn_max_connection": connMaxConn,
"admin_name": adminName,
"admin_pass": adminPass,
}
storage.Data.Database = storage.Database_Access
this.jsonSuccess("", nil, "/install/ready")
}
// 安装准备
func (this *InstallController) Ready() {
if this.isPost() {
if (storage.Data.License != storage.License_Agree) ||
(storage.Data.Env != storage.Env_Access) ||
(storage.Data.System != storage.Sys_Access) ||
(storage.Data.Database != storage.Database_Access) {
this.jsonError("请先完成安装准备")
}
storage.StartInstall()
this.jsonSuccess("", nil, "/install/end")
}
// 协议
licenseConf := map[string]interface{}{
"name": "许可协议",
"value": "同意",
"result": "1",
"url": "/install/license",
}
if storage.Data.License != storage.License_Agree {
licenseConf["value"] = "未同意"
licenseConf["result"] = "0"
}
//环境检测
envConf := map[string]interface{}{
"name": "环境检测",
"value": "通过",
"result": "1",
"url": "/install/env",
}
if storage.Data.Env != storage.Env_Access {
envConf["value"] = "未通过"
envConf["result"] = "0"
}
//系统配置
sysConf := map[string]interface{}{
"name": "系统配置",
"value": "完成",
"result": "1",
"url": "/install/config",
}
if storage.Data.System != storage.Sys_Access {
sysConf["value"] = "未完成"
sysConf["result"] = "0"
}
//数据库配置
databaseConf := map[string]interface{}{
"name": "数据库配置",
"value": "完成",
"result": "1",
"url": "/install/database",
}
if storage.Data.Database != storage.Database_Access {
databaseConf["value"] = "未完成"
databaseConf["result"] = "0"
}
readyConf := []map[string]interface{}{}
readyConf = append(readyConf, licenseConf)
readyConf = append(readyConf, envConf)
readyConf = append(readyConf, sysConf)
readyConf = append(readyConf, databaseConf)
this.Data["readyConf"] = readyConf
this.view("install/ready")
}
// 安装完成
func (this *InstallController) End() {
if storage.Data.Status == storage.Install_Ready {
this.Redirect("/install/ready", 302)
}
this.view("install/end")
}
// 获取状态
func (this *InstallController) Status() {
data := map[string]interface{}{
"status": storage.Data.Status,
"is_success": storage.Data.IsSuccess,
"result": storage.Data.Result,
}
this.jsonSuccess("ok", data)
}
+29
View File
@@ -0,0 +1,29 @@
package main
import (
"flag"
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/install/storage"
"log"
"os"
"path/filepath"
)
// install
var (
port = flag.String("port", "8090", "please input listen port")
)
func main() {
flag.Parse()
_, err := os.Stat(filepath.Join(storage.RootDir, "./install.lock"))
if err == nil || !os.IsNotExist(err) {
log.Println("MM-Wiki already installed!")
os.Exit(1)
}
//beego.BConfig.RunMode = "prod"
beego.Run(":" + *port)
}
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"github.com/astaxie/beego"
"github.com/phachon/mm-wiki/app/utils"
"github.com/phachon/mm-wiki/install/controllers"
"github.com/phachon/mm-wiki/install/storage"
"net/http"
"os"
"path/filepath"
)
func init() {
storage.InstallDir, _ = filepath.Abs(filepath.Dir(os.Args[0]))
storage.RootDir = filepath.Join(storage.InstallDir, "../")
beego.AppConfig.Set("sys.name", "mm-wiki-installer")
beego.BConfig.AppName = beego.AppConfig.String("sys.name")
beego.BConfig.ServerName = beego.AppConfig.String("sys.name")
// set static path
beego.SetStaticPath("/static/", filepath.Join(storage.InstallDir, "../static"))
// views path
beego.BConfig.WebConfig.ViewsPath = filepath.Join(storage.InstallDir, "../views/")
// session
beego.BConfig.WebConfig.Session.SessionName = "mmwikiinstallssid"
beego.BConfig.WebConfig.Session.SessionOn = true
// router
beego.BConfig.WebConfig.AutoRender = false
beego.BConfig.RouterCaseSensitive = false
beego.AutoRouter(&controllers.InstallController{})
beego.Router("/", &controllers.InstallController{}, "*:Index")
beego.ErrorHandler("404", http_404)
beego.ErrorHandler("500", http_500)
// add template func
beego.AddFuncMap("dateFormat", utils.NewDate().Format)
}
func http_404(rs http.ResponseWriter, req *http.Request) {
rs.Write([]byte("404 not found!"))
}
func http_500(rs http.ResponseWriter, req *http.Request) {
rs.Write([]byte("500 server error!"))
}
+348
View File
@@ -0,0 +1,348 @@
package storage
import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/phachon/mm-wiki/app/utils"
"github.com/phachon/mm-wiki/global"
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
)
var (
Data = NewData()
installChan = make(chan int, 1)
InstallDir = ""
RootDir = ""
CopyRight = global.SYSTEM_COPYRIGHT
)
const License_Disagree = 0 // 协议不同意
const License_Agree = 1 // 协议同意
const Env_NotAccess = 0 // 环境检测不通过
const Env_Access = 1 // 环境检测通过
const Sys_NotAccess = 0 // 系统配置不通过
const Sys_Access = 1 // 系统配置通过
const Database_NotAccess = 0 // 数据库配置不通过
const Database_Access = 1 // 数据库配置通过
const Install_Ready = 0 // 安装准备阶段
const Install_Start = 1 // 安装开始
const Install_End = 2 // 安装完成
const Install_Default = 0 // 默认
const Install_Failed = 1 // 安装失败
const Install_Success = 2 // 安装成功
var defaultSystemConf = map[string]string{
"addr": "0.0.0.0",
"port": "8080",
"document_dir": "",
}
var defaultDatabaseConf = map[string]string{
"host": "127.0.0.1",
"port": "3306",
"name": "mm_wiki",
"user": "",
"pass": "",
"conn_max_idle": "30",
"conn_max_connection": "200",
"admin_name": "",
"admin_pass": "",
}
func NewData() *data {
return &data{
License: License_Disagree,
Env: Env_NotAccess,
System: Sys_NotAccess,
Database: Database_NotAccess,
SystemConf: defaultSystemConf,
DatabaseConf: defaultDatabaseConf,
Status: Install_Ready,
Result: "",
IsSuccess: Install_Default,
}
}
type data struct {
License int
Env int
System int
Database int
SystemConf map[string]string
DatabaseConf map[string]string
Status int
Result string
IsSuccess int
}
// check db
func checkDB() (err error) {
host := Data.DatabaseConf["host"]
port := Data.DatabaseConf["port"]
user := Data.DatabaseConf["user"]
pass := Data.DatabaseConf["pass"]
db, err := sql.Open("mysql", user+":"+pass+"@tcp("+host+":"+port+")/")
if err != nil {
return
}
defer db.Close()
err = db.Ping()
if err != nil {
return
}
return
}
// create db
func createDB() (err error) {
host := Data.DatabaseConf["host"]
port := Data.DatabaseConf["port"]
user := Data.DatabaseConf["user"]
pass := Data.DatabaseConf["pass"]
name := Data.DatabaseConf["name"]
db, err := sql.Open("mysql", user+":"+pass+"@tcp("+host+":"+port+")/")
if err != nil {
return
}
defer db.Close()
_, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + name + " CHARACTER SET utf8")
if err != nil {
return
}
return nil
}
// create table
func createTable() (err error) {
host := Data.DatabaseConf["host"]
port := Data.DatabaseConf["port"]
user := Data.DatabaseConf["user"]
pass := Data.DatabaseConf["pass"]
name := Data.DatabaseConf["name"]
sqlBytes, err := ioutil.ReadFile(filepath.Join(RootDir, "docs/databases/table.sql"))
if err != nil {
return err
}
sqlTable := string(sqlBytes)
db, err := sql.Open("mysql", user+":"+pass+"@tcp("+host+":"+port+")/"+name+"?charset=utf8&multiStatements=true")
if err != nil {
return
}
defer db.Close()
_, err = db.Exec(sqlTable)
if err != nil {
return
}
return nil
}
// create admin
func createAdmin() (err error) {
host := Data.DatabaseConf["host"]
port := Data.DatabaseConf["port"]
user := Data.DatabaseConf["user"]
pass := Data.DatabaseConf["pass"]
name := Data.DatabaseConf["name"]
adminName := Data.DatabaseConf["admin_name"]
adminPass := utils.NewEncrypt().Md5Encode(Data.DatabaseConf["admin_pass"])
db, err := sql.Open("mysql", user+":"+pass+"@tcp("+host+":"+port+")/"+name+"?charset=utf8")
if err != nil {
return
}
defer db.Close()
stmt, err := db.Prepare("INSERT mw_user SET username=?,password=?,given_name=?,role_id=?, create_time=?,update_time=?")
if err != nil {
return
}
defer stmt.Close()
_, err = stmt.Exec(adminName, adminPass, adminName, 1, time.Now().Unix(), time.Now().Unix())
return
}
// write database install data
func writeInstallData() (err error) {
host := Data.DatabaseConf["host"]
port := Data.DatabaseConf["port"]
user := Data.DatabaseConf["user"]
pass := Data.DatabaseConf["pass"]
name := Data.DatabaseConf["name"]
sqlBytes, err := ioutil.ReadFile(filepath.Join(RootDir, "docs/databases/data.sql"))
if err != nil {
return err
}
sqlTable := string(sqlBytes)
db, err := sql.Open("mysql", user+":"+pass+"@tcp("+host+":"+port+")/"+name+"?charset=utf8&multiStatements=true")
if err != nil {
return
}
defer db.Close()
_, err = db.Exec(sqlTable)
if err != nil {
return
}
// insert version
stmt, err := db.Prepare("INSERT mw_config SET `name`=?,`key`=?,`value`=?,create_time=?,update_time=?;")
if err != nil {
return
}
defer stmt.Close()
_, err = stmt.Exec("系统版本号", "system_version", global.SYSTEM_VERSION, time.Now().Unix(), time.Now().Unix())
return err
}
// write conf
func makeConf() (err error) {
templateConf, err := utils.NewFile().GetFileContents(filepath.Join(RootDir, "conf/template.conf"))
if err != nil {
return
}
// replace conf tag
templateConf = strings.Replace(templateConf, "#httpaddr#", Data.SystemConf["addr"], 1)
templateConf = strings.Replace(templateConf, "#httpport#", Data.SystemConf["port"], 1)
templateConf = strings.Replace(templateConf, "#document_dir#", Data.SystemConf["document_dir"], 1)
templateConf = strings.Replace(templateConf, "#db.host#", Data.DatabaseConf["host"], 1)
templateConf = strings.Replace(templateConf, "#db.port#", Data.DatabaseConf["port"], 1)
templateConf = strings.Replace(templateConf, "#db.name#", Data.DatabaseConf["name"], 1)
templateConf = strings.Replace(templateConf, "#db.user#", Data.DatabaseConf["user"], 1)
templateConf = strings.Replace(templateConf, "#db.pass#", Data.DatabaseConf["pass"], 1)
templateConf = strings.Replace(templateConf, "#db.conn_max_idle#", Data.DatabaseConf["conn_max_idle"], 1)
templateConf = strings.Replace(templateConf, "#db.conn_max_connection#", Data.DatabaseConf["conn_max_connection"], 1)
logFilename := strings.Replace(filepath.Join(RootDir, "logs/mm-wiki.log"), `\`, `/`, -1)
templateConf = strings.Replace(templateConf, "#log.filename#", logFilename, 1)
fileObject, err := os.OpenFile(filepath.Join(RootDir, "conf/mm-wiki.conf"), os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
return
}
defer fileObject.Close()
_, err = fileObject.Write([]byte(templateConf))
return
}
func installFailed(err string) {
Data.Result = err
Data.Status = Install_End
Data.IsSuccess = Install_Failed
log.Println(err)
}
func installSuccess() {
Data.Status = Install_End
Data.IsSuccess = Install_Success
result := map[string]string{
"cmd": "",
"url": "http://127.0.0.1:" + Data.SystemConf["port"],
}
if runtime.GOOS == "windows" {
result["cmd"] = "mm-wiki.exe --conf conf/mm-wiki.conf"
} else {
result["cmd"] = "./mm-wiki --conf conf/mm-wiki.conf"
}
resByte, _ := json.Marshal(result)
Data.Result = string(resByte)
// create install lock file
file, _ := os.Create(filepath.Join(RootDir, "./install.lock"))
file.Close()
}
func StartInstall() {
installChan <- 1
}
func ListenInstall() {
go func() {
defer func() {
err := recover()
if err != nil {
log.Println(fmt.Sprintf("install crash: %v", err))
}
}()
for {
select {
case <-installChan:
Data.Status = Install_Start
// 开始安装
log.Println("mm-wiki start install")
// 检查db
err := checkDB()
if err != nil {
installFailed("连接数据库出错:" + err.Error())
continue
}
log.Println("database connect success")
// 创建数据库
err = createDB()
if err != nil {
installFailed("创建数据库出错:" + err.Error())
continue
}
log.Println("create database success")
// 创建表
err = createTable()
if err != nil {
installFailed("创建表出错:" + err.Error())
continue
}
log.Println("create table success")
// 创建超级管理员
err = createAdmin()
if err != nil {
installFailed("创建管理员账号出错:" + err.Error())
continue
}
log.Println("create admin user success")
// 写入安装数据
err = writeInstallData()
if err != nil {
installFailed("导入安装数据出错:" + err.Error())
continue
}
log.Println("write install data success")
// 写入 conf 文件
err = makeConf()
if err != nil {
installFailed("生成配置文件出错:" + err.Error())
continue
}
log.Println("make conf file success")
installSuccess()
return
}
}
}()
}
func init() {
ListenInstall()
}
+1
View File
@@ -0,0 +1 @@
*.log

Some files were not shown because too many files have changed in this diff Show More