init the project
This commit is contained in:
commit
81e14d12ea
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#idea file
|
||||||
|
.idea
|
||||||
|
|
||||||
|
dist
|
12
build/conf/tank-nginx.conf
Normal file
12
build/conf/tank-nginx.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
server{
|
||||||
|
listen 80;
|
||||||
|
server_name tank.zicpo.cn;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:9090;
|
||||||
|
proxy_set_header host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
client_max_body_size 2048m;
|
||||||
|
}
|
||||||
|
}
|
12
build/conf/tank.json
Normal file
12
build/conf/tank.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"ServerPort": 9090,
|
||||||
|
"LogToConsole": true,
|
||||||
|
"MysqlPort": 3306,
|
||||||
|
"MysqlHost": "127.0.0.1",
|
||||||
|
"MysqlSchema": "tank",
|
||||||
|
"MysqlUserName": "tank",
|
||||||
|
"MysqlPassword": "tank123",
|
||||||
|
"AdminUsername": "admin",
|
||||||
|
"AdminEmail": "admin@tank.eyeblue.cn",
|
||||||
|
"AdminPassword": "123456"
|
||||||
|
}
|
1
build/html/index.html
Normal file
1
build/html/index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html><head><title>tank-front</title><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="user-scalable=no,width=device-width,initial-scale=1,maximum-scale=1"><meta name=msapplication-tap-highlight content=no><meta name=apple-mobile-web-app-capable content=yes><link href=/static/css/app.cfd8f574917fd86fad8effb02f5563b2.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.67df5041971dde987922.js></script><script type=text/javascript src=/static/js/vendor.392879af4bb24a810ba3.js></script><script type=text/javascript src=/static/js/app.64233513a41451689d54.js></script></body></html>
|
File diff suppressed because one or more lines are too long
BIN
build/html/static/fonts/element-icons.6f0a763.ttf
Normal file
BIN
build/html/static/fonts/element-icons.6f0a763.ttf
Normal file
Binary file not shown.
BIN
build/html/static/fonts/fontawesome-webfont.674f50d.eot
Normal file
BIN
build/html/static/fonts/fontawesome-webfont.674f50d.eot
Normal file
Binary file not shown.
BIN
build/html/static/fonts/fontawesome-webfont.af7ae50.woff2
Normal file
BIN
build/html/static/fonts/fontawesome-webfont.af7ae50.woff2
Normal file
Binary file not shown.
BIN
build/html/static/fonts/fontawesome-webfont.b06871f.ttf
Normal file
BIN
build/html/static/fonts/fontawesome-webfont.b06871f.ttf
Normal file
Binary file not shown.
BIN
build/html/static/fonts/fontawesome-webfont.fee66e7.woff
Normal file
BIN
build/html/static/fonts/fontawesome-webfont.fee66e7.woff
Normal file
Binary file not shown.
2671
build/html/static/img/fontawesome-webfont.912ec66.svg
Normal file
2671
build/html/static/img/fontawesome-webfont.912ec66.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
BIN
build/html/static/img/login_background.ee112c7.jpg
Normal file
BIN
build/html/static/img/login_background.ee112c7.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
BIN
build/html/static/img/shattered.ea23162.png
Normal file
BIN
build/html/static/img/shattered.ea23162.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
10
build/html/static/js/app.64233513a41451689d54.js
Normal file
10
build/html/static/js/app.64233513a41451689d54.js
Normal file
File diff suppressed because one or more lines are too long
1
build/html/static/js/app.64233513a41451689d54.js.map
Normal file
1
build/html/static/js/app.64233513a41451689d54.js.map
Normal file
File diff suppressed because one or more lines are too long
2
build/html/static/js/manifest.67df5041971dde987922.js
Normal file
2
build/html/static/js/manifest.67df5041971dde987922.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
!function(e){function __webpack_require__(r){if(_[r])return _[r].exports;var t=_[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,__webpack_require__),t.l=!0,t.exports}var r=window.webpackJsonp;window.webpackJsonp=function(_,n,o){for(var c,a,i,u=0,p=[];u<_.length;u++)a=_[u],t[a]&&p.push(t[a][0]),t[a]=0;for(c in n)Object.prototype.hasOwnProperty.call(n,c)&&(e[c]=n[c]);for(r&&r(_,n,o);p.length;)p.shift()();if(o)for(u=0;u<o.length;u++)i=__webpack_require__(__webpack_require__.s=o[u]);return i};var _={},t={2:0};__webpack_require__.e=function(e){function onScriptComplete(){o.onerror=o.onload=null,clearTimeout(c);var r=t[e];0!==r&&(r&&r[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}var r=t[e];if(0===r)return new Promise(function(e){e()});if(r)return r[2];var _=new Promise(function(_,n){r=t[e]=[_,n]});r[2]=_;var n=document.getElementsByTagName("head")[0],o=document.createElement("script");o.type="text/javascript",o.charset="utf-8",o.async=!0,o.timeout=12e4,__webpack_require__.nc&&o.setAttribute("nonce",__webpack_require__.nc),o.src=__webpack_require__.p+"static/js/"+e+"."+{0:"392879af4bb24a810ba3",1:"64233513a41451689d54"}[e]+".js";var c=setTimeout(onScriptComplete,12e4);return o.onerror=o.onload=onScriptComplete,n.appendChild(o),_},__webpack_require__.m=e,__webpack_require__.c=_,__webpack_require__.d=function(exports,e,r){__webpack_require__.o(exports,e)||Object.defineProperty(exports,e,{configurable:!1,enumerable:!0,get:r})},__webpack_require__.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return __webpack_require__.d(r,"a",r),r},__webpack_require__.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},__webpack_require__.p="/",__webpack_require__.oe=function(e){throw console.error(e),e}}([]);
|
||||||
|
//# sourceMappingURL=manifest.67df5041971dde987922.js.map
|
File diff suppressed because one or more lines are too long
46
build/html/static/js/vendor.392879af4bb24a810ba3.js
Normal file
46
build/html/static/js/vendor.392879af4bb24a810ba3.js
Normal file
File diff suppressed because one or more lines are too long
1
build/html/static/js/vendor.392879af4bb24a810ba3.js.map
Normal file
1
build/html/static/js/vendor.392879af4bb24a810ba3.js.map
Normal file
File diff suppressed because one or more lines are too long
68
build/script/build.bat
Normal file
68
build/script/build.bat
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
@if "%DEBUG%" == "" echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Tank build script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@REM ==== START VALIDATION ====
|
||||||
|
if "%GOPATH%"=="" (
|
||||||
|
echo The GOPATH environment variable is not defined correctly
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
set PRE_DIR=%cd%
|
||||||
|
|
||||||
|
cd %GOPATH%
|
||||||
|
|
||||||
|
echo golang.org . Please download from: https://github.com/MXi4oyu/golang.org and put in the directory with same level of github.com
|
||||||
|
@rem echo go get golang.org/x
|
||||||
|
@rem go get golang.org/x
|
||||||
|
|
||||||
|
@rem resize image
|
||||||
|
echo go get github.com/disintegration/imaging
|
||||||
|
go get github.com/disintegration/imaging
|
||||||
|
|
||||||
|
@rem json parser
|
||||||
|
echo go get github.com/json-iterator/go
|
||||||
|
go get github.com/json-iterator/go
|
||||||
|
|
||||||
|
|
||||||
|
@rem mysql
|
||||||
|
echo go get github.com/go-sql-driver/mysql
|
||||||
|
go get github.com/go-sql-driver/mysql
|
||||||
|
|
||||||
|
@rem dao database
|
||||||
|
echo go get github.com/jinzhu/gorm
|
||||||
|
go get github.com/jinzhu/gorm
|
||||||
|
|
||||||
|
|
||||||
|
@rem uuid
|
||||||
|
echo go get github.com/nu7hatch/gouuid
|
||||||
|
go get github.com/nu7hatch/gouuid
|
||||||
|
|
||||||
|
echo build tank ...
|
||||||
|
go install tank
|
||||||
|
|
||||||
|
echo packaging
|
||||||
|
set distPath=%GOPATH%\src\tank\dist
|
||||||
|
if exist %distPath% (
|
||||||
|
echo clear %distPath%
|
||||||
|
rmdir /s/q %distPath%
|
||||||
|
)
|
||||||
|
|
||||||
|
echo create directory %distPath%
|
||||||
|
md %distPath%
|
||||||
|
|
||||||
|
echo copying tank.exe
|
||||||
|
copy %GOPATH%\bin\tank.exe %distPath%
|
||||||
|
|
||||||
|
echo copying build
|
||||||
|
xcopy %GOPATH%\src\tank\build %distPath% /e/h
|
||||||
|
|
||||||
|
cd %PRE_DIR%
|
||||||
|
|
||||||
|
echo check the dist file in %distPath%
|
||||||
|
echo finish!
|
14
build/script/shutdown.sh
Normal file
14
build/script/shutdown.sh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
EXE_PATH=$GOPATH/bin/tank
|
||||||
|
|
||||||
|
EDASPID=`ps -ef | grep "$EXE_PATH"|grep -v grep |head -n 1 | awk '{print $2}'`
|
||||||
|
if [ -z $EDASPID ];
|
||||||
|
then
|
||||||
|
echo "Cannot find $EXE_PATH."
|
||||||
|
else
|
||||||
|
kill -9 $EDASPID
|
||||||
|
echo $EXE_PATH
|
||||||
|
echo 'Shutdown successfully.'
|
||||||
|
fi
|
22
build/script/startup.sh
Normal file
22
build/script/startup.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# executable path
|
||||||
|
EXE_PATH=$GOPATH/bin/tank
|
||||||
|
|
||||||
|
# execute arguments
|
||||||
|
MysqlHost=127.0.0.1
|
||||||
|
MysqlPort=3306
|
||||||
|
MysqlSchema=tank
|
||||||
|
MysqlUserName=tank
|
||||||
|
MysqlPassword=Tank_123
|
||||||
|
|
||||||
|
AdminUsername=admin
|
||||||
|
AdminEmail=lish516@126.com
|
||||||
|
AdminPassword=123456
|
||||||
|
|
||||||
|
if [ -f "$EXE_PATH" ]; then
|
||||||
|
nohup $EXE_PATH -MysqlHost=$MysqlHost -MysqlPort=$MysqlPort -MysqlSchema=$MysqlSchema -MysqlUserName=$MysqlUserName -MysqlPassword=$MysqlPassword -AdminUsername=$AdminUsername -AdminEmail=$AdminEmail -AdminPassword=$AdminPassword >/dev/null 2>&1 &
|
||||||
|
else
|
||||||
|
echo 'Cannot find $EXE_PATH.'
|
||||||
|
exit 1
|
||||||
|
fi
|
27
build/script/update.sh
Normal file
27
build/script/update.sh
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
homePath=$GOPATH/src/tank
|
||||||
|
|
||||||
|
oldPath=$(pwd)
|
||||||
|
|
||||||
|
echo "cd homePath"
|
||||||
|
cd $homePath
|
||||||
|
|
||||||
|
echo "shutdown tank"
|
||||||
|
source $homePath/doc/script/shutdown.sh
|
||||||
|
|
||||||
|
echo "git reset"
|
||||||
|
git reset --hard HEAD
|
||||||
|
|
||||||
|
echo "git pull"
|
||||||
|
git pull
|
||||||
|
|
||||||
|
echo "go install tank"
|
||||||
|
go install tank
|
||||||
|
|
||||||
|
cd $oldPath
|
||||||
|
|
||||||
|
echo "startup tank"
|
||||||
|
source $homePath/doc/script/startup.sh
|
||||||
|
|
||||||
|
|
29
main.go
Normal file
29
main.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"tank/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
//将运行时参数装填到config中去。
|
||||||
|
rest.PrepareConfigs()
|
||||||
|
context := rest.NewContext()
|
||||||
|
defer context.Destroy()
|
||||||
|
|
||||||
|
http.Handle("/", context.Router)
|
||||||
|
|
||||||
|
dotPort := fmt.Sprintf(":%v", rest.CONFIG.ServerPort)
|
||||||
|
|
||||||
|
info := fmt.Sprintf("App started at http://localhost%v", dotPort)
|
||||||
|
rest.LogInfo(info)
|
||||||
|
|
||||||
|
err := http.ListenAndServe(dotPort, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("ListenAndServe: ", err)
|
||||||
|
}
|
||||||
|
}
|
459
rest/alien_controller.go
Normal file
459
rest/alien_controller.go
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/disintegration/imaging"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlienController struct {
|
||||||
|
BaseController
|
||||||
|
uploadTokenDao *UploadTokenDao
|
||||||
|
downloadTokenDao *DownloadTokenDao
|
||||||
|
matterDao *MatterDao
|
||||||
|
matterService *MatterService
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化方法
|
||||||
|
func (this *AlienController) Init(context *Context) {
|
||||||
|
this.BaseController.Init(context)
|
||||||
|
|
||||||
|
//手动装填本实例的Bean.
|
||||||
|
b := context.GetBean(this.uploadTokenDao)
|
||||||
|
if c, ok := b.(*UploadTokenDao); ok {
|
||||||
|
this.uploadTokenDao = c
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.downloadTokenDao)
|
||||||
|
if c, ok := b.(*DownloadTokenDao); ok {
|
||||||
|
this.downloadTokenDao = c
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.matterDao)
|
||||||
|
if c, ok := b.(*MatterDao); ok {
|
||||||
|
this.matterDao = c
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.matterService)
|
||||||
|
if c, ok := b.(*MatterService); ok {
|
||||||
|
this.matterService = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册自己的路由。
|
||||||
|
func (this *AlienController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
|
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
|
||||||
|
|
||||||
|
//每个Controller需要主动注册自己的路由。
|
||||||
|
routeMap["/api/alien/fetch/upload/token"] = this.Wrap(this.FetchUploadToken, USER_ROLE_GUEST)
|
||||||
|
routeMap["/api/alien/fetch/download/token"] = this.Wrap(this.FetchDownloadToken, USER_ROLE_GUEST)
|
||||||
|
routeMap["/api/alien/confirm"] = this.Wrap(this.Confirm, USER_ROLE_GUEST)
|
||||||
|
routeMap["/api/alien/upload"] = this.Wrap(this.Upload, USER_ROLE_GUEST)
|
||||||
|
|
||||||
|
return routeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理一些特殊的接口,比如参数包含在路径中,一般情况下,controller不将参数放在url路径中
|
||||||
|
func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) {
|
||||||
|
|
||||||
|
path := request.URL.Path
|
||||||
|
|
||||||
|
//匹配 /api/alien/download/{uuid}/{filename}
|
||||||
|
reg := regexp.MustCompile(`^/api/alien/download/([^/]+)/([^/]+)$`)
|
||||||
|
strs := reg.FindStringSubmatch(path)
|
||||||
|
if len(strs) != 3 {
|
||||||
|
return nil, false
|
||||||
|
} else {
|
||||||
|
var f = func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
this.Download(writer, request, strs[1], strs[2])
|
||||||
|
}
|
||||||
|
return f, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//直接使用邮箱和密码获取用户
|
||||||
|
func (this *AlienController) CheckRequestUser(email, password string) *User {
|
||||||
|
|
||||||
|
if email == "" {
|
||||||
|
panic("邮箱必填啦")
|
||||||
|
}
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
panic("密码必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证用户身份合法性。
|
||||||
|
user := this.userDao.FindByEmail(email)
|
||||||
|
if user == nil {
|
||||||
|
panic(`邮箱或密码错误`)
|
||||||
|
} else {
|
||||||
|
if !MatchBcrypt(password, user.Password) {
|
||||||
|
panic(`邮箱或密码错误`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
//系统中的用户x要获取一个UploadToken,用于提供给x信任的用户上传文件。
|
||||||
|
func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
//文件名。
|
||||||
|
filename := request.FormValue("filename")
|
||||||
|
if filename == "" {
|
||||||
|
panic("文件名必填")
|
||||||
|
} else if m, _ := regexp.MatchString(`[<>|*?/\\]`, filename); m {
|
||||||
|
panic(fmt.Sprintf(`【%s】不符合要求,文件名中不能包含以下特殊符号:< > | * ? / \`, filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
//什么时间后过期,默认24h
|
||||||
|
expireStr := request.FormValue("expire")
|
||||||
|
expire := 24 * 60 * 60
|
||||||
|
if expireStr != "" {
|
||||||
|
var err error
|
||||||
|
expire, err = strconv.Atoi(expireStr)
|
||||||
|
if err != nil {
|
||||||
|
panic(`过期时间不符合规范`)
|
||||||
|
}
|
||||||
|
if expire < 1 {
|
||||||
|
panic(`过期时间不符合规范`)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件公有或私有
|
||||||
|
privacyStr := request.FormValue("privacy")
|
||||||
|
var privacy bool
|
||||||
|
if privacyStr == "" {
|
||||||
|
panic(`文件公有性必填`)
|
||||||
|
} else {
|
||||||
|
if privacyStr == "true" {
|
||||||
|
privacy = true
|
||||||
|
} else if privacyStr == "false" {
|
||||||
|
privacy = false
|
||||||
|
} else {
|
||||||
|
panic(`文件公有性不符合规范`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件大小
|
||||||
|
sizeStr := request.FormValue("size")
|
||||||
|
var size int64
|
||||||
|
if sizeStr == "" {
|
||||||
|
panic(`文件大小必填`)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(`文件大小不符合规范`)
|
||||||
|
}
|
||||||
|
if size < 1 {
|
||||||
|
panic(`文件大小不符合规范`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件夹路径,以 / 开头。
|
||||||
|
dir := request.FormValue("dir")
|
||||||
|
|
||||||
|
user := this.CheckRequestUser(request.FormValue("email"), request.FormValue("password"))
|
||||||
|
dirUuid := this.matterService.GetDirUuid(user.Uuid, dir)
|
||||||
|
|
||||||
|
mm, _ := time.ParseDuration(fmt.Sprintf("%ds", expire))
|
||||||
|
uploadToken := &UploadToken{
|
||||||
|
UserUuid: user.Uuid,
|
||||||
|
FolderUuid: dirUuid,
|
||||||
|
MatterUuid: "",
|
||||||
|
ExpireTime: time.Now().Add(mm),
|
||||||
|
Filename: filename,
|
||||||
|
Privacy: privacy,
|
||||||
|
Size: size,
|
||||||
|
Ip: GetIpAddress(request),
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadToken = this.uploadTokenDao.Create(uploadToken)
|
||||||
|
|
||||||
|
return this.Success(uploadToken)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//系统中的用户x 拿着某个文件的uuid来确认是否其信任的用户已经上传好了。
|
||||||
|
func (this *AlienController) Confirm(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
matterUuid := request.FormValue("matterUuid")
|
||||||
|
if matterUuid == "" {
|
||||||
|
panic("matterUuid必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.CheckRequestUser(request.FormValue("email"), request.FormValue("password"))
|
||||||
|
|
||||||
|
matter := this.matterDao.CheckByUuid(matterUuid)
|
||||||
|
if matter.UserUuid != user.Uuid {
|
||||||
|
panic("文件不属于你")
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//系统中的用户x 信任的用户上传文件。这个接口需要支持跨域。
|
||||||
|
func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
//允许跨域请求。
|
||||||
|
this.allowCORS(writer)
|
||||||
|
if request.Method == "OPTIONS" {
|
||||||
|
return this.Success("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadTokenUuid := request.FormValue("uploadTokenUuid")
|
||||||
|
if uploadTokenUuid == "" {
|
||||||
|
panic("uploadTokenUuid必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadToken := this.uploadTokenDao.FindByUuid(uploadTokenUuid)
|
||||||
|
if uploadToken == nil {
|
||||||
|
panic("uploadTokenUuid无效")
|
||||||
|
}
|
||||||
|
|
||||||
|
if uploadToken.ExpireTime.Before(time.Now()) {
|
||||||
|
panic("uploadToken已失效")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(uploadToken.UserUuid)
|
||||||
|
|
||||||
|
request.ParseMultipartForm(32 << 20)
|
||||||
|
file, handler, err := request.FormFile("file")
|
||||||
|
this.PanicError(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if handler.Filename != uploadToken.Filename {
|
||||||
|
panic("文件名称不正确")
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler.Size != uploadToken.Size {
|
||||||
|
panic("文件大小不正确")
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := this.matterService.Upload(file, user, uploadToken.FolderUuid, uploadToken.Filename, uploadToken.Privacy)
|
||||||
|
|
||||||
|
//更新这个uploadToken的信息.
|
||||||
|
uploadToken.ExpireTime = time.Now()
|
||||||
|
this.uploadTokenDao.Save(uploadToken)
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//系统中的用户x要获取一个DownloadToken,用于提供给x信任的用户下载文件。
|
||||||
|
func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
matterUuid := request.FormValue("matterUuid")
|
||||||
|
if matterUuid == "" {
|
||||||
|
panic("matterUuid必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.CheckRequestUser(request.FormValue("email"), request.FormValue("password"))
|
||||||
|
|
||||||
|
matter := this.matterDao.CheckByUuid(matterUuid)
|
||||||
|
if matter.UserUuid != user.Uuid {
|
||||||
|
panic("文件不属于你")
|
||||||
|
}
|
||||||
|
if matter.Dir {
|
||||||
|
panic("不支持下载文件夹")
|
||||||
|
}
|
||||||
|
|
||||||
|
//什么时间后过期,默认24h
|
||||||
|
expireStr := request.FormValue("expire")
|
||||||
|
expire := 24 * 60 * 60
|
||||||
|
if expireStr != "" {
|
||||||
|
var err error
|
||||||
|
expire, err = strconv.Atoi(expireStr)
|
||||||
|
if err != nil {
|
||||||
|
panic(`过期时间不符合规范`)
|
||||||
|
}
|
||||||
|
if expire < 1 {
|
||||||
|
panic(`过期时间不符合规范`)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mm, _ := time.ParseDuration(fmt.Sprintf("%ds", expire))
|
||||||
|
downloadToken := &DownloadToken{
|
||||||
|
UserUuid: user.Uuid,
|
||||||
|
MatterUuid: matterUuid,
|
||||||
|
ExpireTime: time.Now().Add(mm),
|
||||||
|
Ip: GetIpAddress(request),
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadToken = this.downloadTokenDao.Create(downloadToken)
|
||||||
|
|
||||||
|
return this.Success(downloadToken)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载一个文件。既可以使用登录的方式下载,也可以使用授权的方式下载。
|
||||||
|
func (this *AlienController) Download(writer http.ResponseWriter, request *http.Request, uuid string, filename string) {
|
||||||
|
|
||||||
|
matter := this.matterDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
//判断是否是文件夹
|
||||||
|
if matter.Dir {
|
||||||
|
panic("暂不支持下载文件夹")
|
||||||
|
}
|
||||||
|
|
||||||
|
if matter.Name != filename {
|
||||||
|
panic("文件信息错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证用户的权限问题。
|
||||||
|
//文件如果是私有的才需要权限
|
||||||
|
if matter.Privacy {
|
||||||
|
|
||||||
|
//1.如果带有downloadTokenUuid那么就按照token的信息去获取。
|
||||||
|
downloadTokenUuid := request.FormValue("downloadTokenUuid")
|
||||||
|
if downloadTokenUuid != "" {
|
||||||
|
downloadToken := this.downloadTokenDao.CheckByUuid(downloadTokenUuid)
|
||||||
|
if downloadToken.ExpireTime.Before(time.Now()) {
|
||||||
|
panic("downloadToken已失效")
|
||||||
|
}
|
||||||
|
|
||||||
|
if downloadToken.MatterUuid != uuid {
|
||||||
|
panic("token和文件信息不一致")
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenUser := this.userDao.CheckByUuid(downloadToken.UserUuid)
|
||||||
|
if matter.UserUuid != tokenUser.Uuid {
|
||||||
|
panic(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载之后立即过期掉。
|
||||||
|
downloadToken.ExpireTime = time.Now()
|
||||||
|
this.downloadTokenDao.Save(downloadToken)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//判断文件的所属人是否正确
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid {
|
||||||
|
panic(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diskFile, err := os.Open(GetFilePath() + matter.Path)
|
||||||
|
this.PanicError(err)
|
||||||
|
defer diskFile.Close()
|
||||||
|
// 防止中文乱码
|
||||||
|
fileName := url.QueryEscape(matter.Name)
|
||||||
|
writer.Header().Set("Content-Type", GetMimeType(fileName))
|
||||||
|
|
||||||
|
//如果是图片或者文本就直接打开。
|
||||||
|
mimeType := GetMimeType(matter.Name)
|
||||||
|
if strings.Index(mimeType, "image") != 0 && strings.Index(mimeType, "text") != 0 {
|
||||||
|
writer.Header().Set("content-disposition", "attachment; filename=\""+fileName+"\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
//对图片做缩放处理。
|
||||||
|
imageProcess := request.FormValue("imageProcess")
|
||||||
|
if imageProcess == "resize" {
|
||||||
|
|
||||||
|
//当前的文件是否是图片,只有图片才能处理。
|
||||||
|
extension := GetExtension(matter.Name)
|
||||||
|
formats := map[string]imaging.Format{
|
||||||
|
".jpg": imaging.JPEG,
|
||||||
|
".jpeg": imaging.JPEG,
|
||||||
|
".png": imaging.PNG,
|
||||||
|
".tif": imaging.TIFF,
|
||||||
|
".tiff": imaging.TIFF,
|
||||||
|
".bmp": imaging.BMP,
|
||||||
|
".gif": imaging.GIF,
|
||||||
|
}
|
||||||
|
|
||||||
|
format, ok := formats[extension]
|
||||||
|
if !ok {
|
||||||
|
panic("该图片格式不支持处理")
|
||||||
|
}
|
||||||
|
|
||||||
|
imageResizeM := request.FormValue("imageResizeM")
|
||||||
|
if imageResizeM == "" {
|
||||||
|
imageResizeM = "fit"
|
||||||
|
} else if imageResizeM != "fit" && imageResizeM != "fill" && imageResizeM != "fixed" {
|
||||||
|
panic("imageResizeM参数错误")
|
||||||
|
}
|
||||||
|
imageResizeWStr := request.FormValue("imageResizeW")
|
||||||
|
var imageResizeW int
|
||||||
|
if imageResizeWStr != "" {
|
||||||
|
imageResizeW, err = strconv.Atoi(imageResizeWStr)
|
||||||
|
this.PanicError(err)
|
||||||
|
if imageResizeW < 1 || imageResizeW > 4096 {
|
||||||
|
panic("缩放尺寸不能超过4096")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imageResizeHStr := request.FormValue("imageResizeH")
|
||||||
|
var imageResizeH int
|
||||||
|
if imageResizeHStr != "" {
|
||||||
|
imageResizeH, err = strconv.Atoi(imageResizeHStr)
|
||||||
|
this.PanicError(err)
|
||||||
|
if imageResizeH < 1 || imageResizeH > 4096 {
|
||||||
|
panic("缩放尺寸不能超过4096")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//单边缩略
|
||||||
|
if imageResizeM == "fit" {
|
||||||
|
//将图缩略成宽度为100,高度按比例处理。
|
||||||
|
if imageResizeW > 0 {
|
||||||
|
src, err := imaging.Decode(diskFile)
|
||||||
|
this.PanicError(err)
|
||||||
|
dst := imaging.Resize(src, imageResizeW, 0, imaging.Lanczos)
|
||||||
|
|
||||||
|
err = imaging.Encode(writer, dst, format)
|
||||||
|
this.PanicError(err)
|
||||||
|
} else if imageResizeH > 0 {
|
||||||
|
//将图缩略成高度为100,宽度按比例处理。
|
||||||
|
src, err := imaging.Decode(diskFile)
|
||||||
|
this.PanicError(err)
|
||||||
|
dst := imaging.Resize(src, 0, imageResizeH, imaging.Lanczos)
|
||||||
|
|
||||||
|
err = imaging.Encode(writer, dst, format)
|
||||||
|
this.PanicError(err)
|
||||||
|
} else {
|
||||||
|
panic("单边缩略必须指定imageResizeW或imageResizeH")
|
||||||
|
}
|
||||||
|
} else if imageResizeM == "fill" {
|
||||||
|
//固定宽高,自动裁剪
|
||||||
|
if imageResizeW > 0 && imageResizeH > 0 {
|
||||||
|
src, err := imaging.Decode(diskFile)
|
||||||
|
this.PanicError(err)
|
||||||
|
dst := imaging.Fill(src, imageResizeW, imageResizeH, imaging.Center, imaging.Lanczos)
|
||||||
|
err = imaging.Encode(writer, dst, format)
|
||||||
|
this.PanicError(err)
|
||||||
|
} else {
|
||||||
|
panic("固定宽高,自动裁剪 必须同时指定imageResizeW和imageResizeH")
|
||||||
|
}
|
||||||
|
} else if imageResizeM == "fixed" {
|
||||||
|
//强制宽高缩略
|
||||||
|
if imageResizeW > 0 && imageResizeH > 0 {
|
||||||
|
src, err := imaging.Decode(diskFile)
|
||||||
|
this.PanicError(err)
|
||||||
|
dst := imaging.Resize(src, imageResizeW, imageResizeH, imaging.Lanczos)
|
||||||
|
|
||||||
|
err = imaging.Encode(writer, dst, format)
|
||||||
|
this.PanicError(err)
|
||||||
|
} else {
|
||||||
|
panic("强制宽高缩略必须同时指定imageResizeW和imageResizeH")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_, err = io.Copy(writer, diskFile)
|
||||||
|
this.PanicError(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
169
rest/base_controller.go
Normal file
169
rest/base_controller.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/json-iterator/go"
|
||||||
|
"go/types"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IController interface {
|
||||||
|
IBean
|
||||||
|
//注册自己固定的路由。
|
||||||
|
RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request)
|
||||||
|
//处理一些特殊的路由。
|
||||||
|
HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool)
|
||||||
|
}
|
||||||
|
type BaseController struct {
|
||||||
|
Bean
|
||||||
|
userDao *UserDao
|
||||||
|
sessionDao *SessionDao
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BaseController) Init(context *Context) {
|
||||||
|
|
||||||
|
this.Bean.Init(context)
|
||||||
|
|
||||||
|
//手动装填本实例的Bean.
|
||||||
|
b := context.GetBean(this.userDao)
|
||||||
|
if b, ok := b.(*UserDao); ok {
|
||||||
|
this.userDao = b
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.sessionDao)
|
||||||
|
if b, ok := b.(*SessionDao); ok {
|
||||||
|
this.sessionDao = b
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册自己的路由。
|
||||||
|
func (this *BaseController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
//每个Controller需要主动注册自己的路由。
|
||||||
|
return make(map[string]func(writer http.ResponseWriter, request *http.Request))
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理一些特殊的接口,比如参数包含在路径中,一般情况下,controller不将参数放在url路径中
|
||||||
|
func (this *BaseController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
//需要进行登录验证的wrap包装
|
||||||
|
func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *http.Request) *WebResult, role string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
return func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
|
//writer和request赋值给自己。
|
||||||
|
|
||||||
|
var webResult *WebResult = nil
|
||||||
|
|
||||||
|
//只有游客接口不需要登录
|
||||||
|
if role != USER_ROLE_GUEST {
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if role == USER_ROLE_ADMINISTRATOR && user.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
webResult = ConstWebResult(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
} else {
|
||||||
|
webResult = f(writer, request)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webResult = f(writer, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
//输出的是json格式
|
||||||
|
if webResult != nil {
|
||||||
|
//返回的内容申明是json,utf-8
|
||||||
|
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
|
//用json的方式输出返回值。
|
||||||
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
b, _ := json.Marshal(webResult)
|
||||||
|
|
||||||
|
if webResult.Code == RESULT_CODE_OK {
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
} else {
|
||||||
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(writer, string(b))
|
||||||
|
} else {
|
||||||
|
//输出的内容是二进制的。
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回成功的结果。
|
||||||
|
func (this *BaseController) Success(data interface{}) *WebResult {
|
||||||
|
var webResult *WebResult = nil
|
||||||
|
if value, ok := data.(string); ok {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_OK, Msg: value}
|
||||||
|
} else if value, ok := data.(*WebResult); ok {
|
||||||
|
webResult = value
|
||||||
|
} else if _, ok := data.(types.Nil); ok {
|
||||||
|
webResult = ConstWebResult(RESULT_CODE_OK)
|
||||||
|
} else {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_OK, Data: data}
|
||||||
|
}
|
||||||
|
return webResult
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回错误的结果。
|
||||||
|
func (this *BaseController) Error(err interface{}) *WebResult {
|
||||||
|
var webResult *WebResult = nil
|
||||||
|
if value, ok := err.(string); ok {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: value}
|
||||||
|
} else if value, ok := err.(int); ok {
|
||||||
|
webResult = ConstWebResult(value)
|
||||||
|
} else if value, ok := err.(*WebResult); ok {
|
||||||
|
webResult = value
|
||||||
|
} else if value, ok := err.(error); ok {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: value.Error()}
|
||||||
|
} else {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: "服务器未知错误"}
|
||||||
|
}
|
||||||
|
return webResult
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BaseController) checkLogin(writer http.ResponseWriter, request *http.Request) (*Session, *User) {
|
||||||
|
|
||||||
|
//验证用户是否已经登录。
|
||||||
|
sessionCookie, err := request.Cookie(COOKIE_AUTH_KEY)
|
||||||
|
if err != nil {
|
||||||
|
panic(ConstWebResult(RESULT_CODE_LOGIN))
|
||||||
|
}
|
||||||
|
|
||||||
|
session := this.sessionDao.FindByUuid(sessionCookie.Value)
|
||||||
|
if session == nil {
|
||||||
|
panic(ConstWebResult(RESULT_CODE_LOGIN))
|
||||||
|
} else {
|
||||||
|
if session.ExpireTime.Before(time.Now()) {
|
||||||
|
panic(ConstWebResult(RESULT_CODE_LOGIN_EXPIRED))
|
||||||
|
} else {
|
||||||
|
|
||||||
|
user := this.userDao.FindByUuid(session.UserUuid)
|
||||||
|
if user == nil {
|
||||||
|
panic(ConstWebResult(RESULT_CODE_LOGIN_INVALID))
|
||||||
|
} else {
|
||||||
|
return session, user
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BaseController) checkUser(writer http.ResponseWriter, request *http.Request) *User {
|
||||||
|
|
||||||
|
_, user := this.checkLogin(writer, request)
|
||||||
|
return user
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//允许跨域请求
|
||||||
|
func (this *BaseController) allowCORS(writer http.ResponseWriter) {
|
||||||
|
writer.Header().Add("Access-Control-Allow-Origin", "*")
|
||||||
|
writer.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||||
|
writer.Header().Add("Access-Control-Max-Age", "3600")
|
||||||
|
}
|
12
rest/base_dao.go
Normal file
12
rest/base_dao.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BaseDao struct {
|
||||||
|
Bean
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
48
rest/base_model.go
Normal file
48
rest/base_model.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
"reflect"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Time time.Time
|
||||||
|
|
||||||
|
type Base struct {
|
||||||
|
Uuid string `gorm:"primary_key" json:"uuid"`
|
||||||
|
Sort int64 `json:"sort"`
|
||||||
|
ModifyTime time.Time `json:"modifyTime"`
|
||||||
|
CreateTime time.Time `json:"createTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//将 Struct 转换成map[string]interface{}类型
|
||||||
|
func (this *Base) Map() map[string]interface{} {
|
||||||
|
t := reflect.TypeOf(this)
|
||||||
|
v := reflect.ValueOf(this)
|
||||||
|
|
||||||
|
var data = make(map[string]interface{})
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
data[t.Field(i).Name] = v.Field(i).Interface()
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
//分页类
|
||||||
|
type Pager struct {
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
TotalItems int `json:"totalItems"`
|
||||||
|
TotalPages int `json:"totalPages"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPager(page int, pageSize int, totalItems int, data interface{}) *Pager {
|
||||||
|
|
||||||
|
return &Pager{
|
||||||
|
Page: page,
|
||||||
|
PageSize: pageSize,
|
||||||
|
TotalItems: totalItems,
|
||||||
|
TotalPages: int(math.Ceil(float64(totalItems) / float64(pageSize))),
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
21
rest/bean.go
Normal file
21
rest/bean.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
type IBean interface {
|
||||||
|
Init(context *Context)
|
||||||
|
PanicError(err error);
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bean struct {
|
||||||
|
context *Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Bean) Init(context *Context) {
|
||||||
|
this.context = context
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理错误的统一方法
|
||||||
|
func (this *Bean) PanicError(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
222
rest/config.go
Normal file
222
rest/config.go
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/json-iterator/go"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
"io/ioutil"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//用户身份的cookie字段名
|
||||||
|
COOKIE_AUTH_KEY = "_ak"
|
||||||
|
|
||||||
|
//数据库表前缀 tank100表示当前应用版本是tank:1.0.x版,数据库结构发生变化必然是中型升级
|
||||||
|
TABLE_PREFIX = "tank10_"
|
||||||
|
|
||||||
|
//当前版本
|
||||||
|
VERSION = "1.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CONFIG = &Config{
|
||||||
|
//以下内容是默认配置项。
|
||||||
|
|
||||||
|
//默认监听端口号
|
||||||
|
ServerPort: 9090,
|
||||||
|
//将日志输出到控制台。
|
||||||
|
LogToConsole: true,
|
||||||
|
//mysql相关配置。
|
||||||
|
//数据库端口
|
||||||
|
MysqlPort: 3306,
|
||||||
|
//数据库Host
|
||||||
|
MysqlHost: "127.0.0.1",
|
||||||
|
//数据库名字
|
||||||
|
MysqlSchema: "tank",
|
||||||
|
//用户名
|
||||||
|
MysqlUserName: "tank",
|
||||||
|
//密码
|
||||||
|
MysqlPassword: "tank123",
|
||||||
|
//数据库连接信息。
|
||||||
|
MysqlUrl: "%MysqlUserName:%MysqlPassword@tcp(%MysqlHost:%MysqlPort)/%MysqlSchema?charset=utf8&parseTime=True&loc=Local",
|
||||||
|
//超级管理员用户名,只能包含英文和数字
|
||||||
|
AdminUsername: "admin",
|
||||||
|
//超级管理员邮箱
|
||||||
|
AdminEmail: "admin@tank.eyeblue.cn",
|
||||||
|
//超级管理员密码
|
||||||
|
AdminPassword: "123456",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//依赖外部定义的变量。
|
||||||
|
type Config struct {
|
||||||
|
//默认监听端口号
|
||||||
|
ServerPort int
|
||||||
|
|
||||||
|
//将日志输出到控制台。
|
||||||
|
LogToConsole bool
|
||||||
|
|
||||||
|
//mysql相关配置。
|
||||||
|
//数据库端口
|
||||||
|
MysqlPort int
|
||||||
|
//数据库Host
|
||||||
|
MysqlHost string
|
||||||
|
//数据库名字
|
||||||
|
MysqlSchema string
|
||||||
|
//用户名
|
||||||
|
MysqlUserName string
|
||||||
|
//密码
|
||||||
|
MysqlPassword string
|
||||||
|
//数据库连接信息。
|
||||||
|
MysqlUrl string
|
||||||
|
|
||||||
|
//超级管理员用户名,只能包含英文和数字
|
||||||
|
AdminUsername string
|
||||||
|
//超级管理员邮箱
|
||||||
|
AdminEmail string
|
||||||
|
//超级管理员密码
|
||||||
|
AdminPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证配置文件的正确性。
|
||||||
|
func (this *Config) validate() {
|
||||||
|
|
||||||
|
if this.ServerPort == 0 {
|
||||||
|
LogPanic("ServerPort 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.MysqlUserName == "" {
|
||||||
|
LogPanic("MysqlUserName 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.MysqlPassword == "" {
|
||||||
|
LogPanic("MysqlPassword 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.MysqlHost == "" {
|
||||||
|
LogPanic("MysqlHost 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.MysqlPort == 0 {
|
||||||
|
LogPanic("MysqlPort 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.MysqlSchema == "" {
|
||||||
|
LogPanic("MysqlSchema 未配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.MysqlUrl = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", this.MysqlUserName, this.MysqlPassword, this.MysqlHost, this.MysqlPort, this.MysqlSchema)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//init方法只要这个包被引入了就一定会执行。
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
//json中需要去特殊处理时间。
|
||||||
|
jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||||||
|
//如果使用time.UTC,那么时间会相差8小时
|
||||||
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.Local)
|
||||||
|
if err != nil {
|
||||||
|
iter.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*((*time.Time)(ptr)) = t
|
||||||
|
})
|
||||||
|
|
||||||
|
jsoniter.RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||||
|
t := *((*time.Time)(ptr))
|
||||||
|
//如果使用time.UTC,那么时间会相差8小时
|
||||||
|
stream.WriteString(t.Local().Format("2006-01-02 15:04:05"))
|
||||||
|
}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//从conf/tank.json中获取变量。
|
||||||
|
|
||||||
|
//从flag中或者conf/tank.json中装填变量
|
||||||
|
func PrepareConfigs() {
|
||||||
|
|
||||||
|
//读取配置文件
|
||||||
|
filePath := GetConfPath() + "/tank.json"
|
||||||
|
content, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
LogWarning(fmt.Sprintf("无法找到配置文件:%s,%v", filePath, err))
|
||||||
|
} else {
|
||||||
|
// 用 json.Unmarshal
|
||||||
|
err := json.Unmarshal(content, CONFIG)
|
||||||
|
if err != nil {
|
||||||
|
LogPanic("配置文件格式错误!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//从运行时参数中读取,运行时参数具有更高优先级。
|
||||||
|
//系统端口号
|
||||||
|
ServerPortPtr := flag.Int("ServerPort", CONFIG.ServerPort, "server port")
|
||||||
|
|
||||||
|
//系统端口号
|
||||||
|
LogToConsolePtr := flag.Bool("LogToConsole", CONFIG.LogToConsole, "write log to console. for debug.")
|
||||||
|
|
||||||
|
//mysql相关配置。
|
||||||
|
MysqlPortPtr := flag.Int("MysqlPort", CONFIG.MysqlPort, "mysql port")
|
||||||
|
MysqlHostPtr := flag.String("MysqlHost", CONFIG.MysqlHost, "mysql host")
|
||||||
|
MysqlSchemaPtr := flag.String("MysqlSchema", CONFIG.MysqlSchema, "mysql schema")
|
||||||
|
MysqlUserNamePtr := flag.String("MysqlUserName", CONFIG.MysqlUserName, "mysql username")
|
||||||
|
MysqlPasswordPtr := flag.String("MysqlPassword", CONFIG.MysqlPassword, "mysql password")
|
||||||
|
|
||||||
|
//超级管理员信息
|
||||||
|
AdminUsernamePtr := flag.String("AdminUsername", CONFIG.AdminUsername, "administrator username")
|
||||||
|
AdminEmailPtr := flag.String("AdminEmail", CONFIG.AdminEmail, "administrator email")
|
||||||
|
AdminPasswordPtr := flag.String("AdminPassword", CONFIG.AdminPassword, "administrator password")
|
||||||
|
|
||||||
|
//flag.Parse()方法必须要在使用之前调用。
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *ServerPortPtr != CONFIG.ServerPort {
|
||||||
|
CONFIG.ServerPort = *ServerPortPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *LogToConsolePtr != CONFIG.LogToConsole {
|
||||||
|
CONFIG.LogToConsole = *LogToConsolePtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *MysqlPortPtr != CONFIG.MysqlPort {
|
||||||
|
CONFIG.MysqlPort = *MysqlPortPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *MysqlHostPtr != CONFIG.MysqlHost {
|
||||||
|
CONFIG.MysqlHost = *MysqlHostPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *MysqlSchemaPtr != CONFIG.MysqlSchema {
|
||||||
|
CONFIG.MysqlSchema = *MysqlSchemaPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *MysqlUserNamePtr != CONFIG.MysqlUserName {
|
||||||
|
CONFIG.MysqlUserName = *MysqlUserNamePtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *MysqlPasswordPtr != CONFIG.MysqlPassword {
|
||||||
|
CONFIG.MysqlPassword = *MysqlPasswordPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *AdminUsernamePtr != CONFIG.AdminUsername {
|
||||||
|
CONFIG.AdminUsername = *AdminUsernamePtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *AdminEmailPtr != CONFIG.AdminEmail {
|
||||||
|
CONFIG.AdminEmail = *AdminEmailPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if *AdminPasswordPtr != CONFIG.AdminPassword {
|
||||||
|
CONFIG.AdminPassword = *AdminPasswordPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证配置项的正确性
|
||||||
|
CONFIG.validate()
|
||||||
|
|
||||||
|
//安装程序开始导入初始表和初始数据。
|
||||||
|
InstallDatabase()
|
||||||
|
|
||||||
|
}
|
146
rest/context.go
Normal file
146
rest/context.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
//上下文,管理数据库连接,管理所有路由请求,管理所有的单例component.
|
||||||
|
type Context struct {
|
||||||
|
//数据库连接
|
||||||
|
DB *gorm.DB
|
||||||
|
//处理所有路由请求
|
||||||
|
Router *Router
|
||||||
|
//各类的Bean Map。这里面是包含ControllerMap中所有元素
|
||||||
|
BeanMap map[string]IBean
|
||||||
|
//只包含了Controller的map
|
||||||
|
ControllerMap map[string]IController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Context) OpenDb() {
|
||||||
|
|
||||||
|
var err error = nil
|
||||||
|
this.DB, err = gorm.Open("mysql", CONFIG.MysqlUrl)
|
||||||
|
|
||||||
|
//是否打开sql日志
|
||||||
|
this.DB.LogMode(false)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to connect mysql database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Context) CloseDb() {
|
||||||
|
|
||||||
|
if this.DB != nil {
|
||||||
|
this.DB.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//构造方法
|
||||||
|
func NewContext() *Context {
|
||||||
|
|
||||||
|
context := &Context{}
|
||||||
|
|
||||||
|
//处理数据库连接的开关。
|
||||||
|
context.OpenDb()
|
||||||
|
|
||||||
|
//初始化Map
|
||||||
|
context.BeanMap = make(map[string]IBean)
|
||||||
|
context.ControllerMap = make(map[string]IController)
|
||||||
|
|
||||||
|
//注册各类Beans.在这个方法里面顺便把Controller装入ControllerMap中去。
|
||||||
|
context.registerBeans()
|
||||||
|
|
||||||
|
//初始化每个bean.
|
||||||
|
context.initBeans()
|
||||||
|
|
||||||
|
//初始化Router. 这个方法要在Bean注册好了之后才能。
|
||||||
|
context.Router = NewRouter(context)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册一个Bean
|
||||||
|
func (this *Context) registerBean(bean IBean) {
|
||||||
|
|
||||||
|
typeOf := reflect.TypeOf(bean)
|
||||||
|
typeName := typeOf.String()
|
||||||
|
|
||||||
|
if element, ok := bean.(IBean); ok {
|
||||||
|
|
||||||
|
err := fmt.Sprintf("【%s】已经被注册了,跳过。", typeName)
|
||||||
|
if _, ok := this.BeanMap[typeName]; ok {
|
||||||
|
LogError(fmt.Sprintf(err))
|
||||||
|
} else {
|
||||||
|
this.BeanMap[typeName] = element
|
||||||
|
|
||||||
|
//看看是不是controller类型,如果是,那么单独放在ControllerMap中。
|
||||||
|
if controller, ok1 := bean.(IController); ok1 {
|
||||||
|
this.ControllerMap[typeName] = controller
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
err := fmt.Sprintf("注册的【%s】不是Bean类型。", typeName)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册各个Beans
|
||||||
|
func (this *Context) registerBeans() {
|
||||||
|
|
||||||
|
//alien
|
||||||
|
this.registerBean(new(AlienController))
|
||||||
|
|
||||||
|
//downloadToken
|
||||||
|
this.registerBean(new(DownloadTokenDao))
|
||||||
|
|
||||||
|
//matter
|
||||||
|
this.registerBean(new(MatterController))
|
||||||
|
this.registerBean(new(MatterDao))
|
||||||
|
this.registerBean(new(MatterService))
|
||||||
|
|
||||||
|
//session
|
||||||
|
this.registerBean(new(SessionDao))
|
||||||
|
|
||||||
|
//uploadToken
|
||||||
|
this.registerBean(new(UploadTokenDao))
|
||||||
|
|
||||||
|
//user
|
||||||
|
this.registerBean(new(UserController))
|
||||||
|
this.registerBean(new(UserDao))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//从Map中获取某个Bean.
|
||||||
|
func (this *Context) GetBean(bean IBean) IBean {
|
||||||
|
|
||||||
|
typeOf := reflect.TypeOf(bean)
|
||||||
|
typeName := typeOf.String()
|
||||||
|
|
||||||
|
if val, ok := this.BeanMap[typeName]; ok {
|
||||||
|
return val
|
||||||
|
} else {
|
||||||
|
err := fmt.Sprintf("【%s】没有注册。", typeName)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化每个Bean
|
||||||
|
func (this *Context) initBeans() {
|
||||||
|
|
||||||
|
for _, bean := range this.BeanMap {
|
||||||
|
bean.Init(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//销毁的方法
|
||||||
|
func (this *Context) Destroy() {
|
||||||
|
this.CloseDb()
|
||||||
|
|
||||||
|
}
|
60
rest/download_token_dao.go
Normal file
60
rest/download_token_dao.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DownloadTokenDao struct {
|
||||||
|
BaseDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询
|
||||||
|
func (this *DownloadTokenDao) FindByUuid(uuid string) *DownloadToken {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var downloadToken = &DownloadToken{}
|
||||||
|
db := this.context.DB.Where(&DownloadToken{Base: Base{Uuid: uuid}}).First(downloadToken)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return downloadToken
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询
|
||||||
|
func (this *DownloadTokenDao) CheckByUuid(uuid string) *DownloadToken {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var downloadToken = &DownloadToken{}
|
||||||
|
db := this.context.DB.Where(&DownloadToken{Base: Base{Uuid: uuid}}).First(downloadToken)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return downloadToken
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建一个session并且持久化到数据库中。
|
||||||
|
func (this *DownloadTokenDao) Create(downloadToken *DownloadToken) *DownloadToken {
|
||||||
|
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
downloadToken.Uuid = string(timeUUID.String())
|
||||||
|
|
||||||
|
downloadToken.CreateTime = time.Now()
|
||||||
|
downloadToken.ModifyTime = time.Now()
|
||||||
|
|
||||||
|
db := this.context.DB.Create(downloadToken)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return downloadToken
|
||||||
|
}
|
||||||
|
|
||||||
|
//修改一个downloadToken
|
||||||
|
func (this *DownloadTokenDao) Save(downloadToken *DownloadToken) *DownloadToken {
|
||||||
|
|
||||||
|
downloadToken.ModifyTime = time.Now()
|
||||||
|
db := this.context.DB.Save(downloadToken)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return downloadToken
|
||||||
|
}
|
17
rest/download_token_model.go
Normal file
17
rest/download_token_model.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DownloadToken struct {
|
||||||
|
Base
|
||||||
|
UserUuid string `json:"userUuid"`
|
||||||
|
MatterUuid string `json:"matterUuid"`
|
||||||
|
ExpireTime time.Time `json:"expireTime"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DownloadToken) TableName() string {
|
||||||
|
return TABLE_PREFIX + "download_token"
|
||||||
|
}
|
117
rest/install.go
Normal file
117
rest/install.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
//首次运行的时候,将自动安装数据库等内容。
|
||||||
|
func InstallDatabase() {
|
||||||
|
|
||||||
|
db, err := gorm.Open("mysql", CONFIG.MysqlUrl)
|
||||||
|
if err != nil {
|
||||||
|
LogPanic(fmt.Sprintf("无法打开%s", CONFIG.MysqlUrl))
|
||||||
|
}
|
||||||
|
if db != nil {
|
||||||
|
defer db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
//这个方法只会简单查看表是否存在,不会去比照每个字段的。因此如果用户自己修改表结构将会出现不可预测的错误。
|
||||||
|
var hasTable = true
|
||||||
|
downloadToken := &DownloadToken{}
|
||||||
|
hasTable = db.HasTable(downloadToken)
|
||||||
|
if !hasTable {
|
||||||
|
|
||||||
|
createDownloadToken := "CREATE TABLE `tank10_download_token` (`uuid` char(36) NOT NULL,`user_uuid` char(36) DEFAULT NULL COMMENT '用户uuid',`matter_uuid` char(36) DEFAULT NULL COMMENT '文件标识',`expire_time` timestamp NULL DEFAULT NULL COMMENT '授权访问的次数',`ip` varchar(45) DEFAULT NULL COMMENT '消费者的ip',`sort` bigint(20) DEFAULT NULL,`modify_time` timestamp NULL DEFAULT NULL,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`uuid`),UNIQUE KEY `id_UNIQUE` (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='下载的token表';"
|
||||||
|
db = db.Exec(createDownloadToken)
|
||||||
|
if db.Error != nil {
|
||||||
|
LogPanic(db.Error)
|
||||||
|
}
|
||||||
|
LogInfo("创建DownloadToken表")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := &Matter{}
|
||||||
|
hasTable = db.HasTable(matter)
|
||||||
|
if !hasTable {
|
||||||
|
createMatter := "CREATE TABLE `tank10_matter` (`uuid` char(36) NOT NULL,`puuid` varchar(45) DEFAULT NULL COMMENT '上一级的uuid',`user_uuid` char(36) DEFAULT NULL COMMENT '上传的用户id',`dir` tinyint(1) DEFAULT NULL COMMENT '是否是文件夹',`name` varchar(255) DEFAULT NULL COMMENT '文件名称',`md5` varchar(45) DEFAULT NULL COMMENT '文件的md5值',`size` bigint(20) DEFAULT '0' COMMENT '文件大小',`privacy` tinyint(1) DEFAULT '0' COMMENT '文件是否是公有的',`path` varchar(255) DEFAULT NULL,`sort` bigint(20) DEFAULT NULL,`modify_time` timestamp NULL DEFAULT NULL,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`uuid`),UNIQUE KEY `id_UNIQUE` (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='file表';"
|
||||||
|
db = db.Exec(createMatter)
|
||||||
|
if db.Error != nil {
|
||||||
|
LogPanic(db.Error)
|
||||||
|
}
|
||||||
|
LogInfo("创建Matter表")
|
||||||
|
|
||||||
|
}
|
||||||
|
session := &Session{}
|
||||||
|
hasTable = db.HasTable(session)
|
||||||
|
if !hasTable {
|
||||||
|
|
||||||
|
createSession := "CREATE TABLE `tank10_session` (`uuid` char(36) NOT NULL,`authentication` char(36) DEFAULT NULL COMMENT '认证身份,存放在cookie中',`user_uuid` char(36) DEFAULT NULL COMMENT '用户uuid',`ip` varchar(45) DEFAULT NULL COMMENT '用户的ip地址',`expire_time` timestamp NULL DEFAULT NULL,`sort` bigint(20) DEFAULT NULL,`modify_time` timestamp NULL DEFAULT NULL,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`uuid`),UNIQUE KEY `id_UNIQUE` (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='session表';"
|
||||||
|
db = db.Exec(createSession)
|
||||||
|
if db.Error != nil {
|
||||||
|
LogPanic(db.Error)
|
||||||
|
}
|
||||||
|
LogInfo("创建Session表")
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadToken := &UploadToken{}
|
||||||
|
hasTable = db.HasTable(uploadToken)
|
||||||
|
if !hasTable {
|
||||||
|
|
||||||
|
createUploadToken := "CREATE TABLE `tank10_upload_token` (`uuid` char(36) NOT NULL,`user_uuid` char(36) DEFAULT NULL COMMENT '用户uuid',`folder_uuid` char(36) DEFAULT NULL,`matter_uuid` char(36) DEFAULT NULL,`filename` varchar(255) DEFAULT NULL COMMENT '文件后缀名的过滤,可以只允许用户上传特定格式的文件。',`privacy` tinyint(1) DEFAULT '1',`size` bigint(20) DEFAULT '0',`expire_time` timestamp NULL DEFAULT NULL,`ip` varchar(45) DEFAULT NULL COMMENT '消费者的ip',`sort` bigint(20) DEFAULT NULL,`modify_time` timestamp NULL DEFAULT NULL,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`uuid`),UNIQUE KEY `id_UNIQUE` (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='上传的token表';"
|
||||||
|
db = db.Exec(createUploadToken)
|
||||||
|
if db.Error != nil {
|
||||||
|
LogPanic(db.Error)
|
||||||
|
}
|
||||||
|
LogInfo("创建UploadToken表")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &User{}
|
||||||
|
hasTable = db.HasTable(user)
|
||||||
|
if !hasTable {
|
||||||
|
|
||||||
|
//验证超级管理员的信息
|
||||||
|
if m, _ := regexp.MatchString(`^[0-9a-zA-Z_]+$`, CONFIG.AdminUsername); !m {
|
||||||
|
LogPanic(`超级管理员用户名必填,且只能包含字母,数字和'_''`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(CONFIG.AdminPassword) < 6 {
|
||||||
|
LogPanic(`超级管理员密码长度至少为6位`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if CONFIG.AdminEmail == "" {
|
||||||
|
LogPanic("超级管理员邮箱必填!")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createUser := "CREATE TABLE `tank10_user` (`uuid` char(36) NOT NULL,`role` varchar(45) DEFAULT 'USER',`username` varchar(255) DEFAULT NULL COMMENT '昵称',`password` varchar(255) DEFAULT NULL COMMENT '密码',`email` varchar(45) DEFAULT NULL COMMENT '邮箱',`phone` varchar(45) DEFAULT NULL COMMENT '电话',`gender` varchar(45) DEFAULT 'UNKNOWN' COMMENT '性别,默认未知',`city` varchar(45) DEFAULT NULL COMMENT '城市',`avatar_url` varchar(255) DEFAULT NULL COMMENT '头像链接',`last_time` datetime DEFAULT NULL COMMENT '上次登录使劲按',`last_ip` varchar(45) DEFAULT NULL,`status` varchar(45) DEFAULT 'OK',`sort` bigint(20) DEFAULT NULL,`modify_time` timestamp NULL DEFAULT NULL,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`uuid`),UNIQUE KEY `id_UNIQUE` (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表描述';"
|
||||||
|
db = db.Exec(createUser)
|
||||||
|
if db.Error != nil {
|
||||||
|
LogPanic(db.Error)
|
||||||
|
}
|
||||||
|
LogInfo("创建User表")
|
||||||
|
|
||||||
|
user := &User{}
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
user.Uuid = string(timeUUID.String())
|
||||||
|
user.CreateTime = time.Now()
|
||||||
|
user.ModifyTime = time.Now()
|
||||||
|
user.LastTime = time.Now()
|
||||||
|
user.Sort = time.Now().UnixNano() / 1e6
|
||||||
|
user.Role = USER_ROLE_ADMINISTRATOR
|
||||||
|
user.Username = CONFIG.AdminUsername
|
||||||
|
user.Password = GetBcrypt(CONFIG.AdminPassword)
|
||||||
|
user.Email = CONFIG.AdminEmail
|
||||||
|
user.Phone = ""
|
||||||
|
user.Gender = USER_GENDER_UNKNOWN
|
||||||
|
user.Status = USER_STATUS_OK
|
||||||
|
|
||||||
|
db.Create(user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
384
rest/matter_controller.go
Normal file
384
rest/matter_controller.go
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MatterController struct {
|
||||||
|
BaseController
|
||||||
|
matterDao *MatterDao
|
||||||
|
matterService *MatterService
|
||||||
|
downloadTokenDao *DownloadTokenDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化方法
|
||||||
|
func (this *MatterController) Init(context *Context) {
|
||||||
|
this.BaseController.Init(context)
|
||||||
|
|
||||||
|
//手动装填本实例的Bean. 这里必须要用中间变量方可。
|
||||||
|
b := context.GetBean(this.matterDao)
|
||||||
|
if b, ok := b.(*MatterDao); ok {
|
||||||
|
this.matterDao = b
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.matterService)
|
||||||
|
if b, ok := b.(*MatterService); ok {
|
||||||
|
this.matterService = b
|
||||||
|
}
|
||||||
|
|
||||||
|
b = context.GetBean(this.downloadTokenDao)
|
||||||
|
if b, ok := b.(*DownloadTokenDao); ok {
|
||||||
|
this.downloadTokenDao = b
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册自己的路由。
|
||||||
|
func (this *MatterController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
|
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
|
||||||
|
|
||||||
|
//每个Controller需要主动注册自己的路由。
|
||||||
|
routeMap["/api/matter/create/directory"] = this.Wrap(this.CreateDirectory, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/upload"] = this.Wrap(this.Upload, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/delete"] = this.Wrap(this.Delete, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/delete/batch"] = this.Wrap(this.DeleteBatch, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/rename"] = this.Wrap(this.Rename, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/move"] = this.Wrap(this.Move, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
|
||||||
|
routeMap["/api/matter/page"] = this.Wrap(this.Page, USER_ROLE_USER)
|
||||||
|
|
||||||
|
return routeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
//查看某个文件的详情。
|
||||||
|
func (this *MatterController) Detail(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
if uuid == "" {
|
||||||
|
return this.Error("文件的uuid必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := this.matterDao.FindByUuid(uuid)
|
||||||
|
|
||||||
|
//组装file的内容,展示其父组件。
|
||||||
|
puuid := matter.Puuid
|
||||||
|
tmpMatter := matter
|
||||||
|
for puuid != "root" {
|
||||||
|
pFile := this.matterDao.FindByUuid(puuid)
|
||||||
|
|
||||||
|
tmpMatter.Parent = pFile
|
||||||
|
tmpMatter = pFile
|
||||||
|
puuid = pFile.Puuid
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建一个文件夹。
|
||||||
|
func (this *MatterController) CreateDirectory(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
puuid := request.FormValue("puuid")
|
||||||
|
name := request.FormValue("name")
|
||||||
|
|
||||||
|
userUuid := request.FormValue("userUuid")
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
userUuid = user.Uuid
|
||||||
|
}
|
||||||
|
user = this.userDao.CheckByUuid(userUuid)
|
||||||
|
|
||||||
|
//验证参数。
|
||||||
|
if name == "" {
|
||||||
|
return this.Error("name参数必填")
|
||||||
|
}
|
||||||
|
if m, _ := regexp.MatchString(`[<>|*?/\\]`, name); m {
|
||||||
|
return this.Error(`名称中不能包含以下特殊符号:< > | * ? / \`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if puuid != "" && puuid != "root" {
|
||||||
|
//找出上一级的文件夹。
|
||||||
|
this.matterDao.FindByUuidAndUserUuid(puuid, user.Uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断同级文件夹中是否有同名的文件。
|
||||||
|
count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, puuid, true, name)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
return this.Error("【" + name + "】已经存在了,请使用其他名称。")
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := &Matter{
|
||||||
|
Puuid: puuid,
|
||||||
|
UserUuid: user.Uuid,
|
||||||
|
Dir: true,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
matter = this.matterDao.Create(matter)
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照分页的方式获取某个文件夹下文件和子文件夹的列表,通常情况下只有一页。
|
||||||
|
func (this *MatterController) Page(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
//如果是根目录,那么就传入root.
|
||||||
|
puuid := request.FormValue("puuid")
|
||||||
|
pageStr := request.FormValue("page")
|
||||||
|
pageSizeStr := request.FormValue("pageSize")
|
||||||
|
userUuid := request.FormValue("userUuid")
|
||||||
|
name := request.FormValue("name")
|
||||||
|
dir := request.FormValue("dir")
|
||||||
|
orderDir := request.FormValue("orderDir")
|
||||||
|
orderCreateTime := request.FormValue("orderCreateTime")
|
||||||
|
orderSize := request.FormValue("orderSize")
|
||||||
|
orderName := request.FormValue("orderName")
|
||||||
|
extensionsStr := request.FormValue("extensions")
|
||||||
|
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
userUuid = user.Uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
var page int
|
||||||
|
if pageStr != "" {
|
||||||
|
page, _ = strconv.Atoi(pageStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pageSize := 200
|
||||||
|
if pageSizeStr != "" {
|
||||||
|
tmp, err := strconv.Atoi(pageSizeStr)
|
||||||
|
if err == nil {
|
||||||
|
pageSize = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//筛选后缀名
|
||||||
|
var extensions []string
|
||||||
|
if extensionsStr != "" {
|
||||||
|
extensions = strings.Split(extensionsStr, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件列表默认文件夹始终在文件的前面。
|
||||||
|
if orderDir == "" {
|
||||||
|
orderDir = "DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
sortArray := []OrderPair{
|
||||||
|
{
|
||||||
|
key: "dir",
|
||||||
|
value: orderDir,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "create_time",
|
||||||
|
value: orderCreateTime,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "size",
|
||||||
|
value: orderSize,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
value: orderName,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pager := this.matterDao.Page(page, pageSize, puuid, userUuid, name, dir, extensions, sortArray)
|
||||||
|
|
||||||
|
return this.Success(pager)
|
||||||
|
}
|
||||||
|
|
||||||
|
//上传文件
|
||||||
|
func (this *MatterController) Upload(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
userUuid := request.FormValue("userUuid")
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
userUuid = user.Uuid
|
||||||
|
}
|
||||||
|
user = this.userDao.CheckByUuid(userUuid)
|
||||||
|
|
||||||
|
puuid := request.FormValue("puuid")
|
||||||
|
if puuid == "" {
|
||||||
|
return this.Error("puuid必填")
|
||||||
|
} else {
|
||||||
|
if puuid != "root" {
|
||||||
|
//找出上一级的文件夹。
|
||||||
|
this.matterDao.FindByUuidAndUserUuid(puuid, userUuid)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request.ParseMultipartForm(32 << 20)
|
||||||
|
file, handler, err := request.FormFile("file")
|
||||||
|
this.PanicError(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
matter := this.matterService.Upload(file, user, puuid, handler.Filename, true)
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除一个文件
|
||||||
|
func (this *MatterController) Delete(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
if uuid == "" {
|
||||||
|
return this.Error("文件的uuid必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := this.matterDao.FindByUuid(uuid)
|
||||||
|
|
||||||
|
//判断文件的所属人是否正确
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.matterDao.Delete(matter)
|
||||||
|
|
||||||
|
return this.Success("删除成功!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除一系列文件。
|
||||||
|
func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuids := request.FormValue("uuids")
|
||||||
|
if uuids == "" {
|
||||||
|
return this.Error("文件的uuids必填")
|
||||||
|
}
|
||||||
|
|
||||||
|
uuidArray := strings.Split(uuids, ",")
|
||||||
|
|
||||||
|
for _, uuid := range uuidArray {
|
||||||
|
|
||||||
|
matter := this.matterDao.FindByUuid(uuid)
|
||||||
|
|
||||||
|
//判断文件的所属人是否正确
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.matterDao.Delete(matter)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success("删除成功!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//重命名一个文件或一个文件夹
|
||||||
|
func (this *MatterController) Rename(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
name := request.FormValue("name")
|
||||||
|
|
||||||
|
//验证参数。
|
||||||
|
if name == "" {
|
||||||
|
return this.Error("name参数必填")
|
||||||
|
}
|
||||||
|
if m, _ := regexp.MatchString(`[<>|*?/\\]`, name); m {
|
||||||
|
return this.Error(`名称中不能包含以下特殊符号:< > | * ? / \`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//找出该文件或者文件夹
|
||||||
|
matter := this.matterDao.FindByUuid(uuid)
|
||||||
|
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == matter.Name {
|
||||||
|
return this.Error("新名称和旧名称一样,操作失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断同级文件夹中是否有同名的文件
|
||||||
|
count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, matter.Puuid, matter.Dir, name)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
return this.Error("【" + name + "】已经存在了,请使用其他名称。")
|
||||||
|
}
|
||||||
|
|
||||||
|
matter.Name = name
|
||||||
|
matter = this.matterDao.Save(matter)
|
||||||
|
|
||||||
|
return this.Success(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//将一个文件夹或者文件移入到另一个文件夹下。
|
||||||
|
func (this *MatterController) Move(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
srcUuidsStr := request.FormValue("srcUuids")
|
||||||
|
destUuid := request.FormValue("destUuid")
|
||||||
|
|
||||||
|
var srcUuids []string
|
||||||
|
//验证参数。
|
||||||
|
if srcUuidsStr == "" {
|
||||||
|
return this.Error("srcUuids参数必填")
|
||||||
|
} else {
|
||||||
|
srcUuids = strings.Split(srcUuidsStr, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
userUuid := request.FormValue("userUuid")
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
userUuid = user.Uuid
|
||||||
|
}
|
||||||
|
if userUuid == "" {
|
||||||
|
userUuid = user.Uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
user = this.userDao.CheckByUuid(userUuid)
|
||||||
|
|
||||||
|
//验证dest是否有问题
|
||||||
|
if destUuid == "" {
|
||||||
|
return this.Error("destUuid参数必填")
|
||||||
|
} else {
|
||||||
|
if destUuid != "root" {
|
||||||
|
destMatter := this.matterDao.FindByUuid(destUuid)
|
||||||
|
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && destMatter.UserUuid != user.Uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcMatters []*Matter
|
||||||
|
//验证src是否有问题。
|
||||||
|
for _, uuid := range srcUuids {
|
||||||
|
//找出该文件或者文件夹
|
||||||
|
srcMatter := this.matterDao.FindByUuid(uuid)
|
||||||
|
|
||||||
|
if user.Role != USER_ROLE_ADMINISTRATOR && srcMatter.UserUuid != user.Uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcMatter.Puuid == destUuid {
|
||||||
|
return this.Error("没有进行移动,操作无效!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断同级文件夹中是否有同名的文件
|
||||||
|
count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, destUuid, srcMatter.Dir, srcMatter.Name)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
return this.Error("【" + srcMatter.Name + "】在目标文件夹已经存在了,操作失败。")
|
||||||
|
}
|
||||||
|
|
||||||
|
srcMatters = append(srcMatters, srcMatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, srcMatter := range srcMatters {
|
||||||
|
srcMatter.Puuid = destUuid
|
||||||
|
srcMatter = this.matterDao.Save(srcMatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success(nil)
|
||||||
|
}
|
237
rest/matter_dao.go
Normal file
237
rest/matter_dao.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MatterDao struct {
|
||||||
|
BaseDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询文件
|
||||||
|
func (this *MatterDao) FindByUuid(uuid string) *Matter {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var matter Matter
|
||||||
|
db := this.context.DB.Where(&Matter{Base: Base{Uuid: uuid}}).First(&matter)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &matter
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询文件
|
||||||
|
func (this *MatterDao) CheckByUuid(uuid string) *Matter {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var matter Matter
|
||||||
|
db := this.context.DB.Where(&Matter{Base: Base{Uuid: uuid}}).First(&matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return &matter
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照名字查询文件夹
|
||||||
|
func (this *MatterDao) FindByUserUuidAndPuuidAndNameAndDirTrue(userUuid string, puuid string, name string) *Matter {
|
||||||
|
|
||||||
|
var wp = &WherePair{}
|
||||||
|
|
||||||
|
if userUuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if puuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "puuid = ?", Args: []interface{}{puuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "name = ?", Args: []interface{}{name}})
|
||||||
|
}
|
||||||
|
|
||||||
|
wp = wp.And(&WherePair{Query: "dir = ?", Args: []interface{}{1}})
|
||||||
|
|
||||||
|
var matter = &Matter{}
|
||||||
|
db := this.context.DB.Model(&Matter{}).Where(wp.Query, wp.Args...).First(matter)
|
||||||
|
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return matter
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照id和userUuid来查找。
|
||||||
|
func (this *MatterDao) FindByUuidAndUserUuid(uuid string, userUuid string) *Matter {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var matter = &Matter{}
|
||||||
|
db := this.context.DB.Where(&Matter{Base: Base{Uuid: uuid}, UserUuid: userUuid}).First(matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return matter
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//统计某个用户的某个文件夹下的某个名字的文件(或文件夹)数量。
|
||||||
|
func (this *MatterDao) CountByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) int {
|
||||||
|
|
||||||
|
var matter Matter
|
||||||
|
var count int
|
||||||
|
|
||||||
|
var wp = &WherePair{}
|
||||||
|
|
||||||
|
if puuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "puuid = ?", Args: []interface{}{puuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if userUuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "name = ?", Args: []interface{}{name}})
|
||||||
|
}
|
||||||
|
|
||||||
|
wp = wp.And(&WherePair{Query: "dir = ?", Args: []interface{}{dir}})
|
||||||
|
|
||||||
|
db := this.context.DB.
|
||||||
|
Model(&matter).
|
||||||
|
Where(wp.Query, wp.Args...).
|
||||||
|
Count(&count)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取某个用户的某个文件夹下的某个名字的文件(或文件夹)列表
|
||||||
|
func (this *MatterDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) []*Matter {
|
||||||
|
|
||||||
|
var matters []*Matter
|
||||||
|
|
||||||
|
db := this.context.DB.
|
||||||
|
Where(Matter{UserUuid: userUuid, Puuid: puuid, Dir: dir, Name: name}).
|
||||||
|
Find(&matters)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return matters
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取某个文件夹下所有的文件和子文件
|
||||||
|
func (this *MatterDao) List(puuid string, userUuid string, sortArray []OrderPair) []*Matter {
|
||||||
|
var matters []*Matter
|
||||||
|
|
||||||
|
db := this.context.DB.Where(Matter{UserUuid: userUuid, Puuid: puuid}).Order(this.GetSortString(sortArray)).Find(&matters)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return matters
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取某个文件夹下所有的文件和子文件
|
||||||
|
func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, name string, dir string, extensions []string, sortArray []OrderPair) *Pager {
|
||||||
|
|
||||||
|
var wp = &WherePair{}
|
||||||
|
|
||||||
|
if puuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "puuid = ?", Args: []interface{}{puuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if userUuid != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "name LIKE ?", Args: []interface{}{"%" + name + "%"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir == "true" {
|
||||||
|
wp = wp.And(&WherePair{Query: "dir = ?", Args: []interface{}{1}})
|
||||||
|
} else if dir == "false" {
|
||||||
|
wp = wp.And(&WherePair{Query: "dir = ?", Args: []interface{}{0}})
|
||||||
|
}
|
||||||
|
|
||||||
|
var conditionDB *gorm.DB
|
||||||
|
if extensions != nil && len(extensions) > 0 {
|
||||||
|
var orWp = &WherePair{}
|
||||||
|
|
||||||
|
for _, v := range extensions {
|
||||||
|
orWp = orWp.Or(&WherePair{Query: "name LIKE ?", Args: []interface{}{"%." + v}})
|
||||||
|
}
|
||||||
|
|
||||||
|
conditionDB = this.context.DB.Model(&Matter{}).Where(wp.Query, wp.Args...).Where(orWp.Query, orWp.Args...)
|
||||||
|
} else {
|
||||||
|
conditionDB = this.context.DB.Model(&Matter{}).Where(wp.Query, wp.Args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
db := conditionDB.Count(&count)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
var matters []*Matter
|
||||||
|
db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&matters)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
pager := NewPager(page, pageSize, count, matters)
|
||||||
|
|
||||||
|
return pager
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建
|
||||||
|
func (this *MatterDao) Create(matter *Matter) *Matter {
|
||||||
|
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
matter.Uuid = string(timeUUID.String())
|
||||||
|
matter.CreateTime = time.Now()
|
||||||
|
matter.ModifyTime = time.Now()
|
||||||
|
db := this.context.DB.Create(matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return matter
|
||||||
|
}
|
||||||
|
|
||||||
|
//修改一个文件
|
||||||
|
func (this *MatterDao) Save(matter *Matter) *Matter {
|
||||||
|
|
||||||
|
matter.ModifyTime = time.Now()
|
||||||
|
db := this.context.DB.Save(matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return matter
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除一个文件,数据库中删除,物理磁盘上删除。
|
||||||
|
func (this *MatterDao) Delete(matter *Matter) {
|
||||||
|
|
||||||
|
//目录的话递归删除。
|
||||||
|
if matter.Dir {
|
||||||
|
matters := this.List(matter.Uuid, matter.UserUuid, nil)
|
||||||
|
|
||||||
|
for _, f := range matters {
|
||||||
|
this.Delete(f)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除文件夹本身
|
||||||
|
db := this.context.DB.Delete(&matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
db := this.context.DB.Delete(&matter)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
//删除文件
|
||||||
|
err := os.Remove(GetFilePath() + matter.Path)
|
||||||
|
|
||||||
|
LogError(fmt.Sprintf("删除磁盘上的文件出错,不做任何处理"))
|
||||||
|
|
||||||
|
this.PanicError(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
rest/matter_model.go
Normal file
19
rest/matter_model.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
type Matter struct {
|
||||||
|
Base
|
||||||
|
Puuid string `json:"puuid"`
|
||||||
|
UserUuid string `json:"userUuid"`
|
||||||
|
Dir bool `json:"dir"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Md5 string `json:"md5"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Privacy bool `json:"privacy"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Parent *Matter `gorm:"-" json:"parent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// set File's table name to be `profiles`
|
||||||
|
func (Matter) TableName() string {
|
||||||
|
return TABLE_PREFIX + "matter"
|
||||||
|
}
|
117
rest/matter_service.go
Normal file
117
rest/matter_service.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
//@Service
|
||||||
|
type MatterService struct {
|
||||||
|
Bean
|
||||||
|
matterDao *MatterDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化方法
|
||||||
|
func (this *MatterService) Init(context *Context) {
|
||||||
|
|
||||||
|
//手动装填本实例的Bean. 这里必须要用中间变量方可。
|
||||||
|
|
||||||
|
b := context.GetBean(this.matterDao)
|
||||||
|
if b, ok := b.(*MatterDao); ok {
|
||||||
|
this.matterDao = b
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据一个文件夹路径,找到最后一个文件夹的uuid,如果中途出错,返回err.
|
||||||
|
func (this *MatterService) GetDirUuid(userUuid string, dir string) string {
|
||||||
|
|
||||||
|
if dir == "" {
|
||||||
|
panic(`文件夹不能为空`)
|
||||||
|
} else if dir[0:1] != "/" {
|
||||||
|
panic(`文件夹必须以/开头`)
|
||||||
|
} else if strings.Index(dir, "//") != -1 {
|
||||||
|
panic(`文件夹不能出现连续的//`)
|
||||||
|
} else if m, _ := regexp.MatchString(`[<>|*?\\]`, dir); m {
|
||||||
|
panic(`文件夹中不能包含以下特殊符号:< > | * ? \`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir == "/" {
|
||||||
|
return "root"
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir[len(dir)-1] == '/' {
|
||||||
|
dir = dir[:len(dir)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
//递归找寻文件的上级目录uuid.
|
||||||
|
folders := strings.Split(dir, "/")
|
||||||
|
|
||||||
|
puuid := "root"
|
||||||
|
for k, name := range folders {
|
||||||
|
if k == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
matter := this.matterDao.FindByUserUuidAndPuuidAndNameAndDirTrue(userUuid, puuid, name)
|
||||||
|
if matter == nil {
|
||||||
|
//创建一个文件夹。
|
||||||
|
matter = &Matter{
|
||||||
|
Puuid: puuid,
|
||||||
|
UserUuid: userUuid,
|
||||||
|
Dir: true,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
matter = this.matterDao.Create(matter)
|
||||||
|
}
|
||||||
|
|
||||||
|
puuid = matter.Uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
return puuid
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始上传文件
|
||||||
|
//上传文件
|
||||||
|
func (this *MatterService) Upload(file multipart.File, user *User, puuid string, filename string, privacy bool) *Matter {
|
||||||
|
|
||||||
|
//获取文件应该存放在的物理路径的绝对路径和相对路径。
|
||||||
|
absolutePath, relativePath := GetUserFilePath(user.Username)
|
||||||
|
absolutePath = absolutePath + "/" + filename
|
||||||
|
relativePath = relativePath + "/" + filename
|
||||||
|
|
||||||
|
distFile, err := os.OpenFile(absolutePath, os.O_WRONLY|os.O_CREATE, 0777)
|
||||||
|
this.PanicError(err)
|
||||||
|
|
||||||
|
defer distFile.Close()
|
||||||
|
|
||||||
|
written, err := io.Copy(distFile, file)
|
||||||
|
this.PanicError(err)
|
||||||
|
|
||||||
|
//查找文件夹下面是否有同名文件。
|
||||||
|
matters := this.matterDao.ListByUserUuidAndPuuidAndDirAndName(user.Uuid, puuid, false, filename)
|
||||||
|
//如果有同名的文件,那么我们直接覆盖同名文件。
|
||||||
|
for _, dbFile := range matters {
|
||||||
|
this.matterDao.Delete(dbFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
//将文件信息存入数据库中。
|
||||||
|
matter := &Matter{
|
||||||
|
Puuid: puuid,
|
||||||
|
UserUuid: user.Uuid,
|
||||||
|
Dir: false,
|
||||||
|
Name: filename,
|
||||||
|
Md5: "",
|
||||||
|
Size: written,
|
||||||
|
Privacy: privacy,
|
||||||
|
Path: relativePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
matter = this.matterDao.Create(matter)
|
||||||
|
|
||||||
|
return matter
|
||||||
|
}
|
138
rest/router.go
Normal file
138
rest/router.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/json-iterator/go"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
//用于处理所有前来的请求
|
||||||
|
type Router struct {
|
||||||
|
context *Context
|
||||||
|
routeMap map[string]func(writer http.ResponseWriter, request *http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
//构造方法
|
||||||
|
func NewRouter(context *Context) *Router {
|
||||||
|
router := &Router{
|
||||||
|
context: context,
|
||||||
|
routeMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, controller := range context.ControllerMap {
|
||||||
|
routes := controller.RegisterRoutes()
|
||||||
|
for k, v := range routes {
|
||||||
|
router.routeMap[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return router
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//全局的异常捕获
|
||||||
|
func (this *Router) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
|
||||||
|
LogError(fmt.Sprintf("全局异常: %v", err))
|
||||||
|
|
||||||
|
var webResult *WebResult = nil
|
||||||
|
if value, ok := err.(string); ok {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: value}
|
||||||
|
} else if value, ok := err.(int); ok {
|
||||||
|
webResult = ConstWebResult(value)
|
||||||
|
} else if value, ok := err.(*WebResult); ok {
|
||||||
|
webResult = value
|
||||||
|
} else if value, ok := err.(WebResult); ok {
|
||||||
|
webResult = &value
|
||||||
|
} else if value, ok := err.(error); ok {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: value.Error()}
|
||||||
|
} else {
|
||||||
|
webResult = &WebResult{Code: RESULT_CODE_UTIL_EXCEPTION, Msg: "服务器未知错误"}
|
||||||
|
}
|
||||||
|
|
||||||
|
//输出的是json格式 返回的内容申明是json,utf-8
|
||||||
|
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
|
//用json的方式输出返回值。
|
||||||
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
b, _ := json.Marshal(webResult)
|
||||||
|
|
||||||
|
if webResult.Code == RESULT_CODE_OK {
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
} else {
|
||||||
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer, string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//让Router具有处理请求的功能。
|
||||||
|
func (this *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
|
//每个请求的入口在这里
|
||||||
|
//全局异常处理。
|
||||||
|
defer this.GlobalPanicHandler(writer, request)
|
||||||
|
|
||||||
|
path := request.URL.Path
|
||||||
|
if strings.HasPrefix(path, "/api") {
|
||||||
|
|
||||||
|
if handler, ok := this.routeMap[path]; ok {
|
||||||
|
|
||||||
|
handler(writer, request)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//直接将请求扔给每个controller,看看他们能不能处理,如果都不能处理,那就算了。
|
||||||
|
canHandle := false
|
||||||
|
for _, controller := range this.context.ControllerMap {
|
||||||
|
if handler, exist := controller.HandleRoutes(writer, request); exist {
|
||||||
|
canHandle = true
|
||||||
|
|
||||||
|
handler(writer, request)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canHandle {
|
||||||
|
panic(fmt.Sprintf("没有找到能够处理%s的方法\n", path))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//当作静态资源处理。默认从当前文件下面的static文件夹中取东西。
|
||||||
|
dir := GetHtmlPath()
|
||||||
|
|
||||||
|
requestURI := request.RequestURI
|
||||||
|
if requestURI == "" || request.RequestURI == "/" {
|
||||||
|
requestURI = "index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := dir + requestURI
|
||||||
|
exists, _ := PathExists(filePath)
|
||||||
|
if !exists {
|
||||||
|
filePath = dir + "/index.html"
|
||||||
|
exists, _ = PathExists(filePath)
|
||||||
|
if !exists {
|
||||||
|
panic("404 not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Header().Set("Content-Type", GetMimeType(GetExtension(filePath)))
|
||||||
|
|
||||||
|
diskFile, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("cannot get file.")
|
||||||
|
}
|
||||||
|
defer diskFile.Close()
|
||||||
|
_, err = io.Copy(writer, diskFile)
|
||||||
|
if err != nil {
|
||||||
|
panic("cannot get file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
rest/session_dao.go
Normal file
75
rest/session_dao.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SessionDao struct {
|
||||||
|
BaseDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//构造函数
|
||||||
|
func NewSessionDao(context *Context) *SessionDao {
|
||||||
|
|
||||||
|
var sessionDao = &SessionDao{}
|
||||||
|
sessionDao.Init(context)
|
||||||
|
return sessionDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询session.
|
||||||
|
func (this *SessionDao) FindByUuid(uuid string) *Session {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var session = &Session{}
|
||||||
|
db := this.context.DB.Where(&Session{Base: Base{Uuid: uuid}}).First(session)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询session.
|
||||||
|
func (this *SessionDao) CheckByUuid(uuid string) *Session {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var session = &Session{}
|
||||||
|
db := this.context.DB.Where(&Session{Base: Base{Uuid: uuid}}).First(session)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照authentication查询用户。
|
||||||
|
func (this *SessionDao) FindByAuthentication(authentication string) *Session {
|
||||||
|
|
||||||
|
var session = &Session{}
|
||||||
|
db := this.context.DB.Where(&Session{Authentication: authentication}).First(session)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return session
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建一个session并且持久化到数据库中。
|
||||||
|
func (this *SessionDao) Create(session *Session) *Session {
|
||||||
|
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
session.Uuid = string(timeUUID.String())
|
||||||
|
db := this.context.DB.Create(session)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SessionDao) Delete(uuid string) {
|
||||||
|
|
||||||
|
session := this.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
session.ExpireTime = time.Now()
|
||||||
|
db := this.context.DB.Delete(session)
|
||||||
|
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
}
|
18
rest/session_model.go
Normal file
18
rest/session_model.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
Base
|
||||||
|
Authentication string `json:"authentication"`
|
||||||
|
UserUuid string `json:"userUuid"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
ExpireTime time.Time `json:"expireTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// set User's table name to be `profiles`
|
||||||
|
func (Session) TableName() string {
|
||||||
|
return TABLE_PREFIX + "session"
|
||||||
|
}
|
48
rest/sql_builder.go
Normal file
48
rest/sql_builder.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
type OrderPair struct {
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type WherePair struct {
|
||||||
|
Query string
|
||||||
|
Args []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WherePair) And(where *WherePair) *WherePair {
|
||||||
|
if this.Query == "" {
|
||||||
|
return where
|
||||||
|
} else {
|
||||||
|
return &WherePair{Query: this.Query + " AND " + where.Query, Args: append(this.Args, where.Args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WherePair) Or(where *WherePair) *WherePair {
|
||||||
|
if this.Query == "" {
|
||||||
|
return where
|
||||||
|
} else {
|
||||||
|
return &WherePair{Query: this.Query + " OR " + where.Query, Args: append(this.Args, where.Args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据一个sortMap,获取到order字符串
|
||||||
|
func (this *BaseDao) GetSortString(sortArray []OrderPair) string {
|
||||||
|
|
||||||
|
if sortArray == nil || len(sortArray) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
str := ""
|
||||||
|
for _, pair := range sortArray {
|
||||||
|
if pair.value == "DESC" || pair.value == "ASC" {
|
||||||
|
if str != "" {
|
||||||
|
str = str + ","
|
||||||
|
}
|
||||||
|
str = str + " " + pair.key + " " + pair.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
50
rest/upload_token_dao.go
Normal file
50
rest/upload_token_dao.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadTokenDao struct {
|
||||||
|
BaseDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询
|
||||||
|
func (this *UploadTokenDao) FindByUuid(uuid string) *UploadToken {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var uploadToken = &UploadToken{}
|
||||||
|
db := this.context.DB.Where(&UploadToken{Base: Base{Uuid: uuid}}).First(uploadToken)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return uploadToken
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建一个session并且持久化到数据库中。
|
||||||
|
func (this *UploadTokenDao) Create(uploadToken *UploadToken) *UploadToken {
|
||||||
|
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
uploadToken.Uuid = string(timeUUID.String())
|
||||||
|
|
||||||
|
uploadToken.CreateTime = time.Now()
|
||||||
|
uploadToken.ModifyTime = time.Now()
|
||||||
|
|
||||||
|
db := this.context.DB.Create(uploadToken)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return uploadToken
|
||||||
|
}
|
||||||
|
|
||||||
|
//修改一个uploadToken
|
||||||
|
func (this *UploadTokenDao) Save(uploadToken *UploadToken) *UploadToken {
|
||||||
|
|
||||||
|
uploadToken.ModifyTime = time.Now()
|
||||||
|
db := this.context.DB.Save(uploadToken)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return uploadToken
|
||||||
|
}
|
21
rest/upload_token_model.go
Normal file
21
rest/upload_token_model.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadToken struct {
|
||||||
|
Base
|
||||||
|
UserUuid string `json:"userUuid"`
|
||||||
|
FolderUuid string `json:"folderUuid"`
|
||||||
|
MatterUuid string `json:"matterUuid"`
|
||||||
|
ExpireTime time.Time `json:"expireTime"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
Privacy bool `json:"privacy"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UploadToken) TableName() string {
|
||||||
|
return TABLE_PREFIX + "upload_token"
|
||||||
|
}
|
322
rest/user_controller.go
Normal file
322
rest/user_controller.go
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserController struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化方法
|
||||||
|
func (this *UserController) Init(context *Context) {
|
||||||
|
this.BaseController.Init(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册自己的路由。
|
||||||
|
func (this *UserController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|
||||||
|
routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request))
|
||||||
|
|
||||||
|
//每个Controller需要主动注册自己的路由。
|
||||||
|
routeMap["/api/user/create"] = this.Wrap(this.Create, USER_ROLE_ADMINISTRATOR)
|
||||||
|
routeMap["/api/user/edit"] = this.Wrap(this.Edit, USER_ROLE_ADMINISTRATOR)
|
||||||
|
routeMap["/api/user/change/password"] = this.Wrap(this.ChangePassword, USER_ROLE_USER)
|
||||||
|
routeMap["/api/user/reset/password"] = this.Wrap(this.ResetPassword, USER_ROLE_ADMINISTRATOR)
|
||||||
|
routeMap["/api/user/login"] = this.Wrap(this.Login, USER_ROLE_GUEST)
|
||||||
|
routeMap["/api/user/logout"] = this.Wrap(this.Logout, USER_ROLE_USER)
|
||||||
|
routeMap["/api/user/detail"] = this.Wrap(this.Detail, USER_ROLE_USER)
|
||||||
|
routeMap["/api/user/page"] = this.Wrap(this.Page, USER_ROLE_ADMINISTRATOR)
|
||||||
|
routeMap["/api/user/disable"] = this.Wrap(this.Disable, USER_ROLE_ADMINISTRATOR)
|
||||||
|
routeMap["/api/user/enable"] = this.Wrap(this.Enable, USER_ROLE_ADMINISTRATOR)
|
||||||
|
|
||||||
|
return routeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
//使用用户名和密码进行登录。
|
||||||
|
//参数:
|
||||||
|
// @email:邮箱
|
||||||
|
// @password:密码
|
||||||
|
func (this *UserController) Login(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
email := request.FormValue("email")
|
||||||
|
password := request.FormValue("password")
|
||||||
|
|
||||||
|
if "" == email || "" == password {
|
||||||
|
|
||||||
|
return this.Error("请输入邮箱和密码")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.userDao.FindByEmail(email)
|
||||||
|
if user == nil {
|
||||||
|
|
||||||
|
return this.Error("邮箱或密码错误")
|
||||||
|
} else {
|
||||||
|
if !MatchBcrypt(password, user.Password) {
|
||||||
|
|
||||||
|
return this.Error("邮箱或密码错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//登录成功,设置Cookie。有效期7天。
|
||||||
|
expiration := time.Now()
|
||||||
|
expiration = expiration.AddDate(0, 0, 7)
|
||||||
|
|
||||||
|
//持久化用户的session.
|
||||||
|
|
||||||
|
session := &Session{
|
||||||
|
UserUuid: user.Uuid,
|
||||||
|
Ip: GetIpAddress(request),
|
||||||
|
ExpireTime: expiration,
|
||||||
|
}
|
||||||
|
session.ModifyTime = time.Now()
|
||||||
|
session.CreateTime = time.Now()
|
||||||
|
session = this.sessionDao.Create(session)
|
||||||
|
|
||||||
|
//设置用户的cookie.
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: COOKIE_AUTH_KEY,
|
||||||
|
Path: "/",
|
||||||
|
Value: session.Uuid,
|
||||||
|
Expires: expiration}
|
||||||
|
http.SetCookie(writer, &cookie)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建一个用户
|
||||||
|
func (this *UserController) Create(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
username := request.FormValue("username")
|
||||||
|
if m, _ := regexp.MatchString(`^[0-9a-zA-Z_]+$`, username); !m {
|
||||||
|
return this.Error(`用户名必填,且只能包含字母,数字和'_''`)
|
||||||
|
}
|
||||||
|
password := request.FormValue("password")
|
||||||
|
if len(password) < 6 {
|
||||||
|
return this.Error(`密码长度至少为6位`)
|
||||||
|
}
|
||||||
|
|
||||||
|
email := request.FormValue("email")
|
||||||
|
if email == "" {
|
||||||
|
return this.Error("邮箱必填!")
|
||||||
|
}
|
||||||
|
|
||||||
|
phone := request.FormValue("phone")
|
||||||
|
gender := request.FormValue("gender")
|
||||||
|
role := request.FormValue("role")
|
||||||
|
city := request.FormValue("city")
|
||||||
|
|
||||||
|
//判断重名。
|
||||||
|
if this.userDao.CountByUsername(username) > 0 {
|
||||||
|
return this.Error(username + "已经被其他用户占用。")
|
||||||
|
}
|
||||||
|
//判断邮箱重名
|
||||||
|
if this.userDao.CountByEmail(email) > 0 {
|
||||||
|
return this.Error(email + "已经被其他用户占用。")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &User{
|
||||||
|
Role: GetRole(role),
|
||||||
|
Username: username,
|
||||||
|
Password: GetBcrypt(password),
|
||||||
|
Email: email,
|
||||||
|
Phone: phone,
|
||||||
|
Gender: gender,
|
||||||
|
City: city,
|
||||||
|
Status: USER_STATUS_OK,
|
||||||
|
}
|
||||||
|
|
||||||
|
user = this.userDao.Create(user)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
//编辑一个用户的资料。
|
||||||
|
func (this *UserController) Edit(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
phone := request.FormValue("phone")
|
||||||
|
gender := request.FormValue("gender")
|
||||||
|
city := request.FormValue("city")
|
||||||
|
|
||||||
|
currentUser := this.checkUser(writer, request)
|
||||||
|
if currentUser.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
if currentUser.Uuid != uuid {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
user.Phone = phone
|
||||||
|
user.Gender = GetGender(gender)
|
||||||
|
user.City = city
|
||||||
|
|
||||||
|
user = this.userDao.Save(user)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取用户详情
|
||||||
|
func (this *UserController) Detail(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//退出登录
|
||||||
|
func (this *UserController) Logout(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
session, _ := this.checkLogin(writer, request)
|
||||||
|
|
||||||
|
//删除session
|
||||||
|
this.sessionDao.Delete(session.Uuid)
|
||||||
|
|
||||||
|
//清空客户端的cookie.
|
||||||
|
expiration := time.Now()
|
||||||
|
expiration = expiration.AddDate(-1, 0, 0)
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: COOKIE_AUTH_KEY,
|
||||||
|
Path: "/",
|
||||||
|
Value: session.Uuid,
|
||||||
|
Expires: expiration}
|
||||||
|
http.SetCookie(writer, &cookie)
|
||||||
|
|
||||||
|
return this.Success("退出成功!")
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取用户列表 管理员的权限。
|
||||||
|
func (this *UserController) Page(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
//如果是根目录,那么就传入root.
|
||||||
|
pageStr := request.FormValue("page")
|
||||||
|
pageSizeStr := request.FormValue("pageSize")
|
||||||
|
username := request.FormValue("username")
|
||||||
|
email := request.FormValue("email")
|
||||||
|
phone := request.FormValue("phone")
|
||||||
|
orderLastTime := request.FormValue("orderLastTime")
|
||||||
|
orderCreateTime := request.FormValue("orderCreateTime")
|
||||||
|
|
||||||
|
var page int
|
||||||
|
if pageStr != "" {
|
||||||
|
page, _ = strconv.Atoi(pageStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pageSize := 200
|
||||||
|
if pageSizeStr != "" {
|
||||||
|
tmp, err := strconv.Atoi(pageSizeStr)
|
||||||
|
if err == nil {
|
||||||
|
pageSize = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortArray := []OrderPair{
|
||||||
|
{
|
||||||
|
key: "last_time",
|
||||||
|
value: orderLastTime,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "create_time",
|
||||||
|
value: orderCreateTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pager := this.userDao.Page(page, pageSize, username, email, phone, sortArray)
|
||||||
|
|
||||||
|
return this.Success(pager)
|
||||||
|
}
|
||||||
|
|
||||||
|
//禁用用户
|
||||||
|
func (this *UserController) Disable(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
if user.Status == USER_STATUS_DISABLED {
|
||||||
|
return this.Error("用户已经被禁用,操作无效。")
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Status = USER_STATUS_DISABLED
|
||||||
|
|
||||||
|
user = this.userDao.Save(user)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//启用用户
|
||||||
|
func (this *UserController) Enable(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
uuid := request.FormValue("uuid")
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(uuid)
|
||||||
|
|
||||||
|
if user.Status == USER_STATUS_OK {
|
||||||
|
return this.Error("用户已经是正常状态,操作无效。")
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Status = USER_STATUS_OK
|
||||||
|
|
||||||
|
user = this.userDao.Save(user)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//用户修改密码
|
||||||
|
func (this *UserController) ChangePassword(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
oldPassword := request.FormValue("oldPassword")
|
||||||
|
newPassword := request.FormValue("newPassword")
|
||||||
|
if oldPassword == "" || newPassword == "" {
|
||||||
|
return this.Error("旧密码和新密码都不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.checkUser(writer, request)
|
||||||
|
|
||||||
|
if !MatchBcrypt(oldPassword, user.Password) {
|
||||||
|
return this.Error("旧密码不正确!")
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Password = GetBcrypt(newPassword)
|
||||||
|
|
||||||
|
user = this.userDao.Save(user)
|
||||||
|
|
||||||
|
return this.Success(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
//管理员重置用户密码
|
||||||
|
func (this *UserController) ResetPassword(writer http.ResponseWriter, request *http.Request) *WebResult {
|
||||||
|
|
||||||
|
userUuid := request.FormValue("userUuid")
|
||||||
|
password := request.FormValue("password")
|
||||||
|
if userUuid == "" {
|
||||||
|
return this.Error("用户不能为空")
|
||||||
|
}
|
||||||
|
if password == "" {
|
||||||
|
return this.Error("密码不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUser := this.checkUser(writer, request)
|
||||||
|
|
||||||
|
if currentUser.Role != USER_ROLE_ADMINISTRATOR {
|
||||||
|
return this.Error(RESULT_CODE_UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
|
||||||
|
user := this.userDao.CheckByUuid(userUuid)
|
||||||
|
|
||||||
|
user.Password = GetBcrypt(password)
|
||||||
|
|
||||||
|
user = this.userDao.Save(user)
|
||||||
|
|
||||||
|
return this.Success(currentUser)
|
||||||
|
}
|
132
rest/user_dao.go
Normal file
132
rest/user_dao.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
"github.com/nu7hatch/gouuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserDao struct {
|
||||||
|
BaseDao
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建用户
|
||||||
|
func (this *UserDao) Create(user *User) *User {
|
||||||
|
|
||||||
|
if user == nil {
|
||||||
|
panic("参数不能为nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
timeUUID, _ := uuid.NewV4()
|
||||||
|
user.Uuid = string(timeUUID.String())
|
||||||
|
user.CreateTime = time.Now()
|
||||||
|
user.ModifyTime = time.Now()
|
||||||
|
user.LastTime = time.Now()
|
||||||
|
user.Sort = time.Now().UnixNano() / 1e6
|
||||||
|
|
||||||
|
db := this.context.DB.Create(user)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询用户,找不到返回nil
|
||||||
|
func (this *UserDao) FindByUuid(uuid string) *User {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var user *User = &User{}
|
||||||
|
db := this.context.DB.Where(&User{Base: Base{Uuid: uuid}}).First(user)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照Id查询用户,找不到抛panic
|
||||||
|
func (this *UserDao) CheckByUuid(uuid string) *User {
|
||||||
|
|
||||||
|
// Read
|
||||||
|
var user *User = &User{}
|
||||||
|
db := this.context.DB.Where(&User{Base: Base{Uuid: uuid}}).First(user)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
//按照邮箱查询用户。
|
||||||
|
func (this *UserDao) FindByEmail(email string) *User {
|
||||||
|
|
||||||
|
var user *User = &User{}
|
||||||
|
db := this.context.DB.Where(&User{Email: email}).First(user)
|
||||||
|
if db.Error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
//显示用户列表。
|
||||||
|
func (this *UserDao) Page(page int, pageSize int, username string, email string, phone string, sortArray []OrderPair) *Pager {
|
||||||
|
|
||||||
|
var wp = &WherePair{}
|
||||||
|
|
||||||
|
if username != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "username LIKE ?", Args: []interface{}{"%" + username + "%"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if email != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "email LIKE ?", Args: []interface{}{"%" + email + "%"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if phone != "" {
|
||||||
|
wp = wp.And(&WherePair{Query: "phone = ?", Args: []interface{}{phone}})
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
db := this.context.DB.Model(&User{}).Where(wp.Query, wp.Args...).Count(&count)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
var users []*User
|
||||||
|
orderStr := this.GetSortString(sortArray)
|
||||||
|
if orderStr == "" {
|
||||||
|
db = this.context.DB.Where(wp.Query, wp.Args...).Offset(page * pageSize).Limit(pageSize).Find(&users)
|
||||||
|
} else {
|
||||||
|
db = this.context.DB.Where(wp.Query, wp.Args...).Order(orderStr).Offset(page * pageSize).Limit(pageSize).Find(&users)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
|
||||||
|
pager := NewPager(page, pageSize, count, users)
|
||||||
|
|
||||||
|
return pager
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询某个用户名是否已经有用户了
|
||||||
|
func (this *UserDao) CountByUsername(username string) int {
|
||||||
|
var count int
|
||||||
|
db := this.context.DB.
|
||||||
|
Model(&User{}).
|
||||||
|
Where("username = ?", username).
|
||||||
|
Count(&count)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询某个邮箱是否已经有用户了
|
||||||
|
func (this *UserDao) CountByEmail(email string) int {
|
||||||
|
var count int
|
||||||
|
db := this.context.DB.
|
||||||
|
Model(&User{}).
|
||||||
|
Where("email = ?", email).
|
||||||
|
Count(&count)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
//保存用户
|
||||||
|
func (this *UserDao) Save(user *User) *User {
|
||||||
|
|
||||||
|
user.ModifyTime = time.Now()
|
||||||
|
db := this.context.DB.
|
||||||
|
Save(user)
|
||||||
|
this.PanicError(db.Error)
|
||||||
|
return user
|
||||||
|
}
|
63
rest/user_model.go
Normal file
63
rest/user_model.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//游客身份
|
||||||
|
USER_ROLE_GUEST = "GUEST"
|
||||||
|
//普通注册用户
|
||||||
|
USER_ROLE_USER = "USER"
|
||||||
|
//管理员
|
||||||
|
USER_ROLE_ADMINISTRATOR = "ADMINISTRATOR"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
USER_GENDER_MALE = "MALE"
|
||||||
|
USER_GENDER_FEMALE = "FEMALE"
|
||||||
|
USER_GENDER_UNKNOWN = "UNKNOWN"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
USER_STATUS_OK = "OK"
|
||||||
|
USER_STATUS_DISABLED = "DISABLED"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Base
|
||||||
|
Role string `json:"role"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"-"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Gender string `json:"gender"`
|
||||||
|
City string `json:"city"`
|
||||||
|
AvatarUrl string `json:"avatarUrl"`
|
||||||
|
LastIp string `json:"lastIp"`
|
||||||
|
LastTime time.Time `json:"lastTime"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// set User's table name to be `profiles`
|
||||||
|
func (User) TableName() string {
|
||||||
|
return TABLE_PREFIX + "user"
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过一个字符串获取性别
|
||||||
|
func GetGender(genderString string) string {
|
||||||
|
if genderString == USER_GENDER_MALE || genderString == USER_GENDER_FEMALE || genderString == USER_GENDER_UNKNOWN {
|
||||||
|
return genderString
|
||||||
|
} else {
|
||||||
|
return USER_GENDER_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过一个字符串获取角色
|
||||||
|
func GetRole(roleString string) string {
|
||||||
|
if roleString == USER_ROLE_USER || roleString == USER_ROLE_ADMINISTRATOR {
|
||||||
|
return roleString
|
||||||
|
} else {
|
||||||
|
return USER_ROLE_USER
|
||||||
|
}
|
||||||
|
}
|
30
rest/util_encode.go
Normal file
30
rest/util_encode.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"fmt"
|
||||||
|
"crypto/md5"
|
||||||
|
)
|
||||||
|
|
||||||
|
//给密码字符串加密
|
||||||
|
func GetMd5(raw string) string {
|
||||||
|
return fmt.Sprintf("%x", md5.Sum([]byte(raw)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBcrypt(raw string) string {
|
||||||
|
|
||||||
|
password := []byte(raw)
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(hashedPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MatchBcrypt(raw string, bcryptStr string) bool {
|
||||||
|
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(bcryptStr), []byte(raw))
|
||||||
|
|
||||||
|
return err == nil
|
||||||
|
|
||||||
|
}
|
50
rest/util_log.go
Normal file
50
rest/util_log.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Log(prefix string, content string) {
|
||||||
|
|
||||||
|
//日志输出到文件中
|
||||||
|
filePath := GetLogPath() + "/tank-" + time.Now().Local().Format("2006-01-02") + ".log"
|
||||||
|
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Errorf("error opening file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
log.SetOutput(f)
|
||||||
|
log.SetPrefix(prefix)
|
||||||
|
log.Println(content)
|
||||||
|
|
||||||
|
//如果需要输出到控制台。
|
||||||
|
if CONFIG.LogToConsole {
|
||||||
|
fmt.Println(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogDebug(content string) {
|
||||||
|
go Log("[Debug]", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogInfo(content string) {
|
||||||
|
go Log("[Info]", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogWarning(content string) {
|
||||||
|
go Log("[Warning]", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogError(content string) {
|
||||||
|
go Log("[Error]", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogPanic(content interface{}) {
|
||||||
|
Log("[Panic]", fmt.Sprintf("%v", content))
|
||||||
|
panic(content)
|
||||||
|
}
|
634
rest/util_mime.go
Normal file
634
rest/util_mime.go
Normal file
@ -0,0 +1,634 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//根据文件名字获取后缀名,均是小写。
|
||||||
|
func GetExtension(filename string) string {
|
||||||
|
|
||||||
|
var extension = filepath.Ext(filename)
|
||||||
|
|
||||||
|
return strings.ToLower(extension)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据一个后缀名获取MimeType
|
||||||
|
func GetMimeType(filename string) string {
|
||||||
|
|
||||||
|
extension := GetExtension(filename)
|
||||||
|
|
||||||
|
mimeMap := map[string]string{
|
||||||
|
".323": "text/h323",
|
||||||
|
".3g2": "video/3gpp2",
|
||||||
|
".3gp": "video/3gpp",
|
||||||
|
".3gp2": "video/3gpp2",
|
||||||
|
".3gpp": "video/3gpp",
|
||||||
|
".7z": "application/x-7z-compressed",
|
||||||
|
".aa": "audio/audible",
|
||||||
|
".AAC": "audio/aac",
|
||||||
|
".aaf": "application/octet-stream",
|
||||||
|
".aax": "audio/vnd.audible.aax",
|
||||||
|
".ac3": "audio/ac3",
|
||||||
|
".aca": "application/octet-stream",
|
||||||
|
".accda": "application/msaccess.addin",
|
||||||
|
".accdb": "application/msaccess",
|
||||||
|
".accdc": "application/msaccess.cab",
|
||||||
|
".accde": "application/msaccess",
|
||||||
|
".accdr": "application/msaccess.runtime",
|
||||||
|
".accdt": "application/msaccess",
|
||||||
|
".accdw": "application/msaccess.webapplication",
|
||||||
|
".accft": "application/msaccess.ftemplate",
|
||||||
|
".acx": "application/internet-property-stream",
|
||||||
|
".AddIn": "text/xml",
|
||||||
|
".ade": "application/msaccess",
|
||||||
|
".adobebridge": "application/x-bridge-url",
|
||||||
|
".adp": "application/msaccess",
|
||||||
|
".ADT": "audio/vnd.dlna.adts",
|
||||||
|
".ADTS": "audio/aac",
|
||||||
|
".afm": "application/octet-stream",
|
||||||
|
".ai": "application/postscript",
|
||||||
|
".aif": "audio/aiff",
|
||||||
|
".aifc": "audio/aiff",
|
||||||
|
".aiff": "audio/aiff",
|
||||||
|
".air": "application/vnd.adobe.air-application-installer-package+zip",
|
||||||
|
".amc": "application/mpeg",
|
||||||
|
".anx": "application/annodex",
|
||||||
|
".apk": "application/vnd.android.package-archive",
|
||||||
|
".application": "application/x-ms-application",
|
||||||
|
".art": "image/x-jg",
|
||||||
|
".asa": "application/xml",
|
||||||
|
".asax": "application/xml",
|
||||||
|
".ascx": "application/xml",
|
||||||
|
".asd": "application/octet-stream",
|
||||||
|
".asf": "video/x-ms-asf",
|
||||||
|
".ashx": "application/xml",
|
||||||
|
".asi": "application/octet-stream",
|
||||||
|
".asm": "text/plain",
|
||||||
|
".asmx": "application/xml",
|
||||||
|
".aspx": "application/xml",
|
||||||
|
".asr": "video/x-ms-asf",
|
||||||
|
".asx": "video/x-ms-asf",
|
||||||
|
".atom": "application/atom+xml",
|
||||||
|
".au": "audio/basic",
|
||||||
|
".avi": "video/x-msvideo",
|
||||||
|
".axa": "audio/annodex",
|
||||||
|
".axs": "application/olescript",
|
||||||
|
".axv": "video/annodex",
|
||||||
|
".bas": "text/plain",
|
||||||
|
".bcpio": "application/x-bcpio",
|
||||||
|
".bin": "application/octet-stream",
|
||||||
|
".bmp": "image/bmp",
|
||||||
|
".c": "text/plain",
|
||||||
|
".cab": "application/octet-stream",
|
||||||
|
".caf": "audio/x-caf",
|
||||||
|
".calx": "application/vnd.ms-office.calx",
|
||||||
|
".cat": "application/vnd.ms-pki.seccat",
|
||||||
|
".cc": "text/plain",
|
||||||
|
".cd": "text/plain",
|
||||||
|
".cdda": "audio/aiff",
|
||||||
|
".cdf": "application/x-cdf",
|
||||||
|
".cer": "application/x-x509-ca-cert",
|
||||||
|
".cfg": "text/plain",
|
||||||
|
".chm": "application/octet-stream",
|
||||||
|
".class": "application/x-java-applet",
|
||||||
|
".clp": "application/x-msclip",
|
||||||
|
".cmd": "text/plain",
|
||||||
|
".cmx": "image/x-cmx",
|
||||||
|
".cnf": "text/plain",
|
||||||
|
".cod": "image/cis-cod",
|
||||||
|
".config": "application/xml",
|
||||||
|
".contact": "text/x-ms-contact",
|
||||||
|
".coverage": "application/xml",
|
||||||
|
".cpio": "application/x-cpio",
|
||||||
|
".cpp": "text/plain",
|
||||||
|
".crd": "application/x-mscardfile",
|
||||||
|
".crl": "application/pkix-crl",
|
||||||
|
".crt": "application/x-x509-ca-cert",
|
||||||
|
".cs": "text/plain",
|
||||||
|
".csdproj": "text/plain",
|
||||||
|
".csh": "application/x-csh",
|
||||||
|
".csproj": "text/plain",
|
||||||
|
".css": "text/css",
|
||||||
|
".csv": "text/csv",
|
||||||
|
".cur": "application/octet-stream",
|
||||||
|
".cxx": "text/plain",
|
||||||
|
".dat": "application/octet-stream",
|
||||||
|
".datasource": "application/xml",
|
||||||
|
".dbproj": "text/plain",
|
||||||
|
".dcr": "application/x-director",
|
||||||
|
".def": "text/plain",
|
||||||
|
".deploy": "application/octet-stream",
|
||||||
|
".der": "application/x-x509-ca-cert",
|
||||||
|
".dgml": "application/xml",
|
||||||
|
".dib": "image/bmp",
|
||||||
|
".dif": "video/x-dv",
|
||||||
|
".dir": "application/x-director",
|
||||||
|
".disco": "text/xml",
|
||||||
|
".divx": "video/divx",
|
||||||
|
".dll": "application/x-msdownload",
|
||||||
|
".dll.config": "text/xml",
|
||||||
|
".dlm": "text/dlm",
|
||||||
|
".doc": "application/msword",
|
||||||
|
".docm": "application/vnd.ms-word.document.macroEnabled.12",
|
||||||
|
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
".dot": "application/msword",
|
||||||
|
".dotm": "application/vnd.ms-word.template.macroEnabled.12",
|
||||||
|
".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||||
|
".dsp": "application/octet-stream",
|
||||||
|
".dsw": "text/plain",
|
||||||
|
".dtd": "text/xml",
|
||||||
|
".dtsConfig": "text/xml",
|
||||||
|
".dv": "video/x-dv",
|
||||||
|
".dvi": "application/x-dvi",
|
||||||
|
".dwf": "drawing/x-dwf",
|
||||||
|
".dwg": "application/acad",
|
||||||
|
".dwp": "application/octet-stream",
|
||||||
|
".dxf": "application/x-dxf",
|
||||||
|
".dxr": "application/x-director",
|
||||||
|
".eml": "message/rfc822",
|
||||||
|
".emz": "application/octet-stream",
|
||||||
|
".eot": "application/vnd.ms-fontobject",
|
||||||
|
".eps": "application/postscript",
|
||||||
|
".etl": "application/etl",
|
||||||
|
".etx": "text/x-setext",
|
||||||
|
".evy": "application/envoy",
|
||||||
|
".exe": "application/octet-stream",
|
||||||
|
".exe.config": "text/xml",
|
||||||
|
".fdf": "application/vnd.fdf",
|
||||||
|
".fif": "application/fractals",
|
||||||
|
".filters": "application/xml",
|
||||||
|
".fla": "application/octet-stream",
|
||||||
|
".flac": "audio/flac",
|
||||||
|
".flr": "x-world/x-vrml",
|
||||||
|
".flv": "video/x-flv",
|
||||||
|
".fsscript": "application/fsharp-script",
|
||||||
|
".fsx": "application/fsharp-script",
|
||||||
|
".generictest": "application/xml",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".gpx": "application/gpx+xml",
|
||||||
|
".group": "text/x-ms-group",
|
||||||
|
".gsm": "audio/x-gsm",
|
||||||
|
".gtar": "application/x-gtar",
|
||||||
|
".gz": "application/x-gzip",
|
||||||
|
".h": "text/plain",
|
||||||
|
".hdf": "application/x-hdf",
|
||||||
|
".hdml": "text/x-hdml",
|
||||||
|
".hhc": "application/x-oleobject",
|
||||||
|
".hhk": "application/octet-stream",
|
||||||
|
".hhp": "application/octet-stream",
|
||||||
|
".hlp": "application/winhlp",
|
||||||
|
".hpp": "text/plain",
|
||||||
|
".hqx": "application/mac-binhex40",
|
||||||
|
".hta": "application/hta",
|
||||||
|
".htc": "text/x-component",
|
||||||
|
".htm": "text/html",
|
||||||
|
".html": "text/html",
|
||||||
|
".htt": "text/webviewhtml",
|
||||||
|
".hxa": "application/xml",
|
||||||
|
".hxc": "application/xml",
|
||||||
|
".hxd": "application/octet-stream",
|
||||||
|
".hxe": "application/xml",
|
||||||
|
".hxf": "application/xml",
|
||||||
|
".hxh": "application/octet-stream",
|
||||||
|
".hxi": "application/octet-stream",
|
||||||
|
".hxk": "application/xml",
|
||||||
|
".hxq": "application/octet-stream",
|
||||||
|
".hxr": "application/octet-stream",
|
||||||
|
".hxs": "application/octet-stream",
|
||||||
|
".hxt": "text/html",
|
||||||
|
".hxv": "application/xml",
|
||||||
|
".hxw": "application/octet-stream",
|
||||||
|
".hxx": "text/plain",
|
||||||
|
".i": "text/plain",
|
||||||
|
".ico": "image/x-icon",
|
||||||
|
".ics": "application/octet-stream",
|
||||||
|
".idl": "text/plain",
|
||||||
|
".ief": "image/ief",
|
||||||
|
".iii": "application/x-iphone",
|
||||||
|
".inc": "text/plain",
|
||||||
|
".inf": "application/octet-stream",
|
||||||
|
".ini": "text/plain",
|
||||||
|
".inl": "text/plain",
|
||||||
|
".ins": "application/x-internet-signup",
|
||||||
|
".ipa": "application/x-itunes-ipa",
|
||||||
|
".ipg": "application/x-itunes-ipg",
|
||||||
|
".ipproj": "text/plain",
|
||||||
|
".ipsw": "application/x-itunes-ipsw",
|
||||||
|
".iqy": "text/x-ms-iqy",
|
||||||
|
".isp": "application/x-internet-signup",
|
||||||
|
".ite": "application/x-itunes-ite",
|
||||||
|
".itlp": "application/x-itunes-itlp",
|
||||||
|
".itms": "application/x-itunes-itms",
|
||||||
|
".itpc": "application/x-itunes-itpc",
|
||||||
|
".IVF": "video/x-ivf",
|
||||||
|
".jar": "application/java-archive",
|
||||||
|
".java": "application/octet-stream",
|
||||||
|
".jck": "application/liquidmotion",
|
||||||
|
".jcz": "application/liquidmotion",
|
||||||
|
".jfif": "image/pjpeg",
|
||||||
|
".jnlp": "application/x-java-jnlp-file",
|
||||||
|
".jpb": "application/octet-stream",
|
||||||
|
".jpe": "image/jpeg",
|
||||||
|
".jpeg": "image/jpeg",
|
||||||
|
".jpg": "image/jpeg",
|
||||||
|
".js": "application/javascript",
|
||||||
|
".json": "application/json",
|
||||||
|
".jsx": "text/jscript",
|
||||||
|
".jsxbin": "text/plain",
|
||||||
|
".latex": "application/x-latex",
|
||||||
|
".library-ms": "application/windows-library+xml",
|
||||||
|
".lit": "application/x-ms-reader",
|
||||||
|
".loadtest": "application/xml",
|
||||||
|
".lpk": "application/octet-stream",
|
||||||
|
".lsf": "video/x-la-asf",
|
||||||
|
".lst": "text/plain",
|
||||||
|
".lsx": "video/x-la-asf",
|
||||||
|
".lzh": "application/octet-stream",
|
||||||
|
".m13": "application/x-msmediaview",
|
||||||
|
".m14": "application/x-msmediaview",
|
||||||
|
".m1v": "video/mpeg",
|
||||||
|
".m2t": "video/vnd.dlna.mpeg-tts",
|
||||||
|
".m2ts": "video/vnd.dlna.mpeg-tts",
|
||||||
|
".m2v": "video/mpeg",
|
||||||
|
".m3u": "audio/x-mpegurl",
|
||||||
|
".m3u8": "audio/x-mpegurl",
|
||||||
|
".m4a": "audio/m4a",
|
||||||
|
".m4b": "audio/m4b",
|
||||||
|
".m4p": "audio/m4p",
|
||||||
|
".m4r": "audio/x-m4r",
|
||||||
|
".m4v": "video/x-m4v",
|
||||||
|
".mac": "image/x-macpaint",
|
||||||
|
".mak": "text/plain",
|
||||||
|
".man": "application/x-troff-man",
|
||||||
|
".manifest": "application/x-ms-manifest",
|
||||||
|
".map": "text/plain",
|
||||||
|
".master": "application/xml",
|
||||||
|
".mbox": "application/mbox",
|
||||||
|
".mda": "application/msaccess",
|
||||||
|
".mdb": "application/x-msaccess",
|
||||||
|
".mde": "application/msaccess",
|
||||||
|
".mdp": "application/octet-stream",
|
||||||
|
".me": "application/x-troff-me",
|
||||||
|
".mfp": "application/x-shockwave-flash",
|
||||||
|
".mht": "message/rfc822",
|
||||||
|
".mhtml": "message/rfc822",
|
||||||
|
".mid": "audio/mid",
|
||||||
|
".midi": "audio/mid",
|
||||||
|
".mix": "application/octet-stream",
|
||||||
|
".mk": "text/plain",
|
||||||
|
".mmf": "application/x-smaf",
|
||||||
|
".mno": "text/xml",
|
||||||
|
".mny": "application/x-msmoney",
|
||||||
|
".mod": "video/mpeg",
|
||||||
|
".mov": "video/quicktime",
|
||||||
|
".movie": "video/x-sgi-movie",
|
||||||
|
".mp2": "video/mpeg",
|
||||||
|
".mp2v": "video/mpeg",
|
||||||
|
".mp3": "audio/mpeg",
|
||||||
|
".mp4": "video/mp4",
|
||||||
|
".mp4v": "video/mp4",
|
||||||
|
".mpa": "video/mpeg",
|
||||||
|
".mpe": "video/mpeg",
|
||||||
|
".mpeg": "video/mpeg",
|
||||||
|
".mpf": "application/vnd.ms-mediapackage",
|
||||||
|
".mpg": "video/mpeg",
|
||||||
|
".mpp": "application/vnd.ms-project",
|
||||||
|
".mpv2": "video/mpeg",
|
||||||
|
".mqv": "video/quicktime",
|
||||||
|
".ms": "application/x-troff-ms",
|
||||||
|
".msg": "application/vnd.ms-outlook",
|
||||||
|
".msi": "application/octet-stream",
|
||||||
|
".mso": "application/octet-stream",
|
||||||
|
".mts": "video/vnd.dlna.mpeg-tts",
|
||||||
|
".mtx": "application/xml",
|
||||||
|
".mvb": "application/x-msmediaview",
|
||||||
|
".mvc": "application/x-miva-compiled",
|
||||||
|
".mxp": "application/x-mmxp",
|
||||||
|
".nc": "application/x-netcdf",
|
||||||
|
".nsc": "video/x-ms-asf",
|
||||||
|
".nws": "message/rfc822",
|
||||||
|
".ocx": "application/octet-stream",
|
||||||
|
".oda": "application/oda",
|
||||||
|
".odb": "application/vnd.oasis.opendocument.database",
|
||||||
|
".odc": "application/vnd.oasis.opendocument.chart",
|
||||||
|
".odf": "application/vnd.oasis.opendocument.formula",
|
||||||
|
".odg": "application/vnd.oasis.opendocument.graphics",
|
||||||
|
".odh": "text/plain",
|
||||||
|
".odi": "application/vnd.oasis.opendocument.image",
|
||||||
|
".odl": "text/plain",
|
||||||
|
".odm": "application/vnd.oasis.opendocument.text-master",
|
||||||
|
".odp": "application/vnd.oasis.opendocument.presentation",
|
||||||
|
".ods": "application/vnd.oasis.opendocument.spreadsheet",
|
||||||
|
".odt": "application/vnd.oasis.opendocument.text",
|
||||||
|
".oga": "audio/ogg",
|
||||||
|
".ogg": "audio/ogg",
|
||||||
|
".ogv": "video/ogg",
|
||||||
|
".ogx": "application/ogg",
|
||||||
|
".one": "application/onenote",
|
||||||
|
".onea": "application/onenote",
|
||||||
|
".onepkg": "application/onenote",
|
||||||
|
".onetmp": "application/onenote",
|
||||||
|
".onetoc": "application/onenote",
|
||||||
|
".onetoc2": "application/onenote",
|
||||||
|
".opus": "audio/ogg",
|
||||||
|
".orderedtest": "application/xml",
|
||||||
|
".osdx": "application/opensearchdescription+xml",
|
||||||
|
".otf": "application/font-sfnt",
|
||||||
|
".otg": "application/vnd.oasis.opendocument.graphics-template",
|
||||||
|
".oth": "application/vnd.oasis.opendocument.text-web",
|
||||||
|
".otp": "application/vnd.oasis.opendocument.presentation-template",
|
||||||
|
".ots": "application/vnd.oasis.opendocument.spreadsheet-template",
|
||||||
|
".ott": "application/vnd.oasis.opendocument.text-template",
|
||||||
|
".oxt": "application/vnd.openofficeorg.extension",
|
||||||
|
".p10": "application/pkcs10",
|
||||||
|
".p12": "application/x-pkcs12",
|
||||||
|
".p7b": "application/x-pkcs7-certificates",
|
||||||
|
".p7c": "application/pkcs7-mime",
|
||||||
|
".p7m": "application/pkcs7-mime",
|
||||||
|
".p7r": "application/x-pkcs7-certreqresp",
|
||||||
|
".p7s": "application/pkcs7-signature",
|
||||||
|
".pbm": "image/x-portable-bitmap",
|
||||||
|
".pcast": "application/x-podcast",
|
||||||
|
".pct": "image/pict",
|
||||||
|
".pcx": "application/octet-stream",
|
||||||
|
".pcz": "application/octet-stream",
|
||||||
|
".pdf": "application/pdf",
|
||||||
|
".pfb": "application/octet-stream",
|
||||||
|
".pfm": "application/octet-stream",
|
||||||
|
".pfx": "application/x-pkcs12",
|
||||||
|
".pgm": "image/x-portable-graymap",
|
||||||
|
".pic": "image/pict",
|
||||||
|
".pict": "image/pict",
|
||||||
|
".pkgdef": "text/plain",
|
||||||
|
".pkgundef": "text/plain",
|
||||||
|
".pko": "application/vnd.ms-pki.pko",
|
||||||
|
".pls": "audio/scpls",
|
||||||
|
".pma": "application/x-perfmon",
|
||||||
|
".pmc": "application/x-perfmon",
|
||||||
|
".pml": "application/x-perfmon",
|
||||||
|
".pmr": "application/x-perfmon",
|
||||||
|
".pmw": "application/x-perfmon",
|
||||||
|
".png": "image/png",
|
||||||
|
".pnm": "image/x-portable-anymap",
|
||||||
|
".pnt": "image/x-macpaint",
|
||||||
|
".pntg": "image/x-macpaint",
|
||||||
|
".pnz": "image/png",
|
||||||
|
".pot": "application/vnd.ms-powerpoint",
|
||||||
|
".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
|
||||||
|
".potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
|
||||||
|
".ppa": "application/vnd.ms-powerpoint",
|
||||||
|
".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
|
||||||
|
".ppm": "image/x-portable-pixmap",
|
||||||
|
".pps": "application/vnd.ms-powerpoint",
|
||||||
|
".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
||||||
|
".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
||||||
|
".ppt": "application/vnd.ms-powerpoint",
|
||||||
|
".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
||||||
|
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||||
|
".prf": "application/pics-rules",
|
||||||
|
".prm": "application/octet-stream",
|
||||||
|
".prx": "application/octet-stream",
|
||||||
|
".ps": "application/postscript",
|
||||||
|
".psc1": "application/PowerShell",
|
||||||
|
".psd": "application/octet-stream",
|
||||||
|
".psess": "application/xml",
|
||||||
|
".psm": "application/octet-stream",
|
||||||
|
".psp": "application/octet-stream",
|
||||||
|
".pst": "application/vnd.ms-outlook",
|
||||||
|
".pub": "application/x-mspublisher",
|
||||||
|
".pwz": "application/vnd.ms-powerpoint",
|
||||||
|
".qht": "text/x-html-insertion",
|
||||||
|
".qhtm": "text/x-html-insertion",
|
||||||
|
".qt": "video/quicktime",
|
||||||
|
".qti": "image/x-quicktime",
|
||||||
|
".qtif": "image/x-quicktime",
|
||||||
|
".qtl": "application/x-quicktimeplayer",
|
||||||
|
".qxd": "application/octet-stream",
|
||||||
|
".ra": "audio/x-pn-realaudio",
|
||||||
|
".ram": "audio/x-pn-realaudio",
|
||||||
|
".rar": "application/x-rar-compressed",
|
||||||
|
".ras": "image/x-cmu-raster",
|
||||||
|
".rat": "application/rat-file",
|
||||||
|
".rc": "text/plain",
|
||||||
|
".rc2": "text/plain",
|
||||||
|
".rct": "text/plain",
|
||||||
|
".rdlc": "application/xml",
|
||||||
|
".reg": "text/plain",
|
||||||
|
".resx": "application/xml",
|
||||||
|
".rf": "image/vnd.rn-realflash",
|
||||||
|
".rgb": "image/x-rgb",
|
||||||
|
".rgs": "text/plain",
|
||||||
|
".rm": "application/vnd.rn-realmedia",
|
||||||
|
".rmi": "audio/mid",
|
||||||
|
".rmp": "application/vnd.rn-rn_music_package",
|
||||||
|
".roff": "application/x-troff",
|
||||||
|
".rpm": "audio/x-pn-realaudio-plugin",
|
||||||
|
".rqy": "text/x-ms-rqy",
|
||||||
|
".rtf": "application/rtf",
|
||||||
|
".rtx": "text/richtext",
|
||||||
|
".rvt": "application/octet-stream",
|
||||||
|
".ruleset": "application/xml",
|
||||||
|
".s": "text/plain",
|
||||||
|
".safariextz": "application/x-safari-safariextz",
|
||||||
|
".scd": "application/x-msschedule",
|
||||||
|
".scr": "text/plain",
|
||||||
|
".sct": "text/scriptlet",
|
||||||
|
".sd2": "audio/x-sd2",
|
||||||
|
".sdp": "application/sdp",
|
||||||
|
".sea": "application/octet-stream",
|
||||||
|
".searchConnector-ms": "application/windows-search-connector+xml",
|
||||||
|
".setpay": "application/set-payment-initiation",
|
||||||
|
".setreg": "application/set-registration-initiation",
|
||||||
|
".settings": "application/xml",
|
||||||
|
".sgimb": "application/x-sgimb",
|
||||||
|
".sgml": "text/sgml",
|
||||||
|
".sh": "application/x-sh",
|
||||||
|
".shar": "application/x-shar",
|
||||||
|
".shtml": "text/html",
|
||||||
|
".sit": "application/x-stuffit",
|
||||||
|
".sitemap": "application/xml",
|
||||||
|
".skin": "application/xml",
|
||||||
|
".skp": "application/x-koan",
|
||||||
|
".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
|
||||||
|
".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
|
||||||
|
".slk": "application/vnd.ms-excel",
|
||||||
|
".sln": "text/plain",
|
||||||
|
".slupkg-ms": "application/x-ms-license",
|
||||||
|
".smd": "audio/x-smd",
|
||||||
|
".smi": "application/octet-stream",
|
||||||
|
".smx": "audio/x-smd",
|
||||||
|
".smz": "audio/x-smd",
|
||||||
|
".snd": "audio/basic",
|
||||||
|
".snippet": "application/xml",
|
||||||
|
".snp": "application/octet-stream",
|
||||||
|
".sol": "text/plain",
|
||||||
|
".sor": "text/plain",
|
||||||
|
".spc": "application/x-pkcs7-certificates",
|
||||||
|
".spl": "application/futuresplash",
|
||||||
|
".spx": "audio/ogg",
|
||||||
|
".src": "application/x-wais-source",
|
||||||
|
".srf": "text/plain",
|
||||||
|
".SSISDeploymentManifest": "text/xml",
|
||||||
|
".ssm": "application/streamingmedia",
|
||||||
|
".sst": "application/vnd.ms-pki.certstore",
|
||||||
|
".stl": "application/vnd.ms-pki.stl",
|
||||||
|
".sv4cpio": "application/x-sv4cpio",
|
||||||
|
".sv4crc": "application/x-sv4crc",
|
||||||
|
".svc": "application/xml",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".swf": "application/x-shockwave-flash",
|
||||||
|
".step": "application/step",
|
||||||
|
".stp": "application/step",
|
||||||
|
".t": "application/x-troff",
|
||||||
|
".tar": "application/x-tar",
|
||||||
|
".tcl": "application/x-tcl",
|
||||||
|
".testrunconfig": "application/xml",
|
||||||
|
".testsettings": "application/xml",
|
||||||
|
".tex": "application/x-tex",
|
||||||
|
".texi": "application/x-texinfo",
|
||||||
|
".texinfo": "application/x-texinfo",
|
||||||
|
".tgz": "application/x-compressed",
|
||||||
|
".thmx": "application/vnd.ms-officetheme",
|
||||||
|
".thn": "application/octet-stream",
|
||||||
|
".tif": "image/tiff",
|
||||||
|
".tiff": "image/tiff",
|
||||||
|
".tlh": "text/plain",
|
||||||
|
".tli": "text/plain",
|
||||||
|
".toc": "application/octet-stream",
|
||||||
|
".tr": "application/x-troff",
|
||||||
|
".trm": "application/x-msterminal",
|
||||||
|
".trx": "application/xml",
|
||||||
|
".ts": "video/vnd.dlna.mpeg-tts",
|
||||||
|
".tsv": "text/tab-separated-values",
|
||||||
|
".ttf": "application/font-sfnt",
|
||||||
|
".tts": "video/vnd.dlna.mpeg-tts",
|
||||||
|
".txt": "text/plain",
|
||||||
|
".u32": "application/octet-stream",
|
||||||
|
".uls": "text/iuls",
|
||||||
|
".user": "text/plain",
|
||||||
|
".ustar": "application/x-ustar",
|
||||||
|
".vb": "text/plain",
|
||||||
|
".vbdproj": "text/plain",
|
||||||
|
".vbk": "video/mpeg",
|
||||||
|
".vbproj": "text/plain",
|
||||||
|
".vbs": "text/vbscript",
|
||||||
|
".vcf": "text/x-vcard",
|
||||||
|
".vcproj": "application/xml",
|
||||||
|
".vcs": "text/plain",
|
||||||
|
".vcxproj": "application/xml",
|
||||||
|
".vddproj": "text/plain",
|
||||||
|
".vdp": "text/plain",
|
||||||
|
".vdproj": "text/plain",
|
||||||
|
".vdx": "application/vnd.ms-visio.viewer",
|
||||||
|
".vml": "text/xml",
|
||||||
|
".vscontent": "application/xml",
|
||||||
|
".vsct": "text/xml",
|
||||||
|
".vsd": "application/vnd.visio",
|
||||||
|
".vsi": "application/ms-vsi",
|
||||||
|
".vsix": "application/vsix",
|
||||||
|
".vsixlangpack": "text/xml",
|
||||||
|
".vsixmanifest": "text/xml",
|
||||||
|
".vsmdi": "application/xml",
|
||||||
|
".vspscc": "text/plain",
|
||||||
|
".vss": "application/vnd.visio",
|
||||||
|
".vsscc": "text/plain",
|
||||||
|
".vssettings": "text/xml",
|
||||||
|
".vssscc": "text/plain",
|
||||||
|
".vst": "application/vnd.visio",
|
||||||
|
".vstemplate": "text/xml",
|
||||||
|
".vsto": "application/x-ms-vsto",
|
||||||
|
".vsw": "application/vnd.visio",
|
||||||
|
".vsx": "application/vnd.visio",
|
||||||
|
".vtx": "application/vnd.visio",
|
||||||
|
".wav": "audio/wav",
|
||||||
|
".wave": "audio/wav",
|
||||||
|
".wax": "audio/x-ms-wax",
|
||||||
|
".wbk": "application/msword",
|
||||||
|
".wbmp": "image/vnd.wap.wbmp",
|
||||||
|
".wcm": "application/vnd.ms-works",
|
||||||
|
".wdb": "application/vnd.ms-works",
|
||||||
|
".wdp": "image/vnd.ms-photo",
|
||||||
|
".webarchive": "application/x-safari-webarchive",
|
||||||
|
".webm": "video/webm",
|
||||||
|
".webp": "image/webp", /* https"://en.wikipedia.org/wiki/WebP */
|
||||||
|
".webtest": "application/xml",
|
||||||
|
".wiq": "application/xml",
|
||||||
|
".wiz": "application/msword",
|
||||||
|
".wks": "application/vnd.ms-works",
|
||||||
|
".WLMP": "application/wlmoviemaker",
|
||||||
|
".wlpginstall": "application/x-wlpg-detect",
|
||||||
|
".wlpginstall3": "application/x-wlpg3-detect",
|
||||||
|
".wm": "video/x-ms-wm",
|
||||||
|
".wma": "audio/x-ms-wma",
|
||||||
|
".wmd": "application/x-ms-wmd",
|
||||||
|
".wmf": "application/x-msmetafile",
|
||||||
|
".wml": "text/vnd.wap.wml",
|
||||||
|
".wmlc": "application/vnd.wap.wmlc",
|
||||||
|
".wmls": "text/vnd.wap.wmlscript",
|
||||||
|
".wmlsc": "application/vnd.wap.wmlscriptc",
|
||||||
|
".wmp": "video/x-ms-wmp",
|
||||||
|
".wmv": "video/x-ms-wmv",
|
||||||
|
".wmx": "video/x-ms-wmx",
|
||||||
|
".wmz": "application/x-ms-wmz",
|
||||||
|
".woff": "application/font-woff",
|
||||||
|
".wpl": "application/vnd.ms-wpl",
|
||||||
|
".wps": "application/vnd.ms-works",
|
||||||
|
".wri": "application/x-mswrite",
|
||||||
|
".wrl": "x-world/x-vrml",
|
||||||
|
".wrz": "x-world/x-vrml",
|
||||||
|
".wsc": "text/scriptlet",
|
||||||
|
".wsdl": "text/xml",
|
||||||
|
".wvx": "video/x-ms-wvx",
|
||||||
|
".x": "application/directx",
|
||||||
|
".xaf": "x-world/x-vrml",
|
||||||
|
".xaml": "application/xaml+xml",
|
||||||
|
".xap": "application/x-silverlight-app",
|
||||||
|
".xbap": "application/x-ms-xbap",
|
||||||
|
".xbm": "image/x-xbitmap",
|
||||||
|
".xdr": "text/plain",
|
||||||
|
".xht": "application/xhtml+xml",
|
||||||
|
".xhtml": "application/xhtml+xml",
|
||||||
|
".xla": "application/vnd.ms-excel",
|
||||||
|
".xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
|
||||||
|
".xlc": "application/vnd.ms-excel",
|
||||||
|
".xld": "application/vnd.ms-excel",
|
||||||
|
".xlk": "application/vnd.ms-excel",
|
||||||
|
".xll": "application/vnd.ms-excel",
|
||||||
|
".xlm": "application/vnd.ms-excel",
|
||||||
|
".xls": "application/vnd.ms-excel",
|
||||||
|
".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
||||||
|
".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
|
||||||
|
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
".xlt": "application/vnd.ms-excel",
|
||||||
|
".xltm": "application/vnd.ms-excel.template.macroEnabled.12",
|
||||||
|
".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
||||||
|
".xlw": "application/vnd.ms-excel",
|
||||||
|
".xml": "text/xml",
|
||||||
|
".xmp": "application/octet-stream",
|
||||||
|
".xmta": "application/xml",
|
||||||
|
".xof": "x-world/x-vrml",
|
||||||
|
".XOML": "text/plain",
|
||||||
|
".xpm": "image/x-xpixmap",
|
||||||
|
".xps": "application/vnd.ms-xpsdocument",
|
||||||
|
".xrm-ms": "text/xml",
|
||||||
|
".xsc": "application/xml",
|
||||||
|
".xsd": "text/xml",
|
||||||
|
".xsf": "text/xml",
|
||||||
|
".xsl": "text/xml",
|
||||||
|
".xslt": "text/xml",
|
||||||
|
".xsn": "application/octet-stream",
|
||||||
|
".xss": "application/xml",
|
||||||
|
".xspf": "application/xspf+xml",
|
||||||
|
".xtp": "application/octet-stream",
|
||||||
|
".xwd": "image/x-xwindowdump",
|
||||||
|
".z": "application/x-compress",
|
||||||
|
".zip": "application/zip"}
|
||||||
|
|
||||||
|
if mimeType, ok := mimeMap[extension]; ok {
|
||||||
|
return mimeType
|
||||||
|
} else {
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
}
|
26
rest/util_network.go
Normal file
26
rest/util_network.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//根据一个请求,获取ip.
|
||||||
|
func GetIpAddress(r *http.Request) string {
|
||||||
|
var ipAddress string
|
||||||
|
|
||||||
|
ipAddress = r.RemoteAddr
|
||||||
|
|
||||||
|
if ipAddress != "" {
|
||||||
|
ipAddress = strings.Split(ipAddress, ":")[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} {
|
||||||
|
for _, ip := range strings.Split(r.Header.Get(h), ",") {
|
||||||
|
if ip != "" {
|
||||||
|
ipAddress = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ipAddress
|
||||||
|
}
|
138
rest/util_path.go
Normal file
138
rest/util_path.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
//判断文件或文件夹是否已经存在
|
||||||
|
func PathExists(path string) (bool, error) {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取该应用可执行文件的位置。
|
||||||
|
//例如:C:\Users\lishuang\AppData\Local\Temp
|
||||||
|
func GetHomePath() string {
|
||||||
|
ex, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
exPath := filepath.Dir(ex)
|
||||||
|
return exPath
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取前端静态资源的位置。如果你在开发模式下,可以将这里直接返回tank/build下面的html路径。
|
||||||
|
//例如:C:/Users/lishuang/AppData/Local/Temp/html
|
||||||
|
func GetHtmlPath() string {
|
||||||
|
|
||||||
|
homePath := GetHomePath()
|
||||||
|
filePath := homePath + "/html"
|
||||||
|
exists, err := PathExists(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("判断上传文件是否存在时出错!")
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
err = os.MkdirAll(filePath, 0777)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建上传文件夹时出错!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取上传文件存放的位置。
|
||||||
|
//例如:C:\Users\lishuang\AppData\Local\Temp/matter
|
||||||
|
func GetFilePath() string {
|
||||||
|
|
||||||
|
homePath := GetHomePath()
|
||||||
|
filePath := homePath + "/matter"
|
||||||
|
exists, err := PathExists(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("判断上传文件是否存在时出错!")
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
err = os.MkdirAll(filePath, 0777)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建上传文件夹时出错!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取日志存放的位置。
|
||||||
|
//例如:C:\Users\lishuang\AppData\Local\Temp/log
|
||||||
|
func GetLogPath() string {
|
||||||
|
|
||||||
|
homePath := GetHomePath()
|
||||||
|
filePath := homePath + "/log"
|
||||||
|
exists, err := PathExists(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("判断日志文件夹是否存在时出错!")
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
err = os.MkdirAll(filePath, 0666)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建日志文件夹时出错!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取配置文件存放的位置
|
||||||
|
//例如:C:\Users\lishuang\AppData\Local\Temp/conf
|
||||||
|
func GetConfPath() string {
|
||||||
|
|
||||||
|
homePath := GetHomePath()
|
||||||
|
filePath := homePath + "/conf"
|
||||||
|
exists, err := PathExists(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("判断日志文件夹是否存在时出错!")
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
err = os.MkdirAll(filePath, 0666)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建日志文件夹时出错!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取某个用户文件应该存放的位置。这个是相对GetFilePath的路径
|
||||||
|
//例如:/zicla/2006-01-02/1510122428000
|
||||||
|
func GetUserFilePath(username string) (string, string) {
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
datePath := now.Format("2006-01-02")
|
||||||
|
//毫秒时间戳
|
||||||
|
timestamp := now.UnixNano() / 1e6
|
||||||
|
|
||||||
|
filePath := GetFilePath()
|
||||||
|
absolutePath := fmt.Sprintf("%s/%s/%s/%d", filePath, username, datePath, timestamp)
|
||||||
|
relativePath := fmt.Sprintf("/%s/%s/%d", username, datePath, timestamp)
|
||||||
|
|
||||||
|
exists, err := PathExists(absolutePath)
|
||||||
|
if err != nil {
|
||||||
|
panic("判断上传文件是否存在时出错!")
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
err = os.MkdirAll(absolutePath, 0777)
|
||||||
|
if err != nil {
|
||||||
|
panic("创建上传文件夹时出错!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return absolutePath, relativePath
|
||||||
|
}
|
115
rest/web_result.go
Normal file
115
rest/web_result.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
type WebResult struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WebResult) Error() string {
|
||||||
|
return this.Msg
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
//正常
|
||||||
|
RESULT_CODE_OK = 200
|
||||||
|
|
||||||
|
//未登录
|
||||||
|
RESULT_CODE_LOGIN = -400
|
||||||
|
|
||||||
|
//没有权限
|
||||||
|
RESULT_CODE_UNAUTHORIZED = -401
|
||||||
|
|
||||||
|
//请求错误
|
||||||
|
RESULT_CODE_BAD_REQUEST = -402
|
||||||
|
|
||||||
|
//没有找到
|
||||||
|
RESULT_CODE_NOT_FOUND = -404
|
||||||
|
|
||||||
|
//登录过期
|
||||||
|
RESULT_CODE_LOGIN_EXPIRED = -405
|
||||||
|
|
||||||
|
//该登录用户不是有效用户
|
||||||
|
RESULT_CODE_LOGIN_INVALID = -406
|
||||||
|
|
||||||
|
//提交的表单验证不通过
|
||||||
|
RESULT_CODE_FORM_INVALID = -410
|
||||||
|
|
||||||
|
//请求太频繁
|
||||||
|
RESULT_CODE_FREQUENCY = -420
|
||||||
|
|
||||||
|
//服务器出错。
|
||||||
|
RESULT_CODE_SERVER_ERROR = -500
|
||||||
|
|
||||||
|
//远程服务不可用
|
||||||
|
RESULT_CODE_NOT_AVAILABLE = -501
|
||||||
|
|
||||||
|
//并发异常
|
||||||
|
RESULT_CODE_CONCURRENCY = -511
|
||||||
|
|
||||||
|
//远程微服务没有找到
|
||||||
|
RESULT_CODE_SERVICE_NOT_FOUND = -600
|
||||||
|
|
||||||
|
//远程微服务连接超时
|
||||||
|
RESULT_CODE_SERVICE_TIME_OUT = -610
|
||||||
|
|
||||||
|
//通用的异常
|
||||||
|
RESULT_CODE_UTIL_EXCEPTION = -700
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConstWebResult(code int) *WebResult {
|
||||||
|
|
||||||
|
wr := &WebResult{}
|
||||||
|
switch code {
|
||||||
|
//正常
|
||||||
|
case RESULT_CODE_OK:
|
||||||
|
wr.Msg = "成功"
|
||||||
|
//未登录
|
||||||
|
case RESULT_CODE_LOGIN:
|
||||||
|
wr.Msg = "没有登录,禁止访问"
|
||||||
|
//没有权限
|
||||||
|
case RESULT_CODE_UNAUTHORIZED:
|
||||||
|
wr.Msg = "没有权限"
|
||||||
|
//请求错误
|
||||||
|
case RESULT_CODE_BAD_REQUEST:
|
||||||
|
wr.Msg = "请求错误"
|
||||||
|
//没有找到
|
||||||
|
case RESULT_CODE_NOT_FOUND:
|
||||||
|
wr.Msg = "没有找到"
|
||||||
|
//登录过期
|
||||||
|
case RESULT_CODE_LOGIN_EXPIRED:
|
||||||
|
wr.Msg = "登录过期"
|
||||||
|
|
||||||
|
//该登录用户不是有效用户
|
||||||
|
case RESULT_CODE_LOGIN_INVALID:
|
||||||
|
wr.Msg = "该登录用户不是有效用户"
|
||||||
|
|
||||||
|
//提交的表单验证不通过
|
||||||
|
case RESULT_CODE_FORM_INVALID:
|
||||||
|
wr.Msg = "提交的表单验证不通过"
|
||||||
|
//请求太频繁
|
||||||
|
case RESULT_CODE_FREQUENCY:
|
||||||
|
wr.Msg = "请求太频繁"
|
||||||
|
//服务器出错。
|
||||||
|
case RESULT_CODE_SERVER_ERROR:
|
||||||
|
wr.Msg = "服务器出错"
|
||||||
|
//远程服务不可用
|
||||||
|
case RESULT_CODE_NOT_AVAILABLE:
|
||||||
|
wr.Msg = "远程服务不可用"
|
||||||
|
//并发异常
|
||||||
|
case RESULT_CODE_CONCURRENCY:
|
||||||
|
wr.Msg = "并发异常"
|
||||||
|
//远程微服务没有找到
|
||||||
|
case RESULT_CODE_SERVICE_NOT_FOUND:
|
||||||
|
wr.Msg = "远程微服务没有找到"
|
||||||
|
//远程微服务连接超时
|
||||||
|
case RESULT_CODE_SERVICE_TIME_OUT:
|
||||||
|
wr.Msg = "远程微服务连接超时"
|
||||||
|
default:
|
||||||
|
code = RESULT_CODE_UTIL_EXCEPTION
|
||||||
|
wr.Msg = "服务器未知错误"
|
||||||
|
}
|
||||||
|
wr.Code = code
|
||||||
|
return wr
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user