Commit a291ed84 authored by zhangxiao's avatar zhangxiao

create

parent 2c62c68d
Pipeline #54 failed with stages

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

resources/
logs/
exhibitioncentre
*.rdb
__debug_bin
\ No newline at end of file
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}/main.go",
"env": {},
"args": []
}
]
}
\ No newline at end of file
# exhibition Centre
## 展馆后台
* resources目录放置展馆资源
* logs目录放置日志文件
* config目录放置服务器配置文件
deploy目录下
exhibition.service
放在/lib/systemd/system/目录下
之后执行命令
sudo systemctl daemon-reload
后续操作
# 启动服务
sudo systemctl start exhibition.service
# 重启服务
sudo systemctl restart exhibition.service
# 停止服务
sudo systemctl stop exhibition.service
# 查看启动后系统log
查看最新的100行log
journalctl -u exhibition.service | tail -n 100
## nginx
所在目录
/usr/local/nginx-1.20.2
重新加载nginx.conf
在/usr/local/nginx-1.20.2/sbin/目录下执行
./nginx -s reload
或者使用命令 ps -ef | grep nginx 查看nginx进程
kill -9 进程号
然后在/usr/local/nginx-1.20.2/sbin/目录下执行
./nginx重启nginx
## redis
/etc/redis/redis.conf
## 阿里云
### oss下载
https://chenlingyun-3dzhanting.oss-cn-beijing.aliyuncs.com/10.jpg?x-oss-process=image/resize,w_512,limit_0
\ No newline at end of file
package app
import (
"exhibitionCentre/cache"
"exhibitionCentre/config"
"exhibitionCentre/logging"
_ "exhibitionCentre/models"
"exhibitionCentre/utils"
"io"
"io/ioutil"
"net/http"
)
func init() {
}
func Run() {
// read net config
port := config.Config.App.HttpPort
netType := config.Config.App.NetType
if len(netType) == 0 || len(port) == 0 {
logging.Log.Fatal("Read net config info failed.")
return
}
address := "0.0.0.0:" + port
chRunning := make(chan bool, 1)
switch netType {
case "http":
go runHttp(address, chRunning)
case "https":
go runHttps(address, chRunning)
}
<-chRunning
// 关闭缓存redis
cache.Close()
}
func AddRouter(routerPath string, method func(data []byte) (int, []byte)) {
http.HandleFunc(routerPath, func(w http.ResponseWriter, r *http.Request) {
// w.Header().Add("Access-Control-Allow-Origin", "*")
// w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
// w.Header().Add("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Authorization, X-Requested-With")
// read request body data
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
if err != nil {
logging.Log.Error("Read request body failed:", routerPath, err)
utils.SendResponse(w, 500, []byte("Read request data failed."))
return
}
// execute api method
statusCode, responseData := method(body)
utils.SendResponse(w, statusCode, responseData)
})
}
func runHttps(address string, ch chan bool) {
server_crt, server_private_key := certificate()
if len(server_crt) == 0 || len(server_private_key) == 0 {
logging.Log.Fatal("Read certificate config info failed.")
return
}
if err := http.ListenAndServeTLS(address, server_crt, server_private_key, nil); err != nil {
logging.Log.Error("ListenAndServeTLS: %s", err.Error())
ch <- true
}
}
func runHttp(address string, ch chan bool) {
if err := http.ListenAndServe(address, nil); err != nil {
logging.Log.Error("ListenAndServe: %s", err.Error())
ch <- true
}
}
func certificate() (string, string) {
server_crt := config.Config.Certificate.ServerCrt
server_private_key := config.Config.Certificate.ServerPrivateKey
return server_crt, server_private_key
}
package base
import "net/http"
type Router struct {
Writer http.ResponseWriter
Req *http.Request
Data []byte
}
/*
* @Author: ZXGoto
* @Date: 2019-10-30
*/
package cache
import (
"exhibitionCentre/config"
"exhibitionCentre/logging"
"fmt"
"time"
"github.com/gomodule/redigo/redis"
)
var (
redisClient *Redis
)
// init - initializes the redis db
func init() {
config := &RedisConfig{
MaxIdle: config.Config.Redis.MaxIdle,
MaxActive: config.Config.Redis.MaxActive,
IdleTimeout: time.Duration(config.Config.Redis.IdleTimeout),
Address: config.Config.Redis.Address,
Password: config.Config.Redis.Password,
DialReadTimeout: config.Config.Redis.DialReadTimeout,
DialWriteTimeout: config.Config.Redis.DialWriteTimeout,
DialConnectTimeout: config.Config.Redis.DialConnectTimeout,
DB: config.Config.Redis.Database,
}
redisClient = NewRedis(config)
logging.Log.Info("初始化Redis完毕.")
}
// Close - closes the redis db
func Close() {
if redisClient == nil {
return
}
redisClient.Close()
logging.Log.Info("Redis关闭.")
}
// Stats - gets redis stats
func Stats() *redis.PoolStats {
if redisClient == nil {
return &redis.PoolStats{}
}
stats := redisClient.Stats()
return &stats
}
func CreateVerificationCode(email, code string) bool {
if redisClient == nil {
return false
}
key := fmt.Sprintf("verification_code:%s", email)
return redisClient.MultiCreate(func(conn redis.Conn) {
conn.Send("MULTI")
conn.Send("SET", key, code)
conn.Send("EXPIRE", key, 60*5)
})
}
func GetVerificationCode(email string) string {
if redisClient == nil {
return ""
}
key := fmt.Sprintf("verification_code:%s", email)
records, err := redis.Strings(redisClient.MultiGet(func(conn redis.Conn) {
conn.Send("MULTI")
conn.Send("GET", key)
}))
if err != nil {
logging.Log.Errorf("获取数据失败: %s\n", err.Error())
return ""
}
if len(records) > 0 {
return records[0]
}
return ""
}
func DeleteVerificationCode(email string) bool {
if redisClient == nil {
return false
}
key := fmt.Sprintf("verification_code:%s", email)
return redisClient.Delete(key)
}
/*
* @Author: ZXGoto
* @Date: 2019-10-30
*/
package cache
import (
"exhibitionCentre/logging"
"time"
"github.com/gomodule/redigo/redis"
)
// Redis - redis data
type Redis struct {
pool *redis.Pool
}
// RedisConfig - the config of redis
type RedisConfig struct {
MaxIdle int
MaxActive int
IdleTimeout time.Duration
Address string
Password string
DialReadTimeout int
DialWriteTimeout int
DialConnectTimeout int
DB int
}
// NewRedis - creates a redis instance
// config - the redis config
func NewRedis(config *RedisConfig) *Redis {
r := new(Redis)
r.pool = &redis.Pool{
MaxIdle: config.MaxIdle,
MaxActive: config.MaxActive,
IdleTimeout: time.Duration(config.IdleTimeout) * time.Millisecond,
Wait: true,
Dial: func() (redis.Conn, error) {
return redis.Dial(
"tcp",
config.Address,
redis.DialPassword(config.Password),
redis.DialReadTimeout(time.Duration(config.DialReadTimeout)*time.Millisecond),
redis.DialWriteTimeout(time.Duration(config.DialWriteTimeout)*time.Millisecond),
redis.DialConnectTimeout(time.Duration(config.DialConnectTimeout)*time.Millisecond),
redis.DialDatabase(config.DB),
)
},
}
return r
}
// Close - closes the redis
func (r *Redis) Close() {
if err := r.pool.Close(); err != nil {
logging.Log.Errorf("关闭redis pool失败: %s\n", err.Error())
}
}
// Stats - gets the stats of redis
func (r *Redis) Stats() redis.PoolStats {
return r.pool.Stats()
}
// MultiCreate - creates a record by using MULTI
// f - a function for transaction processing
func (r *Redis) MultiCreate(f func(redis.Conn)) bool {
conn := r.pool.Get()
defer conn.Close()
if f == nil {
return false
}
f(conn)
if _, err := conn.Do("EXEC"); err != nil {
logging.Log.Errorf("创建数据失败: %s\n", err.Error())
return false
}
return true
}
// Delete - deletes a record by key
// key - the record key
func (r *Redis) Delete(key string) bool {
conn := r.pool.Get()
defer conn.Close()
if _, err := conn.Do("DEL", key); err != nil {
logging.Log.Errorf("删除数据失败: %s\n", err.Error())
return false
}
return true
}
// GetKeys - gets all keys in the rootkey
// rootKey - the root node key
func (r *Redis) GetKeys(rootKey string) []string {
conn := r.pool.Get()
defer conn.Close()
result, err := conn.Do("KEYS", rootKey)
if err != nil {
logging.Log.Errorf("获取keys失败: %s\n", err.Error())
return nil
}
ks, ok := result.([]interface{})
if !ok {
logging.Log.Error(err.Error())
return nil
}
var keys []string
for _, k := range ks {
if bs, ok := k.([]uint8); ok {
keys = append(keys, string(bs))
}
}
return keys
}
// MultiGet - gets a record by using MULTI
// f - a function for transaction processing
func (r *Redis) MultiGet(f func(redis.Conn)) (interface{}, error) {
conn := r.pool.Get()
defer conn.Close()
if f == nil {
return nil, nil
}
f(conn)
return conn.Do("EXEC")
}
// ApplyDataInt - get-set a record by using WATCH
// key - the record key
// f - a function for transaction processing
func (r *Redis) ApplyDataInt(key string, f func(redis.Conn, string) int) int {
conn := r.pool.Get()
defer conn.Close()
for {
if _, err := conn.Do("WATCH", key); err != nil {
logging.Log.Errorf("redis watch key(%s)失败: %s\n", key, err.Error())
return 0
}
value, err := redis.String(conn.Do("GET", key))
if err != nil {
logging.Log.Errorf("redis获取key(%s)失败: %s\n", key, err.Error())
return 0
}
destQuantity := f(conn, value)
if destQuantity <= 0 {
return 0
}
result, err := conn.Do("EXEC")
if err != nil {
logging.Log.Errorf("redis设置key(%s)失败: %s\n", key, err.Error())
return 0
}
if result != nil {
return destQuantity
}
}
}
package config
import (
"encoding/json"
"io/ioutil"
"log"
)
var Config struct {
App AppConfig `json:"app"`
Mysql MysqlConfig `json:"mysql"`
Redis RedisConfig `json:"redis"`
Certificate CertificateConfig `json:"certificate"`
Log LogConfig `json:"log"`
Role RoleConfig `json:"role"`
Smtp SmtpConfig `json:"smtp"`
AliyunOss AliyunOssConfig `json:"aliyun_oss"`
Others OthersConfig `json:"others"`
}
type AppConfig struct {
AppName string `json:"appname"`
Issuer string `json:"issuer"`
HttpPort string `json:"httpport"`
NetType string `json:"net"`
Mode string `json:"mode"`
}
type MysqlConfig struct {
UserName string `json:"dbuser"`
Password string `json:"dbpwd"`
Database string `json:"dbname"`
Host string `json:"dbhost"`
MaxIdle int `json:"maxidle"`
MaxConn int `json:"maxconn"`
}
type RedisConfig struct {
MaxIdle int `json:"max_idle"`
MaxActive int `json:"max_active"`
IdleTimeout int `json:"idle_timeout"`
Address string `json:"address"`
Password string `json:"password"`
DialReadTimeout int `json:"dial_read_timeout"`
DialWriteTimeout int `json:"dial_write_timeout"`
DialConnectTimeout int `json:"dial_connect_timeout"`
Database int `json:"database"`
}
type CertificateConfig struct {
ServerCrt string `json:"server_crt"`
ServerPrivateKey string `json:"server_private_key"`
PasswordPrivateKey string `json:"pwd_private_key"`
JwtPrivatekey string `json:"jwt_private_key"`
}
type LogConfig struct {
Level string `json:"level"`
}
type RoleConfig struct {
Administrators []string `json:"administrators"`
Publishers []string `json:"publishers"`
}
type SmtpConfig struct {
FromEmail string `json:"fromemail"`
Host string `json:"host"`
Port int `json:"port"`
UserName string `json:"username"`
Password string `json:"password"`
}
type AliyunOssConfig struct {
RegionId string `json:"region_id"`
Endpoint string `json:"endpoint"`
AccessKeyId string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
Bucket string `json:"bucket"`
Arn string `json:"arn"` // 阿里云 角色 ARN值
}
type OthersConfig struct {
LoginUrl string `json:"manage_login_url"` // 管理后台登陆地址
}
func init() {
data, err := ioutil.ReadFile("./config/config.json")
if err != nil {
log.Fatalf("加载配置文件失败: %v", err)
}
err = json.Unmarshal(data, &Config)
if err != nil {
log.Fatalf("解析配置文件失败: %v", err)
}
}
{
"app": {
"appname": "ExhibitionCentre",
"issuer": "ZXGoto",
"httpport": "8888",
"net": "http",
"mode": "dev"
},
"mysql": {
"dbuser": "root",
"dbpwd": "0123456789",
"dbname": "exhibitioncentre",
"dbhost": "127.0.0.1:3306",
"maxidle": 30,
"maxconn": 30
},
"redis": {
"max_idle": 64,
"max_active": 256,
"idle_timeout": 2000,
"address": "127.0.0.1:6379",
"password": "123456",
"dial_read_timeout": 2000,
"dial_write_timeout": 2000,
"dial_connect_timeout": 2000,
"database": 1
},
"certificate": {
"server_crt": "keys/server.crt",
"server_private_key": "keys/server_private.key",
"pwd_private_key": "keys/pwd_private_key.pem",
"jwt_private_key": "keys/jwt_private_key.pem"
},
"log": {
"level": "DEBUG"
},
"role": {
"administrators": ["xsxhl@live.com"]
},
"smtp": {
"fromemail": "346202@qq.com",
"host": "smtp.qq.com",
"port": 465,
"username": "346202@qq.com",
"password": "jmvzyhoudqdrcbaf"
},
"aliyun_oss": {
"region_id": "cn-beijing",
"endpoint": "oss-cn-beijing.aliyuncs.com",
"access_key_id": "LTAI5t7nKC36Ys5SVfMiq8bt",
"access_key_secret": "hWZ1K7hRkYBkkTsvld8we660R8XGIp",
"bucket": "chenlingyun-3dzhanting",
"arn": "acs:ram::1455504107194244:role/ossuploader"
},
"others": {
"manage_login_url": "http://182.92.75.61/user/login"
}
}
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)
var ExhibitionConfig struct {
Styles map[string][]RoomInfo `json:"styles"`
PreviewPageSize int `json:"preview_page_size"`
PageSize int `json:"page_size"`
}
type RoomInfo struct {
Index int `json:"index"`
NumberOfPosition int `json:"number_of_position"`
}
func init() {
data, err := ioutil.ReadFile("./config/exhibition_config.json")
if err != nil {
log.Fatalf("加载配置文件失败: %v", err)
}
err = json.Unmarshal(data, &ExhibitionConfig)
if err != nil {
log.Fatalf("解析配置文件失败: %v", err)
}
}
func NumberOfPosition(style, roomIndex int) int {
styleKey := fmt.Sprintf("%d", style)
rooms, ok := ExhibitionConfig.Styles[styleKey]
if !ok {
return 0
}
for _, r := range rooms {
if r.Index == roomIndex {
return r.NumberOfPosition
}
}
return 0
}
{
"styles": {
"1": [
{
"index": 1,
"number_of_position": 3
},
{
"index": 2,
"number_of_position": 156
},
{
"index": 3,
"number_of_position": 15
}
],
"2": [
{
"index": 1,
"number_of_position": 3
},
{
"index": 2,
"number_of_position": 162
},
{
"index": 3,
"number_of_position": 15
}
]
},
"preview_page_size": 12,
"page_size": 12
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/utils"
"net/http"
"time"
)
func AliyunSts(router *base.Router) (int, []byte) {
// 鉴权,鉴权失败则需重新登陆
jwt, authorized := Authenticate(router)
if !authorized {
logging.Log.Error("获取sts令牌失败")
return 0, nil
}
tokenInfo := utils.GenerateStsToken(jwt.Email)
if tokenInfo == nil {
return 403, utils.SerializeErrorData("获取上传权限失败")
}
return 200, utils.Serialize(tokenInfo)
}
func SaveToken(token string, router *base.Router) {
cookie := http.Cookie{Name: "token", Value: token, HttpOnly: true, Secure: false, Path: "/", Expires: time.Now().Add(30 * 24 * time.Hour), MaxAge: 60 * 60 * 24 * 30}
http.SetCookie(router.Writer, &cookie)
}
func DeleteToken(router *base.Router) {
cookie := http.Cookie{Name: "token", Value: "", HttpOnly: true, Secure: false, Path: "/", Expires: time.Now().Add(30 * 24 * time.Hour), MaxAge: 60 * 60 * 24 * 30}
http.SetCookie(router.Writer, &cookie)
}
func Authenticate(router *base.Router) (*utils.JWTCustomClaims, bool) {
token, err := router.Req.Cookie("token")
if err != nil {
Relogin(router)
return nil, false
}
jwt := utils.ParseJWT(token.Value)
if jwt == nil {
Relogin(router)
return nil, false
}
if err := jwt.Valid(); err != nil {
Relogin(router)
return nil, false
}
return jwt, true
}
func LoginAuthenticate(router *base.Router) (string, bool) {
token, err := router.Req.Cookie("token")
if err != nil {
return "", false
}
jwt := utils.ParseJWT(token.Value)
if jwt == nil {
return "", false
}
if err := jwt.Valid(); err != nil {
return "", false
}
return jwt.Email, true
}
func Relogin(router *base.Router) {
DeleteToken(router)
Redirect(router, "/user/login")
}
func Redirect(router *base.Router, path string) {
http.Redirect(router.Writer, router.Req, path, http.StatusFound)
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/models"
"exhibitionCentre/utils"
)
// 展品详情消息
type ExhibitDetailRequest struct {
ID int `mapper:"id" json:"id"`
}
type ExhibitDetailResponse struct {
ID int `json:"id"` // 展品id
Title string `json:"title"` // 展品名称
AuthorIntroduction string `json:"author_introduction"` // 作者介绍
Audio string `json:"audio"` // 展品语音介绍
Introduction string `json:"introduction"` // 展品文字介绍
Details []models.ExhibitDetail `json:"details"` // 展品图文介绍
Likes int `json:"likes"` // 展品点赞数
Flowers int `json:"flowers"` // 展品送花数
Applauses int `json:"applauses"` // 展品鼓掌数
RoomIndex int `json:"room_index"` // 1为开幕式,2为展厅,3为演播厅
}
// 点赞消息
type ExhibitLikeRequest struct {
ID int `mapper:"id" json:"id"`
}
type ExhibitLikeResponse struct {
Count int `json:"count"`
}
// 送花消息
type ExhibitSendFlowerRequest struct {
ID int `mapper:"id" json:"id"`
}
type ExhibitSendFlowerResponse struct {
Count int `json:"count"`
}
// 鼓掌消息
type ExhibitGiveApplauseRequest struct {
ID int `mapper:"id" json:"id"`
}
type ExhibitGiveApplauseResponse struct {
Count int `json:"count"`
}
// 出价消息
type ExhibitOfferRequest struct {
ID int `json:"id"` // 展品id
UserName string `json:"username"` // 姓名
Phone string `json:"phone"` // 手机号
Bid int `json:"bid"` // 报价
}
// todo 测试
// 获取展位详情信息
func GetExhibitDetail(router *base.Router) (int, []byte) {
// 解析request数据
var request ExhibitDetailRequest
if err := utils.ParseQuery(router.Req, &request); err != nil {
logging.Log.Errorf("解析数据失败, err: %v\n", err.Error())
return 400, utils.SerializeErrorData("获取展品失败!")
}
// 数据库获取展品
exhibit, err := models.GetExhibit(request.ID)
if err != nil {
logging.Log.Errorf("数据库获取展品失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("获取展品失败!")
}
// 解析展品详情
var details []models.ExhibitDetail
if len(exhibit.Details) > 0 {
if err := utils.JsonParse([]byte(exhibit.Details), &details); err != nil {
logging.Log.Error("解析models.Exhibit.Details数据失败: ", err.Error())
return 400, utils.SerializeErrorData("获取展品失败!")
}
}
resp := ExhibitDetailResponse{
ID: int(exhibit.ID),
Title: exhibit.Title,
AuthorIntroduction: exhibit.AuthorIntroduction,
Audio: exhibit.Audio,
Introduction: exhibit.Introduction,
Likes: exhibit.Likes,
Flowers: exhibit.Flowers,
Applauses: exhibit.Applauses,
Details: details,
RoomIndex: exhibit.RoomIndex,
}
return 200, utils.Serialize(&resp)
}
// 点赞
func ExhibitLike(router *base.Router) (int, []byte) {
// 解析request数据
var request ExhibitLikeRequest
if err := utils.ParseQuery(router.Req, &request); err != nil {
logging.Log.Errorf("解析数据失败, err: %v\n", err.Error())
return 400, utils.SerializeErrorData("点赞失败!")
}
// 数据库获取展品
exhibit, err := models.GetExhibit(request.ID)
if err != nil {
logging.Log.Errorf("数据库获取展品失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("点赞失败!")
}
// 数据库获取展览
exhibition, err := models.GetExhibition(int(exhibit.ExhibitionId))
if err != nil {
logging.Log.Errorf("数据库获取展览失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("点赞失败!")
}
exhibit.Likes += 1
exhibition.Likes += 1
models.UpdateExhibit(exhibit)
models.UpdateExhibition(exhibition)
resp := ExhibitLikeResponse{
Count: exhibit.Likes,
}
return 200, utils.Serialize(&resp)
}
// 送花
func ExhibitSendFlower(router *base.Router) (int, []byte) {
// 解析request数据
var request ExhibitSendFlowerRequest
if err := utils.ParseQuery(router.Req, &request); err != nil {
logging.Log.Errorf("解析数据失败, err: %v\n", err.Error())
return 400, utils.SerializeErrorData("参数错误!")
}
// 数据库获取展品
exhibit, err := models.GetExhibit(request.ID)
if err != nil {
logging.Log.Errorf("数据库获取展品失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("送花失败!")
}
// 数据库获取展览
exhibition, err := models.GetExhibition(int(exhibit.ExhibitionId))
if err != nil {
logging.Log.Errorf("数据库获取展览失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("送花失败!")
}
exhibit.Flowers += 1
exhibition.Flowers += 1
models.UpdateExhibit(exhibit)
models.UpdateExhibition(exhibition)
resp := ExhibitSendFlowerResponse{
Count: exhibit.Flowers,
}
return 200, utils.Serialize(&resp)
}
// 鼓掌
func ExhibitGiveApplause(router *base.Router) (int, []byte) {
// 解析request数据
var request ExhibitGiveApplauseRequest
if err := utils.ParseQuery(router.Req, &request); err != nil {
logging.Log.Errorf("解析数据失败, err: %v\n", err.Error())
return 400, utils.SerializeErrorData("鼓掌失败!")
}
// 数据库获取展品
exhibit, err := models.GetExhibit(request.ID)
if err != nil {
logging.Log.Errorf("数据库获取展品失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("鼓掌失败!")
}
// 数据库获取展览
exhibition, err := models.GetExhibition(int(exhibit.ExhibitionId))
if err != nil {
logging.Log.Errorf("数据库获取展览失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("鼓掌失败!")
}
exhibit.Applauses += 1
exhibition.Applauses += 1
models.UpdateExhibit(exhibit)
models.UpdateExhibition(exhibition)
resp := ExhibitGiveApplauseResponse{
Count: exhibit.Applauses,
}
return 200, utils.Serialize(&resp)
}
// 出价
func ExhibitOffer(router *base.Router) (int, []byte) {
// 解析request数据
var info ExhibitOfferRequest
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 400, utils.SerializeErrorData("出价失败!")
}
// 数据库获取展品
exhibit, err := models.GetExhibit(info.ID)
if err != nil {
logging.Log.Errorf("数据库获取展品失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("出价失败!")
}
// 构造订单
order := models.Order{
UserName: info.UserName,
Phone: info.Phone,
Price: info.Bid,
ExhibitId: exhibit.ID,
ExhibitionId: exhibit.ExhibitionId,
}
// 数据库保存订单
if err := models.CreateOrder(&order); err != nil {
logging.Log.Errorf("数据库创建展品订单失败: %v\n", err.Error())
return 400, utils.SerializeErrorData("出价失败!")
}
return 200, []byte("{}")
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/models"
"exhibitionCentre/utils"
"mvdan.cc/xurls/v2"
)
type EditExhibitRequest struct {
ID int `json:"id"` // 展位id
}
type DeleteExhibitRequest struct {
ID int `json:"id"` // 展位id
}
// 更新展品消息
type UpdateExhibitRequest struct {
ExhibitionId int `json:"exhibition_id"` // 展览id
RoomIndex int `json:"room_index"` // 展馆编号 1为开幕式 2为展厅 3为演播厅
Number int `json:"number"` // 展位编号
Url string `json:"url"` // 展品下载地址
Width float32 `json:"width"` // 展品宽度
Height float32 `json:"height"` // 展品高度
OffsetX float32 `json:"offset_x"` // 展品展位横向微调
OffsetY float32 `json:"offset_y"` // 展品展位纵向微调
StayTime int `json:"stay_time"` // 展品停留时间
// 详情
Title string `json:"title"` // 详情标题
Audio string `json:"audio"` // 音频介绍
Introduction string `json:"introduction"` // 文字介绍
Details string `json:"details"` // 图文详解
AuthorIntroduction string `json:"author_introduction"` // 作者介绍
}
func EditExhibit(router *base.Router) (int, []byte) {
// 鉴权
_, authorized := Authenticate(router)
if !authorized {
logging.Log.Error("编辑展位鉴权失败")
return 0, nil
}
// 解析request数据
var info EditExhibitRequest
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("编辑展位失败!")
}
// 获取展位
exhibit, err := models.GetExhibit(info.ID)
if err != nil {
logging.Log.Error("数据库获取展位失败: ", err.Error())
return 403, utils.SerializeErrorData("编辑展位失败!")
}
return 200, utils.Serialize(exhibit)
}
func UpdateExhibit(router *base.Router) (int, []byte) {
// 鉴权
_, authorized := Authenticate(router)
if !authorized {
logging.Log.Error("编辑展位鉴权失败")
return 0, nil
}
// 解析request数据
var info UpdateExhibitRequest
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("编辑展位失败!")
}
// 获取展览
exhibit, _ := models.GetExhibitByNumber(info.ExhibitionId, info.RoomIndex, info.Number)
if exhibit != nil {
oldUrl := exhibit.Url
oldAudio := exhibit.Audio
oldDetails := exhibit.Details
exhibit.ExhibitionId = uint(info.ExhibitionId)
exhibit.RoomIndex = info.RoomIndex
exhibit.Number = info.Number
exhibit.Url = info.Url
exhibit.Width = info.Width
exhibit.Height = info.Height
exhibit.OffsetX = info.OffsetX
exhibit.OffsetY = info.OffsetY
exhibit.StayTime = info.StayTime
exhibit.Title = info.Title
exhibit.Audio = info.Audio
exhibit.Introduction = info.Introduction
exhibit.Details = info.Details
exhibit.AuthorIntroduction = info.AuthorIntroduction
if err := models.UpdateExhibit(exhibit); err != nil {
logging.Log.Error("数据库更新展品展位失败: ", err.Error())
return 403, utils.SerializeErrorData("更新展位失败!")
}
// 检查并删除旧资源
if oldUrl != exhibit.Url && len(oldUrl) > 0 {
utils.DeleteAliOssFile(oldUrl)
}
if oldAudio != exhibit.Audio && len(oldAudio) > 0 {
utils.DeleteAliOssFile(oldAudio)
}
processDetailResources(oldDetails, exhibit.Details)
} else {
exhibit = &models.Exhibit{
ExhibitionId: uint(info.ExhibitionId),
RoomIndex: info.RoomIndex,
Number: info.Number,
Url: info.Url,
Width: info.Width,
Height: info.Height,
OffsetX: info.OffsetX,
OffsetY: info.OffsetY,
StayTime: info.StayTime,
Title: info.Title,
Audio: info.Audio,
Introduction: info.Introduction,
Details: info.Details,
AuthorIntroduction: info.AuthorIntroduction,
}
if err := models.CreateExhibit(exhibit); err != nil {
logging.Log.Error("数据库创建展品展位失败: ", err.Error())
return 403, utils.SerializeErrorData("更新展位失败!")
}
}
return 200, []byte("{}")
}
func DeleteExhibit(router *base.Router) (int, []byte) {
// 鉴权
_, authorized := Authenticate(router)
if !authorized {
logging.Log.Error("删除展品鉴权失败")
return 0, nil
}
// 解析request数据
var info DeleteExhibitRequest
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("删除展品失败!")
}
exhibit, err := models.GetExhibit(info.ID)
if exhibit == nil {
logging.Log.Error("数据库未查找到要删除展品失败: ", err.Error())
return 400, utils.SerializeErrorData("删除展品失败!")
}
// 删除展品
if err := models.DeleteExhibit(info.ID); err != nil {
logging.Log.Error("数据库删除展品失败: ", err.Error())
return 400, utils.SerializeErrorData("删除展品失败!")
}
// 删除oss上文件资源
utils.DeleteAliOssFile(exhibit.Url)
utils.DeleteAliOssFile(exhibit.Audio)
deleteDetailResources(exhibit.Details)
return 200, []byte("{}")
}
// 检查展品详情资源,过期则删除
func processDetailResources(oldDetailsData, newDetailsData string) {
xurlsStrict := xurls.Strict()
oldDetails := xurlsStrict.FindAllString(oldDetailsData, -1)
newDetails := xurlsStrict.FindAllString(newDetailsData, -1)
for _, o := range oldDetails {
if !utils.StringArrayContains(newDetails, o) {
utils.DeleteAliOssFile(o)
}
}
}
func deleteDetailResources(detailsData string) {
xurlsStrict := xurls.Strict()
details := xurlsStrict.FindAllString(detailsData, -1)
for _, d := range details {
utils.DeleteAliOssFile(d)
}
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/models"
"exhibitionCentre/utils"
"fmt"
)
type AddUserInfo struct {
Email string `json:"email"`
Role string `json:"role"`
DisplayName string `json:"display_name"`
}
type DeleteUserInfo struct {
Email string `json:"email"`
}
func AddUser(router *base.Router) (int, []byte) {
// 鉴权
jwt, authorized := Authenticate(router)
if !authorized || jwt.Role != int(models.Admin) {
logging.Log.Error("添加用户鉴权失败")
return 0, nil
}
// 解析request数据
var info AddUserInfo
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("添加用户失败!")
}
// 获取email的用户是否存在
user, err := models.GetUser(info.Email)
if err == nil {
// 发送邀请邮件
if !utils.SendInvitationEmail(info.Email) {
logging.Log.Errorf("发送邀请邮件失败,用户(%s)\n", info.Email)
return 403, utils.SerializeErrorData("发送邀请邮件失败!")
}
return 200, utils.SerializeErrorData("邀请邮件已发送")
}
// 添加用户
if info.Role == "1" {
user = models.AddPublisher(info.Email, info.DisplayName)
} else if info.Role == "2" {
user = models.AddAdministrator(info.Email, info.DisplayName)
}
// 检查用户是否存在
if user == nil {
logging.Log.Errorf("添加用户(%s)失败", info.Email)
return 403, utils.SerializeErrorData(fmt.Sprintf("添加用户(%s)失败!", info.Email))
}
// 发送邀请邮件
if !utils.SendInvitationEmail(info.Email) {
logging.Log.Errorf("发送邀请邮件失败,用户(%s)\n", info.Email)
return 403, utils.SerializeErrorData("发送邀请邮件失败!")
}
return 200, utils.Serialize(user)
}
func DeleteUser(router *base.Router) (int, []byte) {
// 鉴权
jwt, authorized := Authenticate(router)
if !authorized || jwt.Role != int(models.Admin) {
logging.Log.Error("删除用户鉴权失败")
return 0, nil
}
// 解析request数据
var info DeleteUserInfo
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("删除用户失败!")
}
// 获取email的用户是否存在
user, err := models.GetUser(info.Email)
if err != nil {
logging.Log.Errorf("删除用户(%s)不存在", info.Email)
return 404, utils.SerializeErrorData(fmt.Sprintf("删除用户(%s)不存在!", info.Email))
}
// // 判断权限
// if user.Role >= models.RoleLevel(jwt.Role) {
// logging.Log.Errorf("管理员(%v)权限(%v)不足,无法删除用户(%v, 权限: %v)\n", jwt.Email, jwt.Role, user.Email, user.Role)
// return 403, utils.SerializeErrorData("权限不足,删除失败!")
// }
// 删除用户
if err := models.DeleteUser(user.Email); err != nil {
logging.Log.Errorf("管理员(%v, 权限:%v),删除数据库用户(%v, 权限: %v), err: %v\n", jwt.Email, jwt.Role, user.Email, user.Role, err.Error())
return 403, utils.SerializeErrorData("删除用户失败!")
}
return 200, utils.Serialize(&info)
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/models"
"exhibitionCentre/utils"
"fmt"
)
func UpdateUser(router *base.Router) (int, []byte) {
// 鉴权
jwt, authorized := Authenticate(router)
if !authorized {
logging.Log.Error("更新用户信息鉴权失败")
return 0, nil
}
// 获取email的用户是否存在
user, err := models.GetUser(jwt.Email)
if err != nil {
logging.Log.Errorf("Settings页用户(%s), err: %v", jwt.Email, err.Error())
return 404, utils.SerializeErrorData(fmt.Sprintf("该用户(%s)不存在!", jwt.Email))
}
// 解析request数据
var info SettingsInfo
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Errorf("解析设置用户信息失败: %s\n", err.Error())
return 403, utils.SerializeErrorData("更新用户信息失败!")
}
user.DisplayName = info.DisplayName
if !models.UpdateUser(user) {
return 403, utils.SerializeErrorData("更新用户信息失败!")
}
return 200, []byte("{}")
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/logging"
"exhibitionCentre/utils"
"text/template"
)
func Home(router *base.Router) (int, []byte) {
// 加载网站Home页面
page, err := template.ParseFiles("./view/html/tourist/index.html")
if err != nil {
logging.Log.Error("加载Home页面失败: ", err.Error())
return 404, utils.SerializeErrorData("")
}
page.Execute(router.Writer, nil)
return 200, nil
}
func ModelTest(router *base.Router) (int, []byte) {
// 加载网站Home页面
page, err := template.ParseFiles("./resources/webgl/index.html")
if err != nil {
logging.Log.Error("加载Home页面失败: ", err.Error())
return 404, utils.SerializeErrorData("")
}
page.Execute(router.Writer, nil)
return 200, nil
}
package controllers
import (
"exhibitionCentre/base"
"exhibitionCentre/cache"
"exhibitionCentre/config"
"exhibitionCentre/logging"
"exhibitionCentre/models"
"exhibitionCentre/utils"
"fmt"
"text/template"
)
type LoginRequest struct {
Email string `json:"email"`
Code string `json:"code"`
}
type EmailInfo struct {
Email string `json:"email"`
}
func Login(router *base.Router) (int, []byte) {
// 检查登陆状态,cookie中令牌未过期则直接进入dashboard页面
if _, authorized := LoginAuthenticate(router); authorized {
Redirect(router, "/manage/dashboard")
return 0, nil
}
// 检查是否包含登陆信息,有则进入登录逻辑
if router.Data != nil && len(router.Data) > 0 {
return loginInternal(router)
}
// 加载登陆界面
page, err := template.ParseFiles("./view/html/login.html")
if err != nil {
logging.Log.Error("加载登陆页面失败: ", err.Error())
return 404, utils.SerializeErrorData("")
}
page.Execute(router.Writer, nil)
logging.Log.Infof("打开登陆界面,客户端ip(%s)\n", utils.RemoteIp(router.Req))
return 200, nil
}
func Logout(router *base.Router) (int, []byte) {
DeleteToken(router)
return 200, []byte("{}")
}
func GetVerificationCode(router *base.Router) (int, []byte) {
// 解析request数据
var info EmailInfo
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Error("解析数据失败: ", err.Error())
return 403, utils.SerializeErrorData("获取验证码失败!")
}
// 数据库查询用户
user, _ := models.GetUser(info.Email)
if user == nil {
if utils.StringArrayContains(config.Config.Role.Administrators, info.Email) {
logging.Log.Infof("创建管理员(%s)\n", info.Email)
user = models.AddAdministrator(info.Email, "")
}
}
// 检查用户是否存在
if user == nil {
logging.Log.Errorf("获取验证码时未找到用户(%s)", info.Email)
return 404, utils.SerializeErrorData(fmt.Sprintf("该用户(%s)不存在!", info.Email))
}
// 生成验证码
code := utils.GenerateVerificationCode(6)
logging.Log.Infof("用户(%s)生成验证码: %s\n", user.Email, code)
// 缓存验证码
if !cache.CreateVerificationCode(user.Email, code) {
logging.Log.Errorf("缓存验证码失败,用户(%s)", info.Email)
return 403, utils.SerializeErrorData("获取验证码失败!")
}
// 发送验证码邮件
if !utils.SendVerificationCode(info.Email, code) {
logging.Log.Errorf("发送验证码邮件失败,用户(%s),验证码(%s)\n", info.Email, code)
return 403, utils.SerializeErrorData("获取验证码失败!")
}
logging.Log.Infof("发送验证码邮件成功,用户(%s),验证码(%s)\n", info.Email, code)
return 200, []byte("{}")
}
func loginInternal(router *base.Router) (int, []byte) {
// 解析request数据
var info LoginRequest
if err := utils.JsonParse(router.Data, &info); err != nil {
logging.Log.Errorf("解析登陆数据失败: %s\n", err.Error())
return 403, utils.SerializeErrorData("登陆失败!")
}
// 检查对应email的用户是否存在
user, err := models.GetUser(info.Email)
if err != nil {
logging.Log.Errorf("登陆时未找到用户(%s), err: %v", info.Email, err.Error())
return 404, utils.SerializeErrorData(fmt.Sprintf("该用户(%s)不存在!", info.Email))
}
// 获取验证码缓存
code := cache.GetVerificationCode(info.Email)
if code == "" || code != info.Code {
if code == "" {
logging.Log.Warningf("未找到缓存验证码或验证码过期,用户(%s)", info.Email)
} else {
logging.Log.Warningf("缓存验证码(%s)验证失败,用户(%s),验证码(%s)", code, info.Email, info.Code)
}
return 403, utils.SerializeErrorData("验证码错误!")
}
// 删除缓存验证码
cache.DeleteVerificationCode(info.Email)
// 获取jwt令牌
token, err := utils.GenerateJWT(user.ID, info.Email, int(user.Role))
if err != nil {
logging.Log.Errorf("登陆时生成令牌失败,用户(%s)", info.Email)
return 401, utils.SerializeErrorData("登陆失败!")
}
// 设置客户端cookie
SaveToken(token, router)
return 200, []byte("{}")
}
package database
import (
"exhibitionCentre/config"
"exhibitionCentre/logging"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func init() {
var err error
if DB, err = initDB(); err != nil {
logging.Log.Fatalf("连接Mysql数据库失败: %s\n", err.Error())
}
logging.Log.Info("连接Mysql数据库完成.")
}
func mysqlConfigString() (string, int, int) {
dbuser := config.Config.Mysql.UserName
dbpwd := config.Config.Mysql.Password
dbname := config.Config.Mysql.Database
dbhost := config.Config.Mysql.Host
maxidle := config.Config.Mysql.MaxIdle
maxconn := config.Config.Mysql.MaxConn
conn := dbuser + ":" + dbpwd + "@tcp(" + dbhost + ")/" + dbname + "?parseTime=true&charset=utf8&loc=Local"
return conn, maxidle, maxconn
}
func initDB() (*gorm.DB, error) {
dbDSN, maxidle, maxconn := mysqlConfigString()
db, err := gorm.Open(mysql.Open(dbDSN), &gorm.Config{}) //("mysql", sqlCfgStr)
if err != nil {
logging.Log.Error("open db failed: ", err)
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
logging.Log.Error("获取DB失败: ", err)
return nil, err
}
sqlDB.SetMaxIdleConns(maxidle)
sqlDB.SetMaxOpenConns(maxconn)
sqlDB.SetConnMaxLifetime(time.Hour)
return db, nil
}
[Unit]
Description=Exhibition
[Service]
Type=simple
ExecStart=/home/ExhibitionCentre/exhibitioncentre_prod/exhibitioncentre #服务程序地址,一般为可执行文件
Restart=always
WorkingDirectory=/home/ExhibitionCentre/exhibitioncentre_prod/
User=root
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
\ No newline at end of file
module exhibitionCentre
go 1.18
require (
github.com/jinzhu/now v1.1.5 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)
require (
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/gomodule/redigo v1.8.9
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
gorm.io/driver/mysql v1.5.1
gorm.io/gorm v1.25.4
)
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.62.539
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
)
require (
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/json-iterator/go v1.1.5 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
mvdan.cc/xurls/v2 v2.5.0
)
require github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1581 h1:Q/yk4z/cHUVZfgTqtD09qeYBxHwshQAjVRX73qs8UH0=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1581/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.539 h1:HDjqiCuJYdUQfhv9YfZ/s2Ol5xxwa0tXGxJMQ9Y5qe0=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.539/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/go-ini/ini v1.66.4 h1:dKjMqkcbkzfddhIhyglTPgMoJnkvmG+bSLrU9cTHc5M=
github.com/go-ini/ini v1.66.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E=
github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.3.3 h1:jXG9ANrwBc4+bMvBcSl8zCfPBaVoPyBEBshA8dA93X8=
gorm.io/driver/mysql v1.3.3/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.4 h1:1BKWM67O6CflSLcwGQR7ccfmC4ebOxQrTfOQGRE9wjg=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=
mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
-----BEGIN RSA PRIVATE KEY-----
MGICAQACEQDhVfOA9fB6/jvT8xeFZVvTAgMBAAECEF+L/4WGQ2MS0H90WYePGskC
CQDytZi9EGwNHwIJAO2szcYtS+bNAgkAs2omVGyVU0UCCDtqClqzMhk1AghjZDRJ
4mEUgQ==
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MGECAQACEQDcN386HZctSQsVlw2NdmLZAgMBAAECEG3/yq1c2objZ+iqIGR5gAEC
CQD71YLaSdHWWQIJAN/cFyHiGGCBAghtj5Y+IZ+JAQIIdBJNWD9APoECCDSoS7ve
SGZg
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICoDCCAgkCCQCRxUqWPjWhcjANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMC
ODYxEDAOBgNVBAgTB0JlaWppbmcxEDAOBgNVBAcTB0JlaWppbmcxDzANBgNVBAoT
BlpYR290bzEfMB0GA1UECxMWRGV2ZWxvcG1lbnQgRGVwYXJ0bWVudDEPMA0GA1UE
AxMGWlhHb3RvMR0wGwYJKoZIhvcNAQkBFg54c3hobEBsaXZlLmNvbTAeFw0xNzA2
MDMxNzA3MTFaFw0xNzA3MDMxNzA3MTFaMIGUMQswCQYDVQQGEwI4NjEQMA4GA1UE
CBMHSmlhbmdzdTEPMA0GA1UEBxMGU3V6aG91MQ8wDQYDVQQKEwZIdW1ibGUxHzAd
BgNVBAsTFkRldmVsb3BtZW50IERlcGFydG1lbnQxEzARBgNVBAMTClhpYW8gWmhh
bmcxGzAZBgkqhkiG9w0BCQEWDHhzeGhsQHFxLmNvbTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAwP+kSKEUIdVS+8I7nH4iKZaLDuGguAbwBrwITQuJXKfqA96k
pz5SKbBvtQ1tEPnI66XX+3wh4jbrUXJt5UXbG+tzu5UIVBrizXihFlwOQWA+5JHr
yG/xdoC27OD1N9G88bsRZS7yaGo/Ek5oIb8MLVdk+8kQCCRY/UCMM+SgYfUCAwEA
ATANBgkqhkiG9w0BAQUFAAOBgQBPTalhRk35VhCpLf53CDZwU/yC+zQTNC/vvbkp
5lXI1F6mJgbFI8ybKWrBFJS4nJEifuOLwzaFtuKiFALzaEJIS1XIxenQ0HCYqWsI
8c2RSvuvRtAak9Mt5d5/qxJLFdI4lExNwSKrj50/SPAEwXiZ0oY/wNPa/hfjkjwG
Xgge/Q==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDA/6RIoRQh1VL7wjucfiIplosO4aC4BvAGvAhNC4lcp+oD3qSn
PlIpsG+1DW0Q+cjrpdf7fCHiNutRcm3lRdsb63O7lQhUGuLNeKEWXA5BYD7kkevI
b/F2gLbs4PU30bzxuxFlLvJoaj8STmghvwwtV2T7yRAIJFj9QIwz5KBh9QIDAQAB
AoGAMdJMgItEfS9qip8rcEyHWSEJqL/KE3eHAtYLdogh349hM7qH2ryVzTlEvQJI
Q3eXzG01gjAbNyBiQtY9VFBiLTIhB6BFGEVmuNN+6AVvPT5yP/1RXXnsAwQeponp
jKvMDhH2tX9FPgz9BWgi8dOvVc6IgQYE+1urrVO56pgYpAECQQDj0cKVxVmX9pv7
wKz80QoPFRQ3/X4O004fCAfvsacqN5DequbCc08Mw4JbHnM/WYN4MooLZZnAzs5B
3kYX4gB1AkEA2N863IIR7Y5+YmZlX0AUs0Fh9MTwPBz2mI5hlvx3i6MhJ9213flQ
WcY3eOV6tU6143Wi4Y7uVWQYylW0obCrgQJBAMuytA+CQ5eSkunI32O17Q6LRGbD
q0DKQqGQZrg02kjvIgNWP7pBq7632Qhr85QDD4AbgD6se4tf3iAbBAU6uDkCQDDj
ses/zzbUZp1cJAIi+gem96QsOVPz24tsnYdiBrkN302TZ4pQx9JVIvA4Gz+ALPTH
8h4TEJtjY0tJotzIbQECQQDiDaXjaaYFWpnZEGTQoQKNmGb0whLrCXvqKqYvikEY
LQAC0/xtwvFHJ4iK+LBPS9Fs0ZdzKvvv8D5kcGHeqt3j
-----END RSA PRIVATE KEY-----
package logging
import (
"exhibitionCentre/config"
"log"
"os"
"time"
"github.com/op/go-logging"
)
var Log = logging.MustGetLogger("HumbleAccount")
func init() {
// If dir does not exist, create dir.
if _, err := os.Stat("logs"); os.IsNotExist(err) {
os.Mkdir("logs", os.ModePerm)
}
// create a new log file per week
go RotateLogs(7 * 24 * time.Hour)
}
func StartNewLogger() *os.File {
// create log file
logName := "logs/log_" + time.Now().Format("2006-01-02") + ".log"
logfile, err := os.OpenFile(logName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
// create backends
fileBackend := logging.NewLogBackend(logfile, "", 0)
consoleBackend := logging.NewLogBackend(os.Stderr, "", 0)
// create formatter backends
fileFormatterBackend := logging.NewBackendFormatter(fileBackend, fileFormat)
consoleFormatterBackend := logging.NewBackendFormatter(consoleBackend, consoleFormat)
// read level
levelName := config.Config.Log.Level
loglevel, _ := logging.LogLevel(levelName)
// create leveled backends
fileLeveledBackend := logging.AddModuleLevel(fileFormatterBackend)
fileLeveledBackend.SetLevel(loglevel, "")
consoleLeveledBackend := logging.AddModuleLevel(consoleFormatterBackend)
consoleLeveledBackend.SetLevel(loglevel, "")
// Set the backends to be used.
logging.SetBackend(fileLeveledBackend, consoleLeveledBackend)
return logfile
}
var consoleFormat = logging.MustStringFormatter(
`%{color}%{time:2006-01-02-15:04:05.000} ▶ %{level:.4s} %{shortfile} %{longfunc}: %{message}`,
)
var fileFormat = logging.MustStringFormatter(
`%{time:2006-01-02-15:04:05.000} ▶ %{level:.4s} %{shortfile} %{longfunc}: %{message}`,
)
package logging
import (
"time"
)
// Create a new log file at 0 am.
func RotateLogs(howOften time.Duration) {
prefile := StartNewLogger()
defer func() {
if prefile != nil {
prefile.Close()
}
}()
timer := time.NewTimer(calculateTimeSpan(howOften))
for range timer.C {
logfile := StartNewLogger()
timer.Reset(calculateTimeSpan(howOften))
if prefile != nil {
prefile.Close()
}
prefile = logfile
}
}
func calculateTimeSpan(howOften time.Duration) time.Duration {
now := time.Now()
next := now.Add(howOften)
next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location())
return next.Sub(now)
}
package main
import (
"exhibitionCentre/app"
_ "exhibitionCentre/routers"
"math/rand"
"time"
)
func init() {
}
func main() {
rand.Seed(time.Now().UnixNano())
app.Run()
}
package models
import (
"exhibitionCentre/database"
"exhibitionCentre/logging"
"gorm.io/gorm"
)
type Exhibit struct {
gorm.Model
Number int `gorm:"not null"` // 展位编号1开始
Width float32 `gorm:"default:1"`
Height float32 `gorm:"default:1"`
OffsetX float32
OffsetY float32
Url string
Title string `gorm:"type:varchar(256)"`
Audio string // 语音介绍
Introduction string // 文字介绍
Details string // json数据格式[{"media":"http://xxxxxx","detail":"《Three masks》"}]
AuthorIntroduction string
StayTime int `gorm:"default:3"` // 驻足停留时间,默认值为3s
Likes int // 点赞数
Flowers int // 送花数
Applauses int // 鼓掌数
RoomIndex int `gorm:"not null"` // 1为开幕式,2为展厅,3为演播厅
ExhibitionId uint `gorm:"not null"`
}
type ExhibitDetail struct {
Media string `json:"media"`
Detail string `json:"detail"`
}
func init() {
if err := database.DB.AutoMigrate(&Exhibit{}); err != nil {
logging.Log.Fatalf("Mysql初始化Exhibit表失败: %s\n", err.Error())
}
logging.Log.Info("Mysql初始化Exhibit表完成.")
}
func CreateExhibit(ex *Exhibit) error {
if err := database.DB.Create(ex).Error; err != nil {
return err
}
return nil // 成功创建
}
func GetExhibit(id int) (*Exhibit, error) {
// 获取第一个id为指定id的展位
var exhibit Exhibit
if err := database.DB.First(&exhibit, "id = ?", uint(id)).Error; err != nil {
return nil, err
}
return &exhibit, nil
}
func GetExhibitByNumber(exhibitionId, roomIndex, number int) (*Exhibit, error) {
// 获取第一个id为指定id的展位
var exhibit Exhibit
if err := database.DB.First(&exhibit, "exhibition_id = ? AND room_index = ? AND number = ?", exhibitionId, roomIndex, number).Error; err != nil {
return nil, err
}
return &exhibit, nil
}
func GetExhibitsByExhibitionId(exhibitionId int) ([]Exhibit, error) {
var exhibits []Exhibit
if err := database.DB.Order("number asc").Find(&exhibits, "exhibition_id = ?", exhibitionId).Error; err != nil {
return exhibits, err
}
return exhibits, nil
}
func GetExhibitsByIds(ids []int) ([]Exhibit, error) {
var exhibits []Exhibit
if len(ids) == 0 {
return exhibits, nil
}
if err := database.DB.Order("number asc").Find(&exhibits, ids).Error; err != nil {
return exhibits, err
}
return exhibits, nil
}
func GetExhibitsByExhibitionIdAndRoomIndex(exhibitionId, roomIndex int) ([]Exhibit, error) {
var exhibits []Exhibit
if err := database.DB.Order("number asc").Find(&exhibits, "exhibition_id = ? AND room_index = ?", exhibitionId, roomIndex).Error; err != nil {
return exhibits, err
}
return exhibits, nil
}
func UpdateExhibit(exhibit *Exhibit) error {
if err := database.DB.Save(exhibit).Error; err != nil {
return err
}
return nil
}
func DeleteExhibit(id int) error {
if err := database.DB.Delete(&Exhibit{}, "id = ?", id).Error; err != nil {
return err
}
// 同时删除与之关联的订单
DeleteOrders(id)
return nil
}
func DeleteExhibits(exhibits []Exhibit) error {
if len(exhibits) == 0 {
return nil
}
if err := database.DB.Delete(&exhibits).Error; err != nil {
return err
}
// 同时删除与之关联的订单
var ids []int
for _, ex := range exhibits {
ids = append(ids, int(ex.ID))
}
DeleteOrdersByExhibits(ids)
return nil
}
This diff is collapsed.
package models
import (
"exhibitionCentre/database"
"exhibitionCentre/logging"
"gorm.io/gorm"
)
type Order struct {
gorm.Model
UserName string `gorm:"type:varchar(255);not null"`
Phone string `gorm:"type:varchar(255);not null"`
Price int `gorm:"not null"`
ExhibitId uint `gorm:"not null"` // 展品id
ExhibitionId uint `gorm:"not null"` // 展览id
}
func init() {
if err := database.DB.AutoMigrate(&Order{}); err != nil {
logging.Log.Fatalf("Mysql初始化Order表失败: %s\n", err.Error())
}
logging.Log.Info("Mysql初始化Order表完成.")
}
func CreateOrder(order *Order) error {
if err := database.DB.Create(order).Error; err != nil {
return err
}
return nil // 成功创建
}
func DeleteOrders(exhibitId int) error {
if err := database.DB.Delete(&Order{}, "exhibit_id = ?", exhibitId).Error; err != nil {
return err
}
return nil
}
func DeleteOrdersByExhibits(ids []int) error {
if len(ids) == 0 {
return nil
}
if err := database.DB.Delete(&Order{}, ids).Error; err != nil {
return err
}
return nil
}
func GetOrdersByExhibitionId(exhibitionId int) ([]Order, error) {
var orders []Order
if err := database.DB.Find(&orders, "exhibition_id = ?", exhibitionId).Error; err != nil {
return orders, err
}
return orders, nil
}
func GetOrdersByExhibitId(exhibitId int) ([]Order, error) {
var orders []Order
if err := database.DB.Order("price desc").Find(&orders, "exhibit_id = ?", exhibitId).Error; err != nil {
return orders, err
}
return orders, nil
}
package models
import (
"exhibitionCentre/database"
"exhibitionCentre/logging"
"fmt"
"time"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Email string `gorm:"type:varchar(255);uniqueIndex;not null"`
Role RoleLevel
DisplayName string `gorm:"type:varchar(128);default:'用户'"`
}
type RoleLevel int
const (
Tourist RoleLevel = iota
Publisher
Admin
)
func init() {
if err := database.DB.AutoMigrate(&User{}); err != nil {
logging.Log.Fatalf("Mysql初始化User表失败: %s\n", err.Error())
}
logging.Log.Info("Mysql初始化User表完成.")
}
func GetUser(email string) (*User, error) {
// 获取第一个email为指定email的用户
var user User
if err := database.DB.First(&user, "email = ?", email).Error; err != nil {
return nil, err
}
return &user, nil
}
func GetAllPublishers() ([]User, error) {
var users []User
if err := database.DB.Find(&users, "role = ?", Publisher).Error; err != nil {
return users, err
}
return users, nil
}
func GetAllUsers() ([]User, error) {
var users []User
if err := database.DB.Order("id desc").Find(&users).Error; err != nil {
return users, err
}
return users, nil
}
func AddUser(user *User) int {
// 检查该用户是否已经存在
var tmp User
if err := database.DB.First(&tmp, "email = ?", user.Email).Error; err == nil {
logging.Log.Errorf("该用户(%s)已存在,不可重复创建.", user.Email)
return -1
} else { // 如果该用户不存在,则创建
if err := database.DB.Create(user).Error; err != nil {
logging.Log.Errorf("Create user failed: %s", err.Error())
return -2
}
}
return 0 // 成功创建
}
func UpdateUser(user *User) bool {
if err := database.DB.Save(user).Error; err != nil {
logging.Log.Errorf("更新用户信息失败: %s", err.Error())
return false
}
return true
}
func UpdateDisplayName(user *User, displayName string) bool {
if user.DisplayName == displayName {
return true
}
if err := database.DB.Model(&user).Update("display_name", displayName).Error; err != nil {
logging.Log.Errorf("更新用户显示名称失败: %s", err.Error())
return false
}
return true
}
func AddAdministrator(email, displayName string) *User {
if displayName == "" {
displayName = getDisplayName()
}
user := User{
Email: email,
Role: Admin,
DisplayName: displayName,
}
// add user to database
if AddUser(&user) == 0 {
return &user
}
return nil
}
func AddPublisher(email, displayName string) *User {
if displayName == "" {
displayName = getDisplayName()
}
user := User{
Email: email,
Role: Publisher,
DisplayName: displayName,
}
// add user to database
if AddUser(&user) == 0 {
return &user
}
return nil
}
func DeleteUser(email string) error {
if err := database.DB.Delete(&User{}, "email = ?", email).Error; err != nil {
return err
}
return nil
}
func getDisplayName() string {
return fmt.Sprintf("用户%v", time.Now().UnixNano()/1e6)
}
package models
import (
"exhibitionCentre/database"
"exhibitionCentre/logging"
"gorm.io/gorm"
)
type VisitStatistic struct {
gorm.Model
Count int `gorm:"default:0"` // 访问次数,每日次数随访问量累加
ExhibitionId uint `gorm:"not null"` // 展览id
}
func init() {
if err := database.DB.AutoMigrate(&VisitStatistic{}); err != nil {
logging.Log.Fatalf("Mysql初始化VisitStatistic表失败: %s\n", err.Error())
}
logging.Log.Info("Mysql初始化VisitStatistic表完成.")
}
func CreateVisitStatistic(visit *VisitStatistic) error {
if err := database.DB.Create(visit).Error; err != nil {
return err
}
return nil // 成功创建
}
func GetTodayVisitStatistic(exhibitionId int) (*VisitStatistic, error) {
var visit VisitStatistic
if err := database.DB.Where("DATE(`created_at`) = CURDATE()").First(&visit, "exhibition_id = ?", exhibitionId).Error; err != nil {
return nil, err
}
return &visit, nil
}
func DeleteVisitStatistics(exhibitionId int) error {
if err := database.DB.Delete(&VisitStatistic{}, "exhibition_id = ?", exhibitionId).Error; err != nil {
return err
}
return nil
}
func UpdateVisitStatistic(visit *VisitStatistic) error {
if err := database.DB.Save(visit).Error; err != nil {
return err
}
return nil
}
func GetVisitStatisticsByExhibitionId(exhibitionId int) ([]VisitStatistic, error) {
var visits []VisitStatistic
if err := database.DB.Order("created_at desc").Find(&visits, "exhibition_id = ?", exhibitionId).Error; err != nil {
return visits, err
}
return visits, nil
}
package routers
import (
"exhibitionCentre/base"
"exhibitionCentre/controllers"
"exhibitionCentre/logging"
"exhibitionCentre/utils"
"io"
"io/ioutil"
"net/http"
)
func init() {
// 资源
http.Handle("/view/css/", http.StripPrefix("/view/css/", http.FileServer(http.Dir("view/css"))))
http.Handle("/view/html/", http.StripPrefix("/view/html/", http.FileServer(http.Dir("view/html"))))
http.Handle("/view/js/", http.StripPrefix("/view/js/", http.FileServer(http.Dir("view/js"))))
http.Handle("/view/images/", http.StripPrefix("/view/images/", http.FileServer(http.Dir("view/images"))))
http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.Dir("resources"))))
// http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
// http.Handle("/view/static/", http.StripPrefix("/view/static/", http.FileServer(http.Dir("view/static"))))
// 游客
{
addRouter("/", controllers.Home)
addRouter("/test", controllers.ModelTest)
}
// exhibition controller
controller := "exhibitions"
{
// 主页展览列表
addRouter(routerPath(controller, ""), controllers.Exhibitions)
// 主页更多展览列表
addRouter(routerPath(controller, "more"), controllers.MoreExhibitions)
}
// exhibition controller
controller = "exhibition"
{
// 展览列表页点击展览请求跳转
addRouter(routerPath(controller, ""), controllers.GotoExhibition)
// 获取展览详细内容
addRouter(routerPath(controller, "detail"), controllers.ExhibitionDetail)
// 点赞
addRouter(routerPath(controller, "like"), controllers.ExhibitionLike)
// 送花
addRouter(routerPath(controller, "send_flower"), controllers.ExhibitionSendFlower)
// 鼓掌
addRouter(routerPath(controller, "give_applause"), controllers.ExhibitionGiveApplause)
}
// exhibit controller
controller = "exhibit"
{
// 展品详情
addRouter(routerPath(controller, "detail"), controllers.GetExhibitDetail)
// 点赞
addRouter(routerPath(controller, "like"), controllers.ExhibitLike)
// 送花
addRouter(routerPath(controller, "send_flower"), controllers.ExhibitSendFlower)
// 鼓掌
addRouter(routerPath(controller, "give_applause"), controllers.ExhibitGiveApplause)
// 出价
addRouter(routerPath(controller, "offer"), controllers.ExhibitOffer)
}
// auth
controller = "auth"
{
addRouter(routerPath(controller, "sts"), controllers.AliyunSts)
}
// user controller
controller = "user"
{
addRouter(routerPath(controller, "login"), controllers.Login)
addRouter(routerPath(controller, "logout"), controllers.Logout)
addRouter(routerPath(controller, "get_verification_code"), controllers.GetVerificationCode)
}
// manage controller
controller = "manage"
{
addRouter(routerPath(controller, "dashboard"), controllers.Dashboard)
// 展览管理
addRouter(routerPath(controller, "dashboard/exhibitions"), controllers.DashboardExhibitions)
addRouter(routerPath(controller, "manage_exhibitions"), controllers.ManageExhibitions)
addRouter(routerPath(controller, "get_exhibitions"), controllers.GetExhibitions)
addRouter(routerPath(controller, "get_publisher_exhibitions"), controllers.GetPublisherExhibitions)
// 用户管理
addRouter(routerPath(controller, "dashboard/users"), controllers.DashboardUsers)
addRouter(routerPath(controller, "manage_users"), controllers.ManageUsers)
addRouter(routerPath(controller, "get_users"), controllers.GetUsers)
// 设置
addRouter(routerPath(controller, "dashboard/settings"), controllers.DashboardSettings)
addRouter(routerPath(controller, "settings"), controllers.Settings)
}
// manage_exhibtion
controller = "manage_exhibitions"
{
addRouter(routerPath(controller, "create"), controllers.CreateExhibition)
addRouter(routerPath(controller, "edit"), controllers.EditExhibition)
addRouter(routerPath(controller, "update"), controllers.UpdateExhibition)
addRouter(routerPath(controller, "delete"), controllers.DeleteExhibition)
// 展览发布操作
addRouter(routerPath(controller, "publish"), controllers.PublishExhibition)
addRouter(routerPath(controller, "cancel_publish"), controllers.CancelPublishExhibition)
// 展览场馆使用操作
// 开幕式使用操作
addRouter(routerPath(controller, "use_opening_ceremony"), controllers.UseOpeningCeremony)
addRouter(routerPath(controller, "cancel_use_opening_ceremony"), controllers.CancelUseOpeningCeremony)
// 展厅使用操作
addRouter(routerPath(controller, "use_exhibition_hall"), controllers.UseExhibitionHall)
addRouter(routerPath(controller, "cancel_use_exhibition_hall"), controllers.CancelUseExhibitionHall)
// 演播厅使用操作
addRouter(routerPath(controller, "use_studio"), controllers.UseStudio)
addRouter(routerPath(controller, "cancel_use_studio"), controllers.CancelUseStudio)
// 开幕式、展厅、演播厅布展操作
addRouter(routerPath(controller, "edit_venue"), controllers.EditVenue)
// 获取访问统计信息
addRouter(routerPath(controller, "visit_statistics"), controllers.GetVisitStatistics)
// 获取当前展览所有有订单的展品
addRouter(routerPath(controller, "exhibits_with_orders"), controllers.GetExhibitsWithOrders)
// 获取展品订单信息
addRouter(routerPath(controller, "orders"), controllers.GetOrders)
}
// manage_exhibtion
controller = "manage_exhibits"
{
addRouter(routerPath(controller, "edit"), controllers.EditExhibit)
addRouter(routerPath(controller, "update"), controllers.UpdateExhibit)
addRouter(routerPath(controller, "delete"), controllers.DeleteExhibit)
}
// manage_users
controller = "manage_users"
{
addRouter(routerPath(controller, "add"), controllers.AddUser)
addRouter(routerPath(controller, "delete"), controllers.DeleteUser)
}
// settings
controller = "settings"
{
addRouter(routerPath(controller, "update"), controllers.UpdateUser)
}
}
func addRouter(routerPath string, method func(r *base.Router) (int, []byte)) {
http.HandleFunc(routerPath, func(w http.ResponseWriter, r *http.Request) {
// read request body data
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
if err != nil {
logging.Log.Error("Read request body failed:", routerPath, err)
utils.SendResponse(w, 500, []byte("Read request data failed."))
return
}
router := base.Router{
Writer: w,
Req: r,
Data: body,
}
// execute api method
statusCode, responseData := method(&router)
if responseData != nil {
utils.SendResponse(w, statusCode, responseData)
}
})
}
func routerPath(controller, method string) string {
if method == "" {
return "/" + controller
} else {
return "/" + controller + "/" + method
}
}
package utils
import (
"exhibitionCentre/config"
"exhibitionCentre/logging"
"fmt"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
var AliyunStsClient *sts.Client
var AliyunOssClient *oss.Client
var AliyunOssBucket *oss.Bucket
type AliyunStsResponse struct {
Region string `json:"region"`
Endpoint string `json:"endpoint"`
AccessKeyId string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
StsToken string `json:"sts_token"`
Bucket string `json:"bucket"`
}
func init() {
initStsClient()
initOssClient()
}
func initStsClient() bool {
client, err := sts.NewClientWithAccessKey(config.Config.AliyunOss.RegionId, config.Config.AliyunOss.AccessKeyId, config.Config.AliyunOss.AccessKeySecret)
if err != nil {
logging.Log.Panicf("阿里云sts客户端创建失败, err: %v\n", err.Error())
return false
}
AliyunStsClient = client
logging.Log.Info("阿里云sts客户端创建完成")
return true
}
func initOssClient() bool {
client, err := oss.New(config.Config.AliyunOss.Endpoint, config.Config.AliyunOss.AccessKeyId, config.Config.AliyunOss.AccessKeySecret)
if err != nil {
logging.Log.Panicf("阿里云oss客户端创建失败, err: %v\n", err.Error())
return false
}
AliyunOssClient = client
logging.Log.Info("阿里云oss客户端创建完成")
// 创建bucket
bucket, err := AliyunOssClient.Bucket(config.Config.AliyunOss.Bucket)
if err != nil {
logging.Log.Panicf("阿里云oss bucket创建失败, err: %v\n", err.Error())
return false
}
AliyunOssBucket = bucket
logging.Log.Info("阿里云oss bucket创建完成")
return true
}
func GenerateStsToken(sessionName string) *AliyunStsResponse {
if AliyunStsClient == nil {
return nil
}
request := sts.CreateAssumeRoleRequest()
request.Scheme = "https"
request.RoleArn = config.Config.AliyunOss.Arn
request.RoleSessionName = sessionName
response, err := AliyunStsClient.AssumeRole(request)
if err != nil {
logging.Log.Errorf("获取阿里云sts令牌失败, err: %v\n", err.Error())
return nil
}
stsResponse := AliyunStsResponse{
Region: config.Config.AliyunOss.RegionId,
Endpoint: config.Config.AliyunOss.Endpoint,
AccessKeyId: response.Credentials.AccessKeyId,
AccessKeySecret: response.Credentials.AccessKeySecret,
StsToken: response.Credentials.SecurityToken,
Bucket: config.Config.AliyunOss.Bucket,
}
return &stsResponse
}
/*********************************** oss操作 ***********************************/
func DeleteAliOssFile(fileurl string) bool {
endpoint := fmt.Sprintf("%s/", config.Config.AliyunOss.Endpoint)
index := strings.Index(fileurl, endpoint)
if index < 0 {
return false
}
index += len(endpoint)
if index >= len(fileurl) {
return false
}
err := AliyunOssBucket.DeleteObject(fileurl[index:])
if err != nil {
logging.Log.Warningf("oss删除文件(%v)失败, err:%v\n", fileurl, err.Error())
return false
}
return true
}
package utils
import (
"bytes"
"exhibitionCentre/config"
"exhibitionCentre/logging"
"text/template"
"gopkg.in/gomail.v2"
)
func SendVerificationCode(address, code string) bool {
tmp, err := template.ParseFiles("./view/html/verification_code.html")
if err != nil {
logging.Log.Errorf("读取验证码邮件模板失败: %s\n", err.Error())
return false
}
var buf bytes.Buffer
tmp.Execute(&buf, code)
return SendEmail(address, "验证码", buf.String())
}
func SendInvitationEmail(address string) bool {
tmp, err := template.ParseFiles("./view/html/invitation.html")
if err != nil {
logging.Log.Errorf("读取邀请邮件模板失败: %s\n", err.Error())
return false
}
var buf bytes.Buffer
tmp.Execute(&buf, config.Config.Others.LoginUrl)
return SendEmail(address, "邀请邮件", buf.String())
}
func SendEmail(toAdress, subject, body string) bool {
from := config.Config.Smtp.FromEmail
m := gomail.NewMessage()
m.SetHeader("From", from)
m.SetHeader("To", toAdress)
m.SetHeader("Subject", subject)
m.SetBody("text/html", body)
host := config.Config.Smtp.Host
port := config.Config.Smtp.Port
username := config.Config.Smtp.UserName
password := config.Config.Smtp.Password
d := gomail.NewDialer(host, port, username, password)
// Send the email to Bob, Cora and Dan.
if err := d.DialAndSend(m); err != nil {
logging.Log.Errorf("发送邮件失败: %s\n", err.Error())
return false
}
return true
}
package utils
import (
"errors"
"fmt"
"net/http"
"reflect"
"strconv"
)
// MapIt maps get request into struct
func ParseQuery(req *http.Request, d interface{}) error {
dType := reflect.TypeOf(d)
if err := shouldBeStruct(dType); err != nil {
return err
}
// Data Holder Value
dhVal := reflect.ValueOf(d)
// Loop over all the fields present in struct (Title, Body, JSON)
for i := 0; i < dType.Elem().NumField(); i++ {
// Give me ith field. Elem() is used to dereference the pointer
field := dType.Elem().Field(i)
// Get the value from field tag i.e in case of Title it is "title"
key := field.Tag.Get("mapper")
// Get the type of field
kind := field.Type.Kind()
// Get the value from query params with given key
val := req.URL.Query().Get(key)
// Get reference of field value provided to input `d`
result := dhVal.Elem().Field(i)
switch kind {
case reflect.Int:
if val == "" {
result.SetInt(0)
} else {
intVal, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return err
}
result.SetInt(intVal)
}
case reflect.String:
if val == "" {
result.SetString("")
} else {
result.SetString(val)
}
}
}
return nil
}
func shouldBeStruct(d reflect.Type) error {
td := d.Elem()
if td.Kind() != reflect.Struct {
errStr := fmt.Sprintf("Input should be %v, found %v", reflect.Struct, td.Kind())
return errors.New(errStr)
}
return nil
}
package utils
import (
"encoding/json"
"exhibitionCentre/logging"
)
func JsonParse(jsonData []byte, info interface{}) error {
if err := json.Unmarshal(jsonData, info); err != nil {
logging.Log.Error("Parse request parameters failed: ", err)
return err
}
return nil
}
package utils
import (
"encoding/json"
"exhibitionCentre/logging"
"fmt"
"net/http"
)
type ErrorInfo struct {
Error string `json:"error"`
}
type TokenInfo struct {
Token string `json:"token"`
}
func SendResponse(writer http.ResponseWriter, statusCode int, data []byte) {
if writer == nil {
logging.Log.Error("SendResponse Error: http.ResponseWriter == nil.")
return
}
// set response header info
writer.Header().Set("Content-Type", "application/json")
// set status code
writer.WriteHeader(statusCode)
// send response
writer.Write(data)
}
func SendSMSRequest(phoneNumber, verificationCode string) bool {
url := fmt.Sprintf("http://221.179.215.39:8144/mtsnport/transms?uid=261&pwd=56tyuk&mobile=%s&msg=%s&srcid=381&dtime&para=2", phoneNumber, verificationCode)
resp, err := http.Get(url)
if err != nil {
logging.Log.Error("Failed to send SMS message to SMS server!", err.Error())
return false
}
return resp.StatusCode == 200
}
func SerializeErrorData(data string) []byte {
if len(data) == 0 {
return []byte("{}")
}
info := ErrorInfo{Error: data}
if bytes, err := json.Marshal(info); err == nil {
return bytes
}
return []byte("{}")
}
func SerializeToken(token string) []byte {
info := TokenInfo{Token: token}
if bytes, err := json.Marshal(info); err == nil {
return bytes
}
return nil
}
func Serialize(data any) []byte {
if bytes, err := json.Marshal(data); err == nil {
return bytes
}
return nil
}
func RemoteIp(req *http.Request) string {
var remoteAddr string
// // RemoteAddr
// remoteAddr = req.RemoteAddr
// if remoteAddr != "" {
// return remoteAddr
// }
// // ipv4
// remoteAddr = req.Header.Get("ipv4")
// if remoteAddr != "" {
// return remoteAddr
// }
// //
// remoteAddr = req.Header.Get("XForwardedFor")
// if remoteAddr != "" {
// return remoteAddr
// }
// // X-Forwarded-For
// remoteAddr = req.Header.Get("X-Forwarded-For")
// if remoteAddr != "" {
// return remoteAddr
// }
// X-Real-Ip
remoteAddr = req.Header.Get("X-Real-Ip")
if remoteAddr != "" {
return remoteAddr
} else {
remoteAddr = "127.0.0.1"
}
return remoteAddr
}
package utils
func StringArrayContains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}
func IntArrayContains(array []int, value int) bool {
for _, v := range array {
if v == value {
return true
}
}
return false
}
package utils
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/hex"
"exhibitionCentre/config"
"exhibitionCentre/logging"
"io"
"io/ioutil"
"time"
"github.com/dgrijalva/jwt-go"
)
type JWTCustomClaims struct {
UserId uint `json:"user_id"`
Email string `json:"email"`
Role int `json:"role"`
jwt.StandardClaims
}
const JWT_EXPIRATION_TIME = 1000000000 * 60 * 60 * 24 * 7 // 7days
var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
func GenerateVerificationCode(codeLen int) string {
b := make([]byte, codeLen)
n, err := io.ReadAtLeast(rand.Reader, b, codeLen)
if n != codeLen {
panic(err)
}
for i := 0; i < len(b); i++ {
b[i] = table[int(b[i])%len(table)]
}
return string(b)
}
func GenerateSecret(secret string) (string, error) {
pwdKeyPath := config.Config.Certificate.PasswordPrivateKey
key, _ := ioutil.ReadFile(pwdKeyPath)
var rsaPSSKey *rsa.PrivateKey
var err error
if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
logging.Log.Errorf("Unable to parse RSA private key: %v", err)
return "", err
}
sha_pwd := SHA(secret)
sha_pri := SHA(rsaPSSKey.D.String())
return SHA(sha_pwd + sha_pri), nil
}
func SHA(str string) string {
// Converts string to sha2
h := sha256.New()
h.Write([]byte(str))
code := h.Sum(nil)
codestr := hex.EncodeToString(code)
return codestr
}
func DecodePwd(str string) {
//var dest []byte
dest, _ := hex.DecodeString(str)
logging.Log.Error(string(dest))
}
func GenerateJWT(userId uint, email string, role int) (string, error) {
signingKey, err := ReadJWTPrivateKey()
if err != nil {
return "", err
}
issuer := config.Config.App.Issuer
// Create the Claims
claims := JWTCustomClaims{
userId,
email,
role,
jwt.StandardClaims{
ExpiresAt: time.Now().Add(JWT_EXPIRATION_TIME).Unix(),
Issuer: issuer,
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(signingKey)
}
func ParseJWT(jwtString string) *JWTCustomClaims {
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdXJpc2RpY3Rpb25MZXZlbCI6MSwiZXhwIjoxNTI4ODk1ODg0LCJpc3MiOiJIdW1ibGUifQ.5m8ojwawO3YMvuc5qua1QpSA-CLwU-j8FUQu446p8pI
token, err := jwt.ParseWithClaims(jwtString, &JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
signingKey, err := ReadJWTPrivateKey()
if err != nil {
return "", err
}
return signingKey, nil
})
if err != nil {
return nil
}
claims, ok := token.Claims.(*JWTCustomClaims)
if ok && token.Valid {
return claims
}
return nil
}
func ReadJWTPrivateKey() ([]byte, error) {
jwtKeyPath := config.Config.Certificate.JwtPrivatekey
key, _ := ioutil.ReadFile(jwtKeyPath)
var rsaPSSKey *rsa.PrivateKey
var err error
if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
logging.Log.Errorf("Unable to parse RSA private key: %v", err)
return nil, err
}
signingKey := []byte(rsaPSSKey.D.String())
return signingKey, nil
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*!
* Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free"; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
.far,
.fa-regular {
font-family: 'Font Awesome 6 Free';
font-weight: 400; }
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment