├── .DS_Store ├── .gitignore ├── README.md ├── conf └── app.conf ├── controllers ├── airad.go ├── base.go ├── common.go ├── default.go ├── device.go ├── error.go ├── mqtt.go ├── mqttoption.go ├── object.go └── user.go ├── database └── airad.sql ├── logs └── logs.log ├── main.go ├── models ├── airad.go ├── base.go ├── common.go ├── device.go ├── messages.go ├── mqtt.go ├── mqttoption.go ├── object.go └── user.go ├── pictures ├── airad.png └── airad_swagger.png ├── routers └── router.go ├── swagger ├── favicon-16x16.png ├── favicon-32x32.png ├── index.html ├── oauth2-redirect.html ├── swagger-ui-bundle.js ├── swagger-ui-bundle.js.map ├── swagger-ui-standalone-preset.js ├── swagger-ui-standalone-preset.js.map ├── swagger-ui.css ├── swagger-ui.css.map ├── swagger-ui.js ├── swagger-ui.js.map ├── swagger.json └── swagger.yml ├── tests └── default_test.go ├── utils ├── airad.go ├── bootStrap.go ├── cache.go ├── cropper.go ├── date.go ├── encrypt.go ├── hashUtils.go ├── jwt.go ├── rand.go ├── sql.go ├── template.go └── validator.go └── views └── index.tpl /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | routers/commentsRouter* 3 | airad 4 | lastupdate.tmp 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AirAd 2 | Beego based RestFul API service 3 | 4 | which supports mobile app as cloud service 5 | ![](https://github.com/rubinliudongpo/airad/blob/master/pictures/airad.png) 6 | 7 | ## 特性 8 | 9 | - RestFul API 10 | - Access Token, User Auth 11 | 12 | ## 依赖 13 | 14 | - [github.com/astaxie/beego](https://github.com/astaxie/beego) 15 | - [github.com/astaxie/beego/context](https://github.com/astaxie/beego/context) 16 | - [github.com/astaxie/beego/orm](https://github.com/astaxie/beego/orm) 17 | - [github.com/dgrijalva/jwt-go](https://github.com/dgrijalva/jwt-go) 18 | - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) 19 | 20 | 21 | ## 如何开始 22 | 23 | - 安装 [bee](https://github.com/beego/bee) 工具 24 | - go get github.com/rubinliudongpo/airad (注意配置GOROOT,GOPATH,详情请参考 http://sourabhbajaj.com/mac-setup/Go/README.html ) 25 | - 在mysql数据库里创建数据库名字叫airad 26 | ``` 27 | mysql -uroot -pYOURROOTPASSWORD -h 127.0.0.1 -e "CREATE DATABASE IF NOT EXISTS airad DEFAULT CHARSET utf8 COLLATE utf8_general_ci;" 28 | ``` 29 | - 创建(并授权给)用户(gouser)和密码(gopassword) 30 | ``` 31 | mysql -uroot -pYOURROOTPASSWORD -h 127.0.0.1 -e "grant all privileges on airad.* to gouser@'%' identified by 'gopass';" 32 | ``` 33 | - 导入airad.sql 34 | ``` 35 | mysql -uroot -pROOTPASSWORD airad < database/airad.sql 36 | ``` 37 | 38 | ## 查看和调试 39 | 40 | 请通过 http://localhost:9080/swagger/ 试用API,界面如下 41 | ![](https://github.com/rubinliudongpo/airad/blob/master/pictures/airad_swagger.png) 42 | 43 | ## 注意 44 | - SWagger的路由页面待更新 45 | -------------------------------------------------------------------------------- /conf/app.conf: -------------------------------------------------------------------------------- 1 | appname = airad 2 | httpport = 9080 3 | runmode = dev 4 | autorender = false 5 | copyrequestbody = true 6 | EnableDocs = true 7 | Graceful = true 8 | 9 | db.host = 127.0.0.1 10 | db.port = 3306 11 | db.user = gouser 12 | db.password = gopass 13 | db.name = airad 14 | db.charset = utf8mb4 15 | 16 | sessionon = true 17 | sessionprovider = file 18 | sessionproviderconfig = "./tmp" 19 | sessiongcmaxlifetime = 31536000 20 | sessioncookielifetime = 31536000 21 | 22 | cache = redis 23 | redis_host = "127.0.0.1:6379" 24 | redis_password = "12345GESAFsfdtewS4G6789" 25 | cache_expire = 6000 26 | 27 | token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 28 | -------------------------------------------------------------------------------- /controllers/airad.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | //"github.com/astaxie/beego" 5 | "github.com/rubinliudongpo/airad/models" 6 | "strings" 7 | "errors" 8 | "encoding/json" 9 | "strconv" 10 | "github.com/rubinliudongpo/airad/utils" 11 | "fmt" 12 | ) 13 | 14 | // AirAdController operations for AirAd 15 | type AirAdController struct { 16 | BaseController 17 | } 18 | 19 | // URLMapping ... 20 | func (c *AirAdController) URLMapping() { 21 | c.Mapping("Post", c.Post) 22 | c.Mapping("GetOne", c.GetOne) 23 | c.Mapping("GetAll", c.GetAll) 24 | c.Mapping("Put", c.Put) 25 | c.Mapping("Delete", c.Delete) 26 | } 27 | 28 | // Post ... 29 | // @Title Create 30 | // @Description create AirAd 31 | // @Param body body models.AirAd true "body for AirAd content" 32 | // @Success 201 {object} models.AirAd 33 | // @Failure 403 body is empty 34 | // @router / [post] 35 | func (c *AirAdController) Post() { 36 | var v models.AirAd 37 | 38 | token := c.Ctx.Input.Header("token") 39 | //id := c.Ctx.Input.Header("id") 40 | et := utils.EasyToken{} 41 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 42 | valido, err := et.ValidateToken(token) 43 | if !valido { 44 | c.Ctx.ResponseWriter.WriteHeader(401) 45 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 46 | c.ServeJSON() 47 | return 48 | } 49 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 50 | if errorMessage := utils.CheckNewAirAdPost(v.DeviceId, v.Co, v.Humidity, v.Temperature, 51 | v.Pm25, v.Pm10, v.Nh3, v.O3, v.Suggest, v.AqiQuality); errorMessage != "ok"{ 52 | c.Ctx.ResponseWriter.WriteHeader(403) 53 | c.Data["json"] = Response{403, 403,errorMessage, ""} 54 | c.ServeJSON() 55 | return 56 | } 57 | if !models.CheckDeviceId(v.DeviceId){ 58 | c.Ctx.ResponseWriter.WriteHeader(403) 59 | c.Data["json"] = Response{403, 403,"设备Id不存在", ""} 60 | c.ServeJSON() 61 | return 62 | } 63 | 64 | if !models.CheckDeviceIdAndToken(v.DeviceId, token){ 65 | c.Ctx.ResponseWriter.WriteHeader(403) 66 | c.Data["json"] = Response{403, 403,"用户ID和Token不匹配", ""} 67 | c.ServeJSON() 68 | return 69 | } 70 | 71 | 72 | if airAdId, err := models.AddAirAd(&v); err == nil { 73 | if device, err := models.GetDeviceById(v.DeviceId); err == nil { 74 | models.UpdateDeviceAirAdCount(device) 75 | c.Ctx.Output.SetStatus(201) 76 | var returnData = &CreateObjectData{int(airAdId)} 77 | c.Data["json"] = &Response{0, 0, "ok", returnData} 78 | } else { 79 | c.Ctx.ResponseWriter.WriteHeader(403) 80 | c.Data["json"] = Response{403, 403,"设备Id不存在", ""} 81 | c.ServeJSON() 82 | return 83 | } 84 | 85 | } else { 86 | c.Data["json"] = err.Error() 87 | } 88 | } else { 89 | c.Data["json"] = err.Error() 90 | } 91 | c.ServeJSON() 92 | } 93 | 94 | // GetOne ... 95 | // @Title GetOne 96 | // @Description get AirAd by id 97 | // @Param id path string true "The key for static block" 98 | // @Success 200 {object} models.AirAd 99 | // @Failure 403 :id is empty 100 | // @router /:id [get] 101 | func (c *AirAdController) GetOne() { 102 | idStr := c.Ctx.Input.Param(":id") 103 | id, _ := strconv.Atoi(idStr) 104 | v, err := models.GetAirAdById(id) 105 | if err != nil { 106 | c.Data["json"] = err.Error() 107 | } else { 108 | c.Data["json"] = v 109 | } 110 | c.ServeJSON() 111 | 112 | } 113 | 114 | // GetAll ... 115 | // @Title GetAll 116 | // @Description get AirAd 117 | // @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." 118 | // @Param fields query string false "Fields returned. e.g. col1,col2 ..." 119 | // @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." 120 | // @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." 121 | // @Param limit query string false "Limit the size of result set. Must be an integer" 122 | // @Param offset query string false "Start position of result set. Must be an integer" 123 | // @Success 200 {object} models.AirAd 124 | // @Failure 403 125 | // @router / [get] 126 | func (c *AirAdController) GetAll() { 127 | var fields []string 128 | var sortby []string 129 | var order []string 130 | var query = make(map[string]string) 131 | var limit int = 20 132 | var offset int 133 | var deviceId int 134 | 135 | deviceId, err := strconv.Atoi(c.Ctx.Input.Header("device_id")) 136 | token := c.Ctx.Input.Header("token") 137 | //id := c.Ctx.Input.Header("id") 138 | et := utils.EasyToken{} 139 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 140 | validation, err := et.ValidateToken(token) 141 | if !validation { 142 | c.Ctx.ResponseWriter.WriteHeader(401) 143 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 144 | c.ServeJSON() 145 | return 146 | } 147 | 148 | found, _ := models.GetUserByToken(token) 149 | if !found { 150 | c.Ctx.Output.SetStatus(201) 151 | c.Data["json"] = &Response{401, 401, "未找到相关的用户", ""} 152 | c.ServeJSON() 153 | return 154 | } 155 | 156 | // fields: col1,col2,entity.col3 157 | if v := c.GetString("fields"); v != "" { 158 | fields = strings.Split(v, ",") 159 | } 160 | // limit: 10 (default is 10) 161 | if v, err := c.GetInt("limit"); err == nil { 162 | limit = v 163 | } 164 | // offset: 0 (default is 0) 165 | if v, err := c.GetInt("offset"); err == nil { 166 | offset = v 167 | } 168 | // sortby: col1,col2 169 | if v := c.GetString("sortby"); v != "" { 170 | sortby = strings.Split(v, ",") 171 | } 172 | // order: desc,asc 173 | if v := c.GetString("order"); v != "" { 174 | order = strings.Split(v, ",") 175 | } 176 | // query: k:v,k:v 177 | if v := c.GetString("query"); v != "" { 178 | for _, cond := range strings.Split(v, ",") { 179 | kv := strings.SplitN(cond, ":", 2) 180 | if len(kv) != 2 { 181 | c.Data["json"] = errors.New("Error: invalid query key/value pair") 182 | c.ServeJSON() 183 | return 184 | } 185 | k, v := kv[0], kv[1] 186 | query[k] = v 187 | } 188 | } 189 | 190 | l, totalCount, err := models.GetAllAirAds(query, fields, sortby, order, offset, limit, deviceId) 191 | if err != nil { 192 | c.Data["json"] = err.Error() 193 | } else { 194 | var returnData = &GetAirAdData{totalCount, l} 195 | c.Data["json"] = &Response{0, 0, "ok", returnData} 196 | } 197 | c.ServeJSON() 198 | } 199 | 200 | // Put ... 201 | // @Title Put 202 | // @Description update the AirAd 203 | // @Param id path string true "The id you want to update" 204 | // @Param body body models.AirAd true "body for AirAd content" 205 | // @Success 200 {object} models.AirAd 206 | // @Failure 403 :id is not int 207 | // @router /:id [put] 208 | func (c *AirAdController) Put() { 209 | idStr := c.Ctx.Input.Param(":id") 210 | id, _ := strconv.Atoi(idStr) 211 | v := models.AirAd{Id: id} 212 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 213 | if err := models.UpdateAirAdById(&v); err == nil { 214 | c.Data["json"] = "OK" 215 | } else { 216 | c.Data["json"] = err.Error() 217 | } 218 | } else { 219 | c.Data["json"] = err.Error() 220 | } 221 | c.ServeJSON() 222 | } 223 | 224 | // Delete ... 225 | // @Title Delete 226 | // @Description delete the AirAd 227 | // @Param id path string true "The id you want to delete" 228 | // @Success 200 {string} delete success! 229 | // @Failure 403 id is empty 230 | // @router /:id [delete] 231 | func (c *AirAdController) Delete() { 232 | idStr := c.Ctx.Input.Param(":id") 233 | id, _ := strconv.Atoi(idStr) 234 | if err := models.DeleteAirAd(id); err == nil { 235 | c.Data["json"] = "OK" 236 | } else { 237 | c.Data["json"] = err.Error() 238 | } 239 | c.ServeJSON() 240 | } 241 | -------------------------------------------------------------------------------- /controllers/base.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | type BaseController struct { 8 | beego.Controller 9 | } 10 | 11 | // Controller Response is controller error info struct. 12 | type Response struct { 13 | Status int `json:"status"` 14 | ErrorCode int `json:"error_code"` 15 | ErrorMessage string `json:"error_message"` 16 | Data interface{} `json:"data"` 17 | } -------------------------------------------------------------------------------- /controllers/common.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | //"errors" 5 | //"regexp" 6 | //"strings" 7 | 8 | "github.com/astaxie/beego" 9 | //"github.com/astaxie/beego/validation" 10 | //"github.com/dgrijalva/jwt-go" 11 | ) 12 | 13 | // Predefined const error strings. 14 | const ( 15 | ErrInputData = "数据输入错误" 16 | ErrDatabase = "数据库操作错误" 17 | ErrDupUser = "用户信息已存在" 18 | ErrNoUser = "用户信息不存在" 19 | ErrPass = "密码不正确" 20 | ErrNoUserPass = "用户信息不存在或密码不正确" 21 | ErrNoUserChange = "用户信息不存在或数据未改变" 22 | ErrInvalidUser = "用户信息不正确" 23 | ErrOpenFile = "打开文件出错" 24 | ErrWriteFile = "写文件出错" 25 | ErrSystem = "操作系统错误" 26 | ) 27 | 28 | // UserData definition. 29 | type UserSuccessLoginData struct { 30 | AccessToken string `json:"access_token"` 31 | UserName string `json:"user_name"` 32 | } 33 | 34 | // CreateDevice definition. 35 | type CreateObjectData struct { 36 | Id int `json:"id"` 37 | } 38 | 39 | // GetDevices definition. 40 | type GetDeviceData struct { 41 | TotalCount int64 `json:"total_count"` 42 | Devices interface{} `json:"devices"` 43 | } 44 | 45 | // GetAirAds definition. 46 | type GetAirAdData struct { 47 | TotalCount int64 `json:"total_count"` 48 | AirAds interface{} `json:"airads"` 49 | } 50 | 51 | // Predefined controller error/success values. 52 | var ( 53 | successReturn = &Response{200, 0, "ok", "ok"} 54 | err404 = &Response{404, 404, "找不到网页", "找不到网页"} 55 | errInputData = &Response{400, 10001, "数据输入错误", "客户端参数错误"} 56 | errDatabase = &Response{500, 10002, "服务器错误", "数据库操作错误"} 57 | errUserToken = &Response{500, 10002, "服务器错误", "令牌操作错误"} 58 | errDupUser = &Response{400, 10003, "用户信息已存在", "数据库记录重复"} 59 | errNoUser = &Response{400, 10004, "用户信息不存在", "数据库记录不存在"} 60 | errPass = &Response{400, 10005, "用户信息不存在或密码不正确", "密码不正确"} 61 | errNoUserOrPass = &Response{400, 10006, "用户不存在或密码不正确", "数据库记录不存在或密码不正确"} 62 | errNoUserChange = &Response{400, 10007, "用户不存在或数据未改变", "数据库记录不存在或数据未改变"} 63 | errInvalidUser = &Response{400, 10008, "用户信息不正确", "Session信息不正确"} 64 | errOpenFile = &Response{500, 10009, "服务器错误", "打开文件出错"} 65 | errWriteFile = &Response{500, 10010, "服务器错误", "写文件出错"} 66 | errSystem = &Response{500, 10011, "服务器错误", "操作系统错误"} 67 | errExpired = &Response{400, 10012, "登录已过期", "验证token过期"} 68 | errPermission = &Response{400, 10013, "没有权限", "没有操作权限"} 69 | ) 70 | 71 | // BaseController definition. 72 | //type BaseController struct { 73 | // beego.Controller 74 | //} 75 | 76 | // RetError return error information in JSON. 77 | func (base *BaseController) RetError(e *Response) { 78 | if mode := beego.AppConfig.String("runmode"); mode == "prod" { 79 | e.Data = "" 80 | } 81 | 82 | base.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8") 83 | base.Ctx.ResponseWriter.WriteHeader(e.Status) 84 | base.Data["json"] = e 85 | base.ServeJSON() 86 | base.StopRun() 87 | } 88 | 89 | var sqlOp = map[string]string{ 90 | "eq": "=", 91 | "ne": "<>", 92 | "gt": ">", 93 | "ge": ">=", 94 | "lt": "<", 95 | "le": "<=", 96 | } 97 | 98 | // ParseQueryParm parse query parameters. 99 | // query=col1:op1:val1,col2:op2:val2,... 100 | // op: one of eq, ne, gt, ge, lt, le 101 | //func (base *BaseController) ParseQueryParameter() (v map[string]string, o map[string]string, err error) { 102 | // var nameRule = regexp.MustCompile("^[a-zA-Z0-9_]+$") 103 | // queryVal := make(map[string]string) 104 | // queryOp := make(map[string]string) 105 | // 106 | // query := base.GetString("query") 107 | // if query == "" { 108 | // return queryVal, queryOp, nil 109 | // } 110 | // 111 | // for _, cond := range strings.Split(query, ",") { 112 | // kov := strings.Split(cond, ":") 113 | // if len(kov) != 3 { 114 | // return queryVal, queryOp, errors.New("Query format != k:o:v") 115 | // } 116 | // 117 | // var key string 118 | // var value string 119 | // var operator string 120 | // if !nameRule.MatchString(kov[0]) { 121 | // return queryVal, queryOp, errors.New("Query key format is wrong") 122 | // } 123 | // key = kov[0] 124 | // if op, ok := sqlOp[kov[1]]; ok { 125 | // operator = op 126 | // } else { 127 | // return queryVal, queryOp, errors.New("Query operator is wrong") 128 | // } 129 | // value = strings.Replace(kov[2], "'", "\\'", -1) 130 | // 131 | // queryVal[key] = value 132 | // queryOp[key] = operator 133 | // } 134 | // 135 | // return queryVal, queryOp, nil 136 | //} 137 | 138 | // ParseOrderParameter parse order parameters. 139 | // order=col1:asc|desc,col2:asc|esc,... 140 | //func (base *BaseController) ParseOrderParameter() (o map[string]string, err error) { 141 | // var nameRule = regexp.MustCompile("^[a-zA-Z0-9_]+$") 142 | // order := make(map[string]string) 143 | // 144 | // v := base.GetString("order") 145 | // if v == "" { 146 | // return order, nil 147 | // } 148 | // 149 | // for _, cond := range strings.Split(v, ",") { 150 | // kv := strings.Split(cond, ":") 151 | // if len(kv) != 2 { 152 | // return order, errors.New("Order format != k:v") 153 | // } 154 | // if !nameRule.MatchString(kv[0]) { 155 | // return order, errors.New("Order key format is wrong") 156 | // } 157 | // if kv[1] != "asc" && kv[1] != "desc" { 158 | // return order, errors.New("Order val isn't asc/desc") 159 | // } 160 | // 161 | // order[kv[0]] = kv[1] 162 | // } 163 | // 164 | // return order, nil 165 | //} 166 | 167 | // ParseLimitParameter parse limit parameter. 168 | // limit=n 169 | //func (base *BaseController) ParseLimitParameter() (l int64, err error) { 170 | // if v, err := base.GetInt64("limit"); err != nil { 171 | // return 10, err 172 | // } else if v > 0 { 173 | // return v, nil 174 | // } else { 175 | // return 10, nil 176 | // } 177 | //} 178 | 179 | // ParseOffsetParameter parse offset parameter. 180 | // offset=n 181 | //func (base *BaseController) ParseOffsetParameter() (o int64, err error) { 182 | // if v, err := base.GetInt64("offset"); err != nil { 183 | // return 0, err 184 | // } else if v > 0 { 185 | // return v, nil 186 | // } else { 187 | // return 0, nil 188 | // } 189 | //} 190 | 191 | // VerifyForm use validation to verify input parameters. 192 | //func (base *BaseController) VerifyForm(obj interface{}) (err error) { 193 | // valid := validation.Validation{} 194 | // ok, err := valid.Valid(obj) 195 | // if err != nil { 196 | // return err 197 | // } 198 | // if !ok { 199 | // str := "" 200 | // for _, err := range valid.Errors { 201 | // str += err.Key + ":" + err.Message + ";" 202 | // } 203 | // return errors.New(str) 204 | // } 205 | // 206 | // return nil 207 | //} 208 | 209 | // ParseToken parse JWT token in http header. 210 | //func (base *BaseController) ParseToken() (t *jwt.Token, e *ControllerError) { 211 | // authString := base.Ctx.Input.Header("Authorization") 212 | // beego.Debug("AuthString:", authString) 213 | // 214 | // kv := strings.Split(authString, " ") 215 | // if len(kv) != 2 || kv[0] != "Bearer" { 216 | // beego.Error("AuthString invalid:", authString) 217 | // return nil, errInputData 218 | // } 219 | // tokenString := kv[1] 220 | // 221 | // // Parse token 222 | // token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { 223 | // return []byte("secret"), nil 224 | // }) 225 | // if err != nil { 226 | // beego.Error("Parse token:", err) 227 | // if ve, ok := err.(*jwt.ValidationError); ok { 228 | // if ve.Errors&jwt.ValidationErrorMalformed != 0 { 229 | // // That's not even a token 230 | // return nil, errInputData 231 | // } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { 232 | // // Token is either expired or not active yet 233 | // return nil, errExpired 234 | // } else { 235 | // // Couldn't handle this token 236 | // return nil, errInputData 237 | // } 238 | // } else { 239 | // // Couldn't handle this token 240 | // return nil, errInputData 241 | // } 242 | // } 243 | // if !token.Valid { 244 | // beego.Error("Token invalid:", tokenString) 245 | // return nil, errInputData 246 | // } 247 | // beego.Debug("Token:", token) 248 | // 249 | // return token, nil 250 | //} 251 | -------------------------------------------------------------------------------- /controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | // MainController definition. 8 | type MainController struct { 9 | beego.Controller 10 | } 11 | 12 | // Get method. 13 | func (c *MainController) Get() { 14 | c.Data["Website"] = "www.liudp.cn" 15 | c.Data["Email"] = "rubinliu@hotmail.com" 16 | c.TplName = "index.tpl" 17 | c.Render() 18 | } 19 | -------------------------------------------------------------------------------- /controllers/device.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "strconv" 7 | "strings" 8 | "github.com/rubinliudongpo/airad/models" 9 | "github.com/astaxie/beego" 10 | "github.com/rubinliudongpo/airad/utils" 11 | "fmt" 12 | ) 13 | 14 | // DeviceController operations for Device 15 | type DeviceController struct { 16 | beego.Controller 17 | } 18 | 19 | // URLMapping ... 20 | func (c *DeviceController) URLMapping() { 21 | c.Mapping("Post", c.Post) 22 | c.Mapping("GetOne", c.GetOne) 23 | c.Mapping("GetAll", c.GetAll) 24 | c.Mapping("Put", c.Put) 25 | c.Mapping("Delete", c.Delete) 26 | } 27 | 28 | // Post ... 29 | // @Title Post 30 | // @Description create Device 31 | // @Param body body models.Device true "body for Device content" 32 | // @Success 201 {int} models.Device 33 | // @Failure 403 body is empty 34 | // @router / [post] 35 | func (c *DeviceController) Post() { 36 | var v models.Device 37 | token := c.Ctx.Input.Header("token") 38 | //id := c.Ctx.Input.Header("id") 39 | et := utils.EasyToken{} 40 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 41 | validation, err := et.ValidateToken(token) 42 | if !validation { 43 | c.Ctx.ResponseWriter.WriteHeader(401) 44 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 45 | c.ServeJSON() 46 | return 47 | } 48 | 49 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 50 | if errorMessage := utils.CheckNewDevicePost(v.UserId, v.DeviceName, 51 | v.Address, v.Status, v.Latitude, v.Longitude); errorMessage != "ok"{ 52 | c.Ctx.ResponseWriter.WriteHeader(403) 53 | c.Data["json"] = Response{403, 403,errorMessage, ""} 54 | c.ServeJSON() 55 | return 56 | } 57 | if models.CheckDeviceName(v.DeviceName){ 58 | c.Ctx.ResponseWriter.WriteHeader(403) 59 | c.Data["json"] = Response{403, 403,"设备名已经注册了", ""} 60 | c.ServeJSON() 61 | return 62 | } 63 | 64 | if !models.CheckUserId(v.UserId){ 65 | c.Ctx.ResponseWriter.WriteHeader(403) 66 | c.Data["json"] = Response{403, 403,"用户ID不存在", ""} 67 | c.ServeJSON() 68 | return 69 | } 70 | 71 | if !models.CheckUserIdAndToken(v.UserId, token){ 72 | c.Ctx.ResponseWriter.WriteHeader(403) 73 | c.Data["json"] = Response{403, 403,"用户ID和Token不匹配", ""} 74 | c.ServeJSON() 75 | return 76 | } 77 | 78 | if deviceId, err := models.AddDevice(&v); err == nil { 79 | if user, err := models.GetUserById(v.UserId); err == nil { 80 | models.UpdateUserDeviceCount(user) 81 | c.Ctx.Output.SetStatus(201) 82 | var returnData = &CreateObjectData{int(deviceId)} 83 | c.Data["json"] = &Response{0, 0, "ok", returnData} 84 | } else { 85 | c.Ctx.ResponseWriter.WriteHeader(403) 86 | c.Data["json"] = Response{403, 403,"用户Id不存在", ""} 87 | c.ServeJSON() 88 | return 89 | } 90 | 91 | c.Ctx.Output.SetStatus(201) 92 | var returnData = &CreateObjectData{int(deviceId)} 93 | c.Data["json"] = &Response{0, 0, "ok", returnData} 94 | } else { 95 | c.Data["json"] = err.Error() 96 | } 97 | } else { 98 | c.Data["json"] = &Response{1, 1, "设备名注册失败", err.Error()} 99 | } 100 | c.ServeJSON() 101 | } 102 | 103 | // GetOne ... 104 | // @Title Get One 105 | // @Description get Device by id 106 | // @Param id path string true "The key for staticblock" 107 | // @Success 200 {object} models.Device 108 | // @Failure 403 :id is empty 109 | // @router /:id [get] 110 | func (c *DeviceController) GetOne() { 111 | idStr := c.Ctx.Input.Param(":id") 112 | id, _ := strconv.Atoi(idStr) 113 | v, err := models.GetDeviceById(id) 114 | if err != nil { 115 | c.Data["json"] = err.Error() 116 | } else { 117 | c.Data["json"] = v 118 | } 119 | c.ServeJSON() 120 | } 121 | 122 | // GetAll ... 123 | // @Title Get All 124 | // @Description get Device 125 | // @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." 126 | // @Param fields query string false "Fields returned. e.g. col1,col2 ..." 127 | // @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." 128 | // @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." 129 | // @Param limit query string false "Limit the size of result set. Must be an integer" 130 | // @Param offset query string false "Start position of result set. Must be an integer" 131 | // @Success 200 {object} models.Device 132 | // @Failure 403 133 | // @router / [get] 134 | func (c *DeviceController) GetAll() { 135 | var fields []string 136 | var sortby []string 137 | var order []string 138 | var query = make(map[string]string) 139 | var limit int = 10 140 | var offset int 141 | var userId int 142 | 143 | token := c.Ctx.Input.Header("token") 144 | //id := c.Ctx.Input.Header("id") 145 | et := utils.EasyToken{} 146 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 147 | valido, err := et.ValidateToken(token) 148 | if !valido { 149 | c.Ctx.ResponseWriter.WriteHeader(401) 150 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 151 | c.ServeJSON() 152 | return 153 | } 154 | 155 | if found, user := models.GetUserByToken(token); !found { 156 | c.Ctx.Output.SetStatus(201) 157 | c.Data["json"] = &Response{401, 401, "未找到相关的用户", ""} 158 | c.ServeJSON() 159 | return 160 | } else { 161 | userId = user.Id 162 | } 163 | 164 | // fields: col1,col2,entity.col3 165 | if v := c.GetString("fields"); v != "" { 166 | fields = strings.Split(v, ",") 167 | } 168 | // limit: 10 (default is 10) 169 | if v, err := c.GetInt("limit"); err == nil { 170 | limit = v 171 | } 172 | // offset: 0 (default is 0) 173 | if v, err := c.GetInt("offset"); err == nil { 174 | offset = v 175 | } 176 | // sortby: col1,col2 177 | if v := c.GetString("sortby"); v != "" { 178 | sortby = strings.Split(v, ",") 179 | } 180 | // order: desc,asc 181 | if v := c.GetString("order"); v != "" { 182 | order = strings.Split(v, ",") 183 | } 184 | // query: k:v,k:v 185 | if v := c.GetString("query"); v != "" { 186 | for _, cond := range strings.Split(v, ",") { 187 | kv := strings.SplitN(cond, ":", 2) 188 | if len(kv) != 2 { 189 | c.Data["json"] = errors.New("Error: invalid query key/value pair") 190 | c.ServeJSON() 191 | return 192 | } 193 | k, v := kv[0], kv[1] 194 | query[k] = v 195 | } 196 | } 197 | 198 | l, totalCount, err := models.GetAllDevices(query, fields, sortby, order, offset, limit, userId) 199 | if err != nil { 200 | c.Data["json"] = err.Error() 201 | } else { 202 | var returnData = &GetDeviceData{totalCount, l} 203 | c.Data["json"] = &Response{0, 0, "ok", returnData} 204 | } 205 | c.ServeJSON() 206 | } 207 | 208 | // Put ... 209 | // @Title Put 210 | // @Description update the Device 211 | // @Param id path string true "The id you want to update" 212 | // @Param body body models.Device true "body for Device content" 213 | // @Success 200 {object} models.Device 214 | // @Failure 403 :id is not int 215 | // @router /:id [put] 216 | func (c *DeviceController) Put() { 217 | idStr := c.Ctx.Input.Param(":id") 218 | id, _ := strconv.Atoi(idStr) 219 | v := models.Device{Id: id} 220 | json.Unmarshal(c.Ctx.Input.RequestBody, &v) 221 | if err := models.UpdateDeviceById(&v); err == nil { 222 | c.Data["json"] = "OK" 223 | } else { 224 | c.Data["json"] = err.Error() 225 | } 226 | c.ServeJSON() 227 | } 228 | 229 | // Delete ... 230 | // @Title Delete 231 | // @Description delete the Device 232 | // @Param id path string true "The id you want to delete" 233 | // @Success 200 {string} delete success! 234 | // @Failure 403 id is empty 235 | // @router /:id [delete] 236 | func (c *DeviceController) Delete() { 237 | idStr := c.Ctx.Input.Param(":id") 238 | id, _ := strconv.Atoi(idStr) 239 | if err := models.DeleteDevice(id); err == nil { 240 | c.Data["json"] = "OK" 241 | } else { 242 | c.Data["json"] = err.Error() 243 | } 244 | c.ServeJSON() 245 | } 246 | 247 | // Delete ... 248 | // @Title Delete 249 | // @Description Get All Devices by User Id 250 | // @Param userId path int true 251 | // @Param limit path int true 252 | // @Param offset path int true 253 | // @Param fields path String true 254 | // @Param token path String true 255 | // @Success 200 {string} delete success! 256 | // @Failure 403 id is empty 257 | // @router /:id [post] 258 | func (c *DeviceController) GetDevicesByUserId() { 259 | var limit int = 10 260 | var offset int 261 | var fields []string 262 | var v models.DeviceRequestStruct 263 | 264 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 265 | if errorMessage := utils.CheckUserDevicePost(v.UserId, v.Limit, v.Offset); errorMessage != "ok"{ 266 | c.Ctx.ResponseWriter.WriteHeader(403) 267 | c.Data["json"] = Response{403, 403,errorMessage, ""} 268 | c.ServeJSON() 269 | return 270 | } 271 | if v := v.Fields; v != "" { 272 | fields = strings.Split(v, ",") 273 | } else { 274 | fields = strings.Split("DeviceName,Address,Status,Latitude,Longitude", ",") 275 | } 276 | // limit: 10 (default is 10) 277 | if para := v.Limit; para != 0 { 278 | limit = para 279 | } 280 | // offset: 0 (default is 0) 281 | if para := v.Offset; para != 0 { 282 | offset = para 283 | } 284 | if !models.CheckUserId(v.UserId){ 285 | c.Ctx.ResponseWriter.WriteHeader(403) 286 | c.Data["json"] = Response{403, 403,"用户ID不存在", ""} 287 | c.ServeJSON() 288 | return 289 | } 290 | if devices, err := models.GetDevicesByUserId(v.UserId, fields,limit, offset); err == nil { 291 | c.Data["json"] = devices 292 | } else { 293 | c.Data["json"] = err.Error() 294 | } 295 | } else { 296 | c.Data["json"] = &Response{1, 1, "设备结构解析失败", err.Error()} 297 | } 298 | c.ServeJSON() 299 | } -------------------------------------------------------------------------------- /controllers/error.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import "github.com/astaxie/beego" 4 | 5 | // ErrorController definition. 6 | type ErrorController struct { 7 | beego.Controller 8 | } 9 | 10 | 11 | func (c *ErrorController) Error404() { 12 | c.Data["json"] = Response{ 13 | ErrorCode: 404, 14 | ErrorMessage: "Not Found", 15 | } 16 | c.ServeJSON() 17 | } 18 | func (c *ErrorController) Error401() { 19 | c.Data["json"] = Response{ 20 | ErrorCode: 401, 21 | ErrorMessage: "Permission denied", 22 | } 23 | c.ServeJSON() 24 | } 25 | func (c *ErrorController) Error403() { 26 | c.Data["json"] = Response{ 27 | ErrorCode: 403, 28 | ErrorMessage: "Forbidden", 29 | } 30 | c.ServeJSON() 31 | } -------------------------------------------------------------------------------- /controllers/mqtt.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "strconv" 7 | "strings" 8 | "github.com/rubinliudongpo/airad/models" 9 | 10 | "github.com/astaxie/beego" 11 | ) 12 | 13 | // MqttController operations for Mqtt 14 | type MqttController struct { 15 | beego.Controller 16 | } 17 | 18 | // URLMapping ... 19 | func (c *MqttController) URLMapping() { 20 | c.Mapping("Post", c.Post) 21 | c.Mapping("GetOne", c.GetOne) 22 | c.Mapping("GetAll", c.GetAll) 23 | c.Mapping("Put", c.Put) 24 | c.Mapping("Delete", c.Delete) 25 | } 26 | 27 | // Post ... 28 | // @Title Post 29 | // @Description create Mqtt 30 | // @Param body body models.Mqtt true "body for Mqtt content" 31 | // @Success 201 {int} models.Mqtt 32 | // @Failure 403 body is empty 33 | // @router / [post] 34 | func (c *MqttController) Post() { 35 | var v models.Mqtt 36 | json.Unmarshal(c.Ctx.Input.RequestBody, &v) 37 | if _, err := models.AddMqtt(&v); err == nil { 38 | c.Ctx.Output.SetStatus(201) 39 | c.Data["json"] = v 40 | } else { 41 | c.Data["json"] = err.Error() 42 | } 43 | c.ServeJSON() 44 | } 45 | 46 | // GetOne ... 47 | // @Title Get One 48 | // @Description get Mqtt by id 49 | // @Param id path string true "The key for staticblock" 50 | // @Success 200 {object} models.Mqtt 51 | // @Failure 403 :id is empty 52 | // @router /:id [get] 53 | func (c *MqttController) GetOne() { 54 | idStr := c.Ctx.Input.Param(":id") 55 | id, _ := strconv.Atoi(idStr) 56 | v, err := models.GetMqttById(id) 57 | if err != nil { 58 | c.Data["json"] = err.Error() 59 | } else { 60 | c.Data["json"] = v 61 | } 62 | c.ServeJSON() 63 | } 64 | 65 | // GetAll ... 66 | // @Title Get All 67 | // @Description get Mqtt 68 | // @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." 69 | // @Param fields query string false "Fields returned. e.g. col1,col2 ..." 70 | // @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." 71 | // @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." 72 | // @Param limit query string false "Limit the size of result set. Must be an integer" 73 | // @Param offset query string false "Start position of result set. Must be an integer" 74 | // @Success 200 {object} models.Mqtt 75 | // @Failure 403 76 | // @router / [get] 77 | func (c *MqttController) GetAll() { 78 | var fields []string 79 | var sortby []string 80 | var order []string 81 | var query = make(map[string]string) 82 | var limit int64 = 10 83 | var offset int64 84 | 85 | // fields: col1,col2,entity.col3 86 | if v := c.GetString("fields"); v != "" { 87 | fields = strings.Split(v, ",") 88 | } 89 | // limit: 10 (default is 10) 90 | if v, err := c.GetInt64("limit"); err == nil { 91 | limit = v 92 | } 93 | // offset: 0 (default is 0) 94 | if v, err := c.GetInt64("offset"); err == nil { 95 | offset = v 96 | } 97 | // sortby: col1,col2 98 | if v := c.GetString("sortby"); v != "" { 99 | sortby = strings.Split(v, ",") 100 | } 101 | // order: desc,asc 102 | if v := c.GetString("order"); v != "" { 103 | order = strings.Split(v, ",") 104 | } 105 | // query: k:v,k:v 106 | if v := c.GetString("query"); v != "" { 107 | for _, cond := range strings.Split(v, ",") { 108 | kv := strings.SplitN(cond, ":", 2) 109 | if len(kv) != 2 { 110 | c.Data["json"] = errors.New("Error: invalid query key/value pair") 111 | c.ServeJSON() 112 | return 113 | } 114 | k, v := kv[0], kv[1] 115 | query[k] = v 116 | } 117 | } 118 | 119 | l, err := models.GetAllMqtt(query, fields, sortby, order, offset, limit) 120 | if err != nil { 121 | c.Data["json"] = err.Error() 122 | } else { 123 | c.Data["json"] = l 124 | } 125 | c.ServeJSON() 126 | } 127 | 128 | // Put ... 129 | // @Title Put 130 | // @Description update the Mqtt 131 | // @Param id path string true "The id you want to update" 132 | // @Param body body models.Mqtt true "body for Mqtt content" 133 | // @Success 200 {object} models.Mqtt 134 | // @Failure 403 :id is not int 135 | // @router /:id [put] 136 | func (c *MqttController) Put() { 137 | idStr := c.Ctx.Input.Param(":id") 138 | id, _ := strconv.Atoi(idStr) 139 | v := models.Mqtt{Id: id} 140 | json.Unmarshal(c.Ctx.Input.RequestBody, &v) 141 | if err := models.UpdateMqttById(&v); err == nil { 142 | c.Data["json"] = "OK" 143 | } else { 144 | c.Data["json"] = err.Error() 145 | } 146 | c.ServeJSON() 147 | } 148 | 149 | // Delete ... 150 | // @Title Delete 151 | // @Description delete the Mqtt 152 | // @Param id path string true "The id you want to delete" 153 | // @Success 200 {string} delete success! 154 | // @Failure 403 id is empty 155 | // @router /:id [delete] 156 | func (c *MqttController) Delete() { 157 | idStr := c.Ctx.Input.Param(":id") 158 | id, _ := strconv.Atoi(idStr) 159 | if err := models.DeleteMqtt(id); err == nil { 160 | c.Data["json"] = "OK" 161 | } else { 162 | c.Data["json"] = err.Error() 163 | } 164 | c.ServeJSON() 165 | } 166 | -------------------------------------------------------------------------------- /controllers/mqttoption.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "strconv" 7 | "strings" 8 | "github.com/rubinliudongpo/airad/models" 9 | 10 | "github.com/astaxie/beego" 11 | ) 12 | 13 | // MqttOptionController operations for MqttOption 14 | type MqttOptionController struct { 15 | beego.Controller 16 | } 17 | 18 | // URLMapping ... 19 | func (c *MqttOptionController) URLMapping() { 20 | c.Mapping("Post", c.Post) 21 | c.Mapping("GetOne", c.GetOne) 22 | c.Mapping("GetAll", c.GetAll) 23 | c.Mapping("Put", c.Put) 24 | c.Mapping("Delete", c.Delete) 25 | } 26 | 27 | // Post ... 28 | // @Title Post 29 | // @Description create MqttOption 30 | // @Param body body models.MqttOption true "body for MqttOption content" 31 | // @Success 201 {int} models.MqttOption 32 | // @Failure 403 body is empty 33 | // @router / [post] 34 | func (c *MqttOptionController) Post() { 35 | var v models.MqttOption 36 | json.Unmarshal(c.Ctx.Input.RequestBody, &v) 37 | if _, err := models.AddMqttOption(&v); err == nil { 38 | c.Ctx.Output.SetStatus(201) 39 | c.Data["json"] = v 40 | } else { 41 | c.Data["json"] = err.Error() 42 | } 43 | c.ServeJSON() 44 | } 45 | 46 | // GetOne ... 47 | // @Title Get One 48 | // @Description get MqttOption by id 49 | // @Param id path string true "The key for staticblock" 50 | // @Success 200 {object} models.MqttOption 51 | // @Failure 403 :id is empty 52 | // @router /:id [get] 53 | func (c *MqttOptionController) GetOne() { 54 | idStr := c.Ctx.Input.Param(":id") 55 | id, _ := strconv.Atoi(idStr) 56 | v, err := models.GetMqttOptionById(id) 57 | if err != nil { 58 | c.Data["json"] = err.Error() 59 | } else { 60 | c.Data["json"] = v 61 | } 62 | c.ServeJSON() 63 | } 64 | 65 | // GetAll ... 66 | // @Title Get All 67 | // @Description get MqttOption 68 | // @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." 69 | // @Param fields query string false "Fields returned. e.g. col1,col2 ..." 70 | // @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." 71 | // @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." 72 | // @Param limit query string false "Limit the size of result set. Must be an integer" 73 | // @Param offset query string false "Start position of result set. Must be an integer" 74 | // @Success 200 {object} models.MqttOption 75 | // @Failure 403 76 | // @router / [get] 77 | func (c *MqttOptionController) GetAll() { 78 | var fields []string 79 | var sortby []string 80 | var order []string 81 | var query = make(map[string]string) 82 | var limit int64 = 10 83 | var offset int64 84 | 85 | // fields: col1,col2,entity.col3 86 | if v := c.GetString("fields"); v != "" { 87 | fields = strings.Split(v, ",") 88 | } 89 | // limit: 10 (default is 10) 90 | if v, err := c.GetInt64("limit"); err == nil { 91 | limit = v 92 | } 93 | // offset: 0 (default is 0) 94 | if v, err := c.GetInt64("offset"); err == nil { 95 | offset = v 96 | } 97 | // sortby: col1,col2 98 | if v := c.GetString("sortby"); v != "" { 99 | sortby = strings.Split(v, ",") 100 | } 101 | // order: desc,asc 102 | if v := c.GetString("order"); v != "" { 103 | order = strings.Split(v, ",") 104 | } 105 | // query: k:v,k:v 106 | if v := c.GetString("query"); v != "" { 107 | for _, cond := range strings.Split(v, ",") { 108 | kv := strings.SplitN(cond, ":", 2) 109 | if len(kv) != 2 { 110 | c.Data["json"] = errors.New("Error: invalid query key/value pair") 111 | c.ServeJSON() 112 | return 113 | } 114 | k, v := kv[0], kv[1] 115 | query[k] = v 116 | } 117 | } 118 | 119 | l, err := models.GetAllMqttOption(query, fields, sortby, order, offset, limit) 120 | if err != nil { 121 | c.Data["json"] = err.Error() 122 | } else { 123 | c.Data["json"] = l 124 | } 125 | c.ServeJSON() 126 | } 127 | 128 | // Put ... 129 | // @Title Put 130 | // @Description update the MqttOption 131 | // @Param id path string true "The id you want to update" 132 | // @Param body body models.MqttOption true "body for MqttOption content" 133 | // @Success 200 {object} models.MqttOption 134 | // @Failure 403 :id is not int 135 | // @router /:id [put] 136 | func (c *MqttOptionController) Put() { 137 | idStr := c.Ctx.Input.Param(":id") 138 | id, _ := strconv.Atoi(idStr) 139 | v := models.MqttOption{Id: id} 140 | json.Unmarshal(c.Ctx.Input.RequestBody, &v) 141 | if err := models.UpdateMqttOptionById(&v); err == nil { 142 | c.Data["json"] = "OK" 143 | } else { 144 | c.Data["json"] = err.Error() 145 | } 146 | c.ServeJSON() 147 | } 148 | 149 | // Delete ... 150 | // @Title Delete 151 | // @Description delete the MqttOption 152 | // @Param id path string true "The id you want to delete" 153 | // @Success 200 {string} delete success! 154 | // @Failure 403 id is empty 155 | // @router /:id [delete] 156 | func (c *MqttOptionController) Delete() { 157 | idStr := c.Ctx.Input.Param(":id") 158 | id, _ := strconv.Atoi(idStr) 159 | if err := models.DeleteMqttOption(id); err == nil { 160 | c.Data["json"] = "OK" 161 | } else { 162 | c.Data["json"] = err.Error() 163 | } 164 | c.ServeJSON() 165 | } 166 | -------------------------------------------------------------------------------- /controllers/object.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/rubinliudongpo/airad/models" 5 | "encoding/json" 6 | 7 | "github.com/astaxie/beego" 8 | ) 9 | 10 | // Operations about object 11 | type ObjectController struct { 12 | beego.Controller 13 | } 14 | 15 | // @Title Create 16 | // @Description create object 17 | // @Param body body models.Object true "The object content" 18 | // @Success 200 {string} models.Object.Id 19 | // @Failure 403 body is empty 20 | // @router / [post] 21 | func (o *ObjectController) Post() { 22 | var ob models.Object 23 | json.Unmarshal(o.Ctx.Input.RequestBody, &ob) 24 | objectid := models.AddOne(ob) 25 | o.Data["json"] = map[string]string{"ObjectId": objectid} 26 | o.ServeJSON() 27 | } 28 | 29 | // @Title Get 30 | // @Description find object by objectid 31 | // @Param objectId path string true "the objectid you want to get" 32 | // @Success 200 {object} models.Object 33 | // @Failure 403 :objectId is empty 34 | // @router /:objectId [get] 35 | func (o *ObjectController) Get() { 36 | objectId := o.Ctx.Input.Param(":objectId") 37 | if objectId != "" { 38 | ob, err := models.GetOne(objectId) 39 | if err != nil { 40 | o.Data["json"] = err.Error() 41 | } else { 42 | o.Data["json"] = ob 43 | } 44 | } 45 | o.ServeJSON() 46 | } 47 | 48 | // @Title GetAll 49 | // @Description get all objects 50 | // @Success 200 {object} models.Object 51 | // @Failure 403 :objectId is empty 52 | // @router / [get] 53 | func (o *ObjectController) GetAll() { 54 | obs := models.GetAll() 55 | o.Data["json"] = obs 56 | o.ServeJSON() 57 | } 58 | 59 | // @Title Update 60 | // @Description update the object 61 | // @Param objectId path string true "The objectid you want to update" 62 | // @Param body body models.Object true "The body" 63 | // @Success 200 {object} models.Object 64 | // @Failure 403 :objectId is empty 65 | // @router /:objectId [put] 66 | func (o *ObjectController) Put() { 67 | objectId := o.Ctx.Input.Param(":objectId") 68 | var ob models.Object 69 | json.Unmarshal(o.Ctx.Input.RequestBody, &ob) 70 | 71 | err := models.Update(objectId, ob.Score) 72 | if err != nil { 73 | o.Data["json"] = err.Error() 74 | } else { 75 | o.Data["json"] = "update success!" 76 | } 77 | o.ServeJSON() 78 | } 79 | 80 | // @Title Delete 81 | // @Description delete the object 82 | // @Param objectId path string true "The objectId you want to delete" 83 | // @Success 200 {string} delete success! 84 | // @Failure 403 objectId is empty 85 | // @router /:objectId [delete] 86 | func (o *ObjectController) Delete() { 87 | objectId := o.Ctx.Input.Param(":objectId") 88 | models.Delete(objectId) 89 | o.Data["json"] = "delete success!" 90 | o.ServeJSON() 91 | } 92 | 93 | -------------------------------------------------------------------------------- /controllers/user.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/rubinliudongpo/airad/models" 5 | "github.com/rubinliudongpo/airad/utils" 6 | "encoding/json" 7 | "errors" 8 | "github.com/astaxie/beego" 9 | "strings" 10 | "strconv" 11 | "time" 12 | "fmt" 13 | ) 14 | 15 | // Operations about Users 16 | type UserController struct { 17 | beego.Controller 18 | } 19 | 20 | // URLMapping ... 21 | func (c *UserController) URLMapping() { 22 | c.Mapping("Post", c.Post) 23 | c.Mapping("GetOne", c.GetOne) 24 | c.Mapping("GetAll", c.GetAll) 25 | c.Mapping("Put", c.Put) 26 | c.Mapping("Delete", c.Delete) 27 | } 28 | 29 | // @Title CreateUser 30 | // @Description create users 31 | // @Param body body models.User true "body for user content" 32 | // @Success 200 {int} models.User.Id 33 | // @Failure 403 body is empty 34 | // @router / [post] 35 | func (c *UserController) Post() { 36 | var v models.User 37 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 38 | if errorMessage := utils.CheckNewUserPost(v.Username, v.Password, 39 | v.Age, v.Gender, v.Address, v.Email); errorMessage != "ok"{ 40 | c.Ctx.ResponseWriter.WriteHeader(403) 41 | c.Data["json"] = Response{403, 403,errorMessage, ""} 42 | c.ServeJSON() 43 | return 44 | } 45 | if models.CheckUserName(v.Username){ 46 | c.Ctx.ResponseWriter.WriteHeader(403) 47 | c.Data["json"] = Response{403, 403,"用户名称已经注册了", ""} 48 | c.ServeJSON() 49 | return 50 | } 51 | if models.CheckEmail(v.Email) { 52 | c.Ctx.ResponseWriter.WriteHeader(403) 53 | c.Data["json"] = Response{403, 403,"邮箱已经注册了", ""} 54 | c.ServeJSON() 55 | return 56 | } 57 | 58 | if user, err := models.AddUser(&v); err == nil { 59 | c.Ctx.Output.SetStatus(201) 60 | var returnData = &UserSuccessLoginData{user.Token, user.Username} 61 | c.Data["json"] = &Response{0, 0, "ok", returnData} 62 | } else { 63 | c.Data["json"] = &Response{1, 1, "用户注册失败", err.Error()} 64 | } 65 | } else { 66 | c.Data["json"] = &Response{1, 1, "用户注册失败", err.Error()} 67 | } 68 | c.ServeJSON() 69 | } 70 | 71 | // @Title GetAll 72 | // @Description get all Users 73 | // @Success 200 {object} models.User 74 | // @router / [get] 75 | func (c *UserController) GetAll() { 76 | var fields []string 77 | var sortby []string 78 | var order []string 79 | var query = make(map[string]string) 80 | var limit int = 10 81 | var offset int 82 | 83 | token := c.Ctx.Input.Header("token") 84 | //id := c.Ctx.Input.Header("id") 85 | et := utils.EasyToken{} 86 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 87 | validation, err := et.ValidateToken(token) 88 | if !validation { 89 | c.Ctx.ResponseWriter.WriteHeader(401) 90 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 91 | c.ServeJSON() 92 | return 93 | } 94 | 95 | // fields: col1,col2,entity.col3 96 | if v := c.GetString("fields"); v != "" { 97 | fields = strings.Split(v, ",") 98 | } else { 99 | fields = strings.Split("Username,Gender,Age,Address,Email,Token", ",") 100 | } 101 | // limit: 10 (default is 10) 102 | if v, err := c.GetInt("limit"); err == nil { 103 | limit = v 104 | } 105 | // offset: 0 (default is 0) 106 | if v, err := c.GetInt("offset"); err == nil { 107 | offset = v 108 | } 109 | // sortby: col1,col2 110 | if v := c.GetString("sortby"); v != "" { 111 | sortby = strings.Split(v, ",") 112 | } 113 | // order: desc,asc 114 | if v := c.GetString("order"); v != "" { 115 | order = strings.Split(v, ",") 116 | } 117 | // query: k:v,k:v 118 | if v := c.GetString("query"); v != "" { 119 | for _, cond := range strings.Split(v, ",") { 120 | kv := strings.SplitN(cond, ":", 2) 121 | if len(kv) != 2 { 122 | c.Data["json"] = errors.New("Error: invalid query key/value pair") 123 | c.ServeJSON() 124 | return 125 | } 126 | k, v := kv[0], kv[1] 127 | query[k] = v 128 | } 129 | } 130 | 131 | l, err := models.GetAllUser(query, fields, sortby, order, offset, limit) 132 | if err != nil { 133 | c.Data["json"] = err.Error() 134 | } else { 135 | c.Data["json"] = l 136 | } 137 | c.ServeJSON() 138 | } 139 | 140 | // GetOne ... 141 | // @Title GetOne 142 | // @Description get User by id 143 | // @Param id path string true "The key for static block" 144 | // @Success 200 {object} models.AirAd 145 | // @Failure 403 :id is empty 146 | // @router /:id [get] 147 | func (c *UserController) GetOne() { 148 | token := c.Ctx.Input.Header("token") 149 | //idStr := c.Ctx.Input.Param("id") 150 | idStr := c.Ctx.Input.Param(":id") 151 | //token := c.Ctx.Input.Param(":token") 152 | et := utils.EasyToken{} 153 | //token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 154 | valido, err := et.ValidateToken(token) 155 | if !valido { 156 | c.Ctx.ResponseWriter.WriteHeader(401) 157 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 158 | c.ServeJSON() 159 | return 160 | } 161 | 162 | id, _ := strconv.Atoi(idStr) 163 | v, err := models.GetUserById(id) 164 | if v == nil { 165 | c.Data["json"] = err.Error() 166 | } else { 167 | c.Data["json"] = v 168 | } 169 | c.ServeJSON() 170 | 171 | } 172 | 173 | // @Title Update 174 | // @Description update the user 175 | // @Param uid path string true "The uid you want to update" 176 | // @Param body body models.User true "body for user content" 177 | // @Success 200 {object} models.User 178 | // @Failure 403 :uid is not int 179 | // @router /:uid [put] 180 | func (c *UserController) Put() { 181 | idStr := c.Ctx.Input.Param(":id") 182 | id, _ := strconv.Atoi(idStr) 183 | v := models.User{Id: id} 184 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil { 185 | if err := models.UpdateUserById(&v); err == nil { 186 | c.Data["json"] = successReturn 187 | } else { 188 | c.Data["json"] = err.Error() 189 | } 190 | } else { 191 | c.Data["json"] = err.Error() 192 | } 193 | c.ServeJSON() 194 | } 195 | 196 | // @Title Delete 197 | // @Description delete the user 198 | // @Param uid path string true "The uid you want to delete" 199 | // @Success 200 {string} delete success! 200 | // @Failure 403 uid is empty 201 | // @router /:uid [delete] 202 | func (c *UserController) Delete() { 203 | idStr := c.Ctx.Input.Param(":id") 204 | id, _ := strconv.Atoi(idStr) 205 | if err := models.DeleteUser(id); err == nil { 206 | c.Data["json"] = successReturn 207 | } else { 208 | c.Data["json"] = err.Error() 209 | } 210 | c.ServeJSON() 211 | } 212 | 213 | // @Title Login 214 | // @Description Logs user into the system 215 | // @Param username query string true "The username for login" 216 | // @Param password query string true "The password for login" 217 | // @Success 200 {string} login success 218 | // @Failure 403 user not exist 219 | // @router /login [POST] 220 | func (c *UserController) Login() { 221 | var reqData struct { 222 | Username string `valid:"Required"` 223 | Password string `valid:"Required"` 224 | } 225 | var token string 226 | 227 | if err := json.Unmarshal(c.Ctx.Input.RequestBody, &reqData); err == nil { 228 | if errorMessage := utils.CheckUsernamePassword(reqData.Username, reqData.Password); errorMessage != "ok"{ 229 | c.Ctx.ResponseWriter.WriteHeader(403) 230 | c.Data["json"] = Response{403, 403,errorMessage, ""} 231 | c.ServeJSON() 232 | return 233 | } 234 | if ok, user := models.Login(reqData.Username, reqData.Password); ok { 235 | et := utils.EasyToken{} 236 | validation, err := et.ValidateToken(user.Token) 237 | if !validation { 238 | et = utils.EasyToken{ 239 | Username: user.Username, 240 | Uid: int64(user.Id), 241 | Expires: time.Now().Unix() + 2 * 3600, 242 | } 243 | token, err = et.GetToken() 244 | if token == "" || err != nil { 245 | c.Data["json"] = errUserToken 246 | c.ServeJSON() 247 | return 248 | } else { 249 | models.UpdateUserToken(user, token) 250 | } 251 | } else { 252 | token = user.Token 253 | } 254 | models.UpdateUserLastLogin(user) 255 | 256 | var returnData = &UserSuccessLoginData{token, user.Username} 257 | c.Data["json"] = &Response{0, 0, "ok", returnData} 258 | } else { 259 | c.Data["json"] = &errNoUserOrPass 260 | } 261 | } else { 262 | c.Data["json"] = &errNoUserOrPass 263 | } 264 | c.ServeJSON() 265 | } 266 | 267 | // @Title 认证测试 268 | // @Description 测试错误码 269 | // @Success 200 {object} 270 | // @Failure 401 unauthorized 271 | // @router /auth [get] 272 | func (c *UserController) Auth() { 273 | et := utils.EasyToken{} 274 | token := strings.TrimSpace(c.Ctx.Request.Header.Get("Authorization")) 275 | validation, err := et.ValidateToken(token) 276 | if !validation { 277 | c.Ctx.ResponseWriter.WriteHeader(401) 278 | c.Data["json"] = Response{401, 401, fmt.Sprintf("%s", err), ""} 279 | c.ServeJSON() 280 | return 281 | } 282 | 283 | c.Data["json"] = Response{0, 0, "is login", ""} 284 | c.ServeJSON() 285 | } 286 | 287 | // @Title logout 288 | // @Description Logs out current logged in user session 289 | // @Success 200 {string} logout success 290 | // @router /logout [get] 291 | func (u *UserController) Logout() { 292 | u.Data["json"] = successReturn 293 | u.ServeJSON() 294 | } 295 | 296 | -------------------------------------------------------------------------------- /database/airad.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.7.19, for osx10.12 (x86_64) 2 | -- 3 | -- Host: localhost Database: airad 4 | -- ------------------------------------------------------ 5 | -- Server version 5.7.19 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `air_ad` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `air_ad`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!40101 SET character_set_client = utf8 */; 25 | CREATE TABLE `air_ad` ( 26 | `id` int(11) NOT NULL AUTO_INCREMENT, 27 | `device_id` int(11) NOT NULL DEFAULT '0', 28 | `created_at` bigint(20) NOT NULL DEFAULT '0', 29 | `nh3` varchar(4) NOT NULL DEFAULT '', 30 | `co` varchar(4) NOT NULL DEFAULT '', 31 | `o3` varchar(4) NOT NULL DEFAULT '', 32 | `pm25` varchar(4) NOT NULL DEFAULT '', 33 | `pm10` varchar(4) NOT NULL DEFAULT '', 34 | `so2` varchar(4) NOT NULL DEFAULT '', 35 | `temperature` varchar(4) NOT NULL DEFAULT '', 36 | `humidity` varchar(4) NOT NULL DEFAULT '', 37 | `aqi_quality` varchar(4) NOT NULL DEFAULT '', 38 | `suggest` varchar(4) NOT NULL DEFAULT '', 39 | PRIMARY KEY (`id`) 40 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 41 | /*!40101 SET character_set_client = @saved_cs_client */; 42 | 43 | -- 44 | -- Dumping data for table `air_ad` 45 | -- 46 | 47 | LOCK TABLES `air_ad` WRITE; 48 | /*!40000 ALTER TABLE `air_ad` DISABLE KEYS */; 49 | /*!40000 ALTER TABLE `air_ad` ENABLE KEYS */; 50 | UNLOCK TABLES; 51 | 52 | -- 53 | -- Table structure for table `device` 54 | -- 55 | 56 | DROP TABLE IF EXISTS `device`; 57 | /*!40101 SET @saved_cs_client = @@character_set_client */; 58 | /*!40101 SET character_set_client = utf8 */; 59 | CREATE TABLE `device` ( 60 | `id` int(11) NOT NULL AUTO_INCREMENT, 61 | `user_id` int(11) NOT NULL DEFAULT '0', 62 | `device_name` varchar(32) NOT NULL DEFAULT '', 63 | `address` varchar(50) NOT NULL DEFAULT '', 64 | `status` int(11) NOT NULL DEFAULT '0', 65 | `created_at` bigint(20) NOT NULL DEFAULT '0', 66 | `updated_at` bigint(20) NOT NULL DEFAULT '0', 67 | `latitude` varchar(12) NOT NULL DEFAULT '', 68 | `longitude` varchar(12) NOT NULL DEFAULT '', 69 | `airad_count` bigint(20) NOT NULL DEFAULT '0', 70 | PRIMARY KEY (`id`), 71 | UNIQUE KEY `device_name` (`device_name`) 72 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 73 | /*!40101 SET character_set_client = @saved_cs_client */; 74 | 75 | -- 76 | -- Dumping data for table `device` 77 | -- 78 | 79 | LOCK TABLES `device` WRITE; 80 | /*!40000 ALTER TABLE `device` DISABLE KEYS */; 81 | /*!40000 ALTER TABLE `device` ENABLE KEYS */; 82 | UNLOCK TABLES; 83 | 84 | -- 85 | -- Table structure for table `mqtt` 86 | -- 87 | 88 | DROP TABLE IF EXISTS `mqtt`; 89 | /*!40101 SET @saved_cs_client = @@character_set_client */; 90 | /*!40101 SET character_set_client = utf8 */; 91 | CREATE TABLE `mqtt` ( 92 | `id` int(11) NOT NULL AUTO_INCREMENT, 93 | `device_id` int(11) NOT NULL DEFAULT '0', 94 | `mqtt_option_id` int(11) NOT NULL DEFAULT '0', 95 | `qos` tinyint(3) unsigned NOT NULL DEFAULT '0', 96 | `retain` tinyint(1) NOT NULL DEFAULT '0', 97 | `topic_name` varchar(255) NOT NULL DEFAULT '', 98 | `topic_filter` varchar(255) NOT NULL DEFAULT '', 99 | PRIMARY KEY (`id`) 100 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 101 | /*!40101 SET character_set_client = @saved_cs_client */; 102 | 103 | -- 104 | -- Dumping data for table `mqtt` 105 | -- 106 | 107 | LOCK TABLES `mqtt` WRITE; 108 | /*!40000 ALTER TABLE `mqtt` DISABLE KEYS */; 109 | /*!40000 ALTER TABLE `mqtt` ENABLE KEYS */; 110 | UNLOCK TABLES; 111 | 112 | -- 113 | -- Table structure for table `mqtt_option` 114 | -- 115 | 116 | DROP TABLE IF EXISTS `mqtt_option`; 117 | /*!40101 SET @saved_cs_client = @@character_set_client */; 118 | /*!40101 SET character_set_client = utf8 */; 119 | CREATE TABLE `mqtt_option` ( 120 | `id` int(11) NOT NULL AUTO_INCREMENT, 121 | `client_id` varchar(255) NOT NULL DEFAULT '', 122 | `conn_ack_timeout` bigint(20) NOT NULL DEFAULT '0', 123 | `user_name` varchar(32) NOT NULL DEFAULT '', 124 | `password` varchar(128) NOT NULL DEFAULT '', 125 | `clean_session` tinyint(1) NOT NULL DEFAULT '0', 126 | `keep_alive` smallint(5) unsigned NOT NULL DEFAULT '0', 127 | `will_topic` varchar(255) NOT NULL DEFAULT '', 128 | `will_message` varchar(255) NOT NULL DEFAULT '', 129 | `will_qos` tinyint(1) NOT NULL DEFAULT '0', 130 | `will_retain` tinyint(1) NOT NULL DEFAULT '0', 131 | PRIMARY KEY (`id`) 132 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 133 | /*!40101 SET character_set_client = @saved_cs_client */; 134 | 135 | -- 136 | -- Dumping data for table `mqtt_option` 137 | -- 138 | 139 | LOCK TABLES `mqtt_option` WRITE; 140 | /*!40000 ALTER TABLE `mqtt_option` DISABLE KEYS */; 141 | /*!40000 ALTER TABLE `mqtt_option` ENABLE KEYS */; 142 | UNLOCK TABLES; 143 | 144 | -- 145 | -- Table structure for table `user` 146 | -- 147 | 148 | DROP TABLE IF EXISTS `user`; 149 | /*!40101 SET @saved_cs_client = @@character_set_client */; 150 | /*!40101 SET character_set_client = utf8 */; 151 | CREATE TABLE `user` ( 152 | `id` int(11) NOT NULL AUTO_INCREMENT, 153 | `username` varchar(32) NOT NULL DEFAULT '', 154 | `password` varchar(128) NOT NULL DEFAULT '', 155 | `salt` varchar(128) NOT NULL DEFAULT '', 156 | `token` varchar(256) NOT NULL DEFAULT '', 157 | `gender` int(11) NOT NULL DEFAULT '0', 158 | `age` int(11) NOT NULL DEFAULT '0', 159 | `address` varchar(50) NOT NULL DEFAULT '', 160 | `email` varchar(50) NOT NULL DEFAULT '', 161 | `last_login` bigint(20) NOT NULL DEFAULT '0', 162 | `status` int(11) NOT NULL DEFAULT '0', 163 | `created_at` bigint(20) NOT NULL DEFAULT '0', 164 | `updated_at` bigint(20) NOT NULL DEFAULT '0', 165 | `device_count` int(11) NOT NULL DEFAULT '0', 166 | PRIMARY KEY (`id`), 167 | UNIQUE KEY `username` (`username`) 168 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 169 | /*!40101 SET character_set_client = @saved_cs_client */; 170 | 171 | -- 172 | -- Dumping data for table `user` 173 | -- 174 | 175 | LOCK TABLES `user` WRITE; 176 | /*!40000 ALTER TABLE `user` DISABLE KEYS */; 177 | /*!40000 ALTER TABLE `user` ENABLE KEYS */; 178 | UNLOCK TABLES; 179 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 180 | 181 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 182 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 183 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 184 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 185 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 186 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 187 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 188 | 189 | -- Dump completed on 2018-04-16 11:49:30 190 | -------------------------------------------------------------------------------- /logs/logs.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/logs/logs.log -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | import ( 5 | _ "github.com/rubinliudongpo/airad/routers" 6 | "github.com/rubinliudongpo/airad/utils" 7 | 8 | 9 | "github.com/astaxie/beego" 10 | "github.com/rubinliudongpo/airad/controllers" 11 | ) 12 | 13 | func main() { 14 | utils.InitSql() 15 | utils.InitTemplate() 16 | utils.InitCache() 17 | utils.InitBootStrap() 18 | beego.ErrorController(&controllers.ErrorController{}) 19 | 20 | beego.Run() 21 | } -------------------------------------------------------------------------------- /models/airad.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | "github.com/astaxie/beego/orm" 9 | "time" 10 | ) 11 | 12 | type AirAd struct { 13 | Id int `json:"id, omitempty" orm:"column(id);pk;unique;auto_increment"` 14 | DeviceId int `json:"device_id" orm:"column(device_id);size(11)"` 15 | CreatedAt int64 `json:"created_at, omitempty" orm:"column(created_at);size(11)"` 16 | Nh3 string `json:"nh3, omitempty" orm:"column(nh3);size(4)"` 17 | Co string `json:"co, omitempty" orm:"column(co);size(4)"` 18 | O3 string `json:"o3, omitempty" orm:"column(o3);size(4)"` 19 | Pm25 string `json:"pm25, omitempty" orm:"column(pm25);size(4)"` 20 | Pm10 string `json:"pm10, omitempty" orm:"column(pm10);size(4)"` 21 | So2 string `json:"so2, omitempty" orm:"column(so2);size(4)"` 22 | Temperature string `json:"temperature, omitempty" orm:"column(temperature);size(4)"` 23 | Humidity string `json:"humidity, omitempty" orm:"column(humidity);size(4)"` 24 | AqiQuality string `json:"aqi_quality, omitempty" orm:"column(aqi_quality);size(4)"` 25 | Suggest string `json:"suggest, omitempty" orm:"column(suggest);size(4)"` 26 | //Device *Device `orm:"rel(fk)"` 27 | } 28 | 29 | func init() { 30 | orm.RegisterModel(new(AirAd)) 31 | } 32 | 33 | func AirAds() orm.QuerySeter { 34 | return orm.NewOrm().QueryTable(new(AirAd)) 35 | } 36 | 37 | // AddAirAd insert a new AirAd into database and returns 38 | // last inserted Id on success. 39 | func AddAirAd(m *AirAd) (id int64, err error) { 40 | o := orm.NewOrm() 41 | 42 | CreatedAt := time.Now().UTC().Unix() 43 | 44 | airAd := AirAd{ 45 | DeviceId:m.DeviceId, 46 | Nh3:m.Nh3, 47 | Pm10:m.Pm10, 48 | Pm25:m.Pm25, 49 | Co:m.Co, 50 | O3:m.O3, 51 | So2:m.So2, 52 | Temperature:m.Temperature, 53 | Humidity:m.Humidity, 54 | AqiQuality:m.AqiQuality, 55 | Suggest:m.Suggest, 56 | CreatedAt:CreatedAt, 57 | } 58 | 59 | id, err = o.Insert(&airAd) 60 | if err == nil{ 61 | return id, err 62 | } 63 | 64 | return 0, err 65 | } 66 | 67 | // GetAirAdById retrieves AirAd by Id. Returns error if 68 | // Id doesn't exist 69 | func GetAirAdById(id int) (v *AirAd, err error) { 70 | o := orm.NewOrm() 71 | v = &AirAd{Id: id} 72 | if err = o.QueryTable(new(AirAd)).Filter("Id", id).RelatedSel().One(v); err == nil { 73 | return v, nil 74 | } 75 | return nil, err 76 | } 77 | 78 | // 检测DeviceId是否存在 79 | func CheckDeviceId(deviceId int) bool { 80 | exist := Devices().Filter("Id", deviceId).Exist() 81 | return exist 82 | } 83 | 84 | // 检测DeviceId vs. Token 是否匹配 85 | func CheckDeviceIdAndToken(deviceId int, token string) bool { 86 | o := orm.NewOrm() 87 | var device Device 88 | if err := o.QueryTable(new(Device)).Filter("Id", deviceId).RelatedSel().One(&device); err == nil { 89 | exist := Users().Filter("Id", device.UserId).Filter("Token", token).Exist() 90 | return exist 91 | } 92 | return false 93 | } 94 | 95 | 96 | // GetAllAirAds retrieves all AirAd matches certain condition. Returns empty list if 97 | // no records exist 98 | func GetAllAirAds(query map[string]string, fields []string, sortby []string, order []string, 99 | offset int, limit int, deviceId int) (ml []interface{}, totalCount int64,err error) { 100 | o := orm.NewOrm() 101 | qs := o.QueryTable(new(AirAd)) 102 | // query k=v 103 | for k, v := range query { 104 | // rewrite dot-notation to Object__Attribute 105 | k = strings.Replace(k, ".", "__", -1) 106 | qs = qs.Filter(k, v) 107 | } 108 | // order by: 109 | var sortFields []string 110 | if len(sortby) != 0 { 111 | if len(sortby) == len(order) { 112 | // 1) for each sort field, there is an associated order 113 | for i, v := range sortby { 114 | orderby := "" 115 | if order[i] == "desc" { 116 | orderby = "-" + v 117 | } else if order[i] == "asc" { 118 | orderby = v 119 | } else { 120 | return nil, 0,errors.New("Error: Invalid order. Must be either [asc|desc]") 121 | } 122 | sortFields = append(sortFields, orderby) 123 | } 124 | qs = qs.OrderBy(sortFields...) 125 | } else if len(sortby) != len(order) && len(order) == 1 { 126 | // 2) there is exactly one order, all the sorted fields will be sorted by this order 127 | for _, v := range sortby { 128 | orderby := "" 129 | if order[0] == "desc" { 130 | orderby = "-" + v 131 | } else if order[0] == "asc" { 132 | orderby = v 133 | } else { 134 | return nil, 0, errors.New("Error: Invalid order. Must be either [asc|desc]") 135 | } 136 | sortFields = append(sortFields, orderby) 137 | } 138 | } else if len(sortby) != len(order) && len(order) != 1 { 139 | return nil, 0, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") 140 | } 141 | } else { 142 | if len(order) != 0 { 143 | return nil, 0, errors.New("Error: unused 'order' fields") 144 | } 145 | } 146 | 147 | var l []AirAd 148 | qs = qs.OrderBy(sortFields...).RelatedSel() 149 | totalCount, err = qs.Filter("DeviceId", deviceId).Count() 150 | if _, err = qs.Filter("DeviceId", deviceId).Limit(limit, offset).All(&l, fields...); err == nil { 151 | if len(fields) == 0 { 152 | for _, v := range l { 153 | ml = append(ml, v) 154 | } 155 | } else { 156 | // trim unused fields 157 | for _, v := range l { 158 | m := make(map[string]interface{}) 159 | val := reflect.ValueOf(v) 160 | for _, fname := range fields { 161 | m[fname] = val.FieldByName(fname).Interface() 162 | } 163 | ml = append(ml, m) 164 | } 165 | } 166 | return ml, totalCount,nil 167 | } 168 | return nil, 0, err 169 | } 170 | 171 | // UpdateAirAd updates AirAd by Id and returns error if 172 | // the record to be updated doesn't exist 173 | func UpdateAirAdById(m *AirAd) (err error) { 174 | o := orm.NewOrm() 175 | v := AirAd{Id: m.Id} 176 | // ascertain id exists in the database 177 | if err = o.Read(&v); err == nil { 178 | var num int64 179 | if num, err = o.Update(m); err == nil { 180 | fmt.Println("Number of records updated in database:", num) 181 | } 182 | } 183 | return 184 | } 185 | 186 | // DeleteAirAd deletes AirAd by Id and returns error if 187 | // the record to be deleted doesn't exist 188 | func DeleteAirAd(id int) (err error) { 189 | o := orm.NewOrm() 190 | v := AirAd{Id: id} 191 | // ascertain id exists in the database 192 | if err = o.Read(&v); err == nil { 193 | var num int64 194 | if num, err = o.Delete(&AirAd{Id: id}); err == nil { 195 | fmt.Println("Number of records deleted in database:", num) 196 | } 197 | } 198 | return 199 | } -------------------------------------------------------------------------------- /models/base.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | //"fmt" 5 | "github.com/astaxie/beego/config" 6 | //"github.com/astaxie/beego/orm" 7 | _ "github.com/go-sql-driver/mysql" 8 | ) 9 | 10 | // 数据库连接初始化 11 | //func Init() { 12 | // appConf, err := config.NewConfig("ini", "conf/app.conf") 13 | // if err != nil { 14 | // panic(err) 15 | // } 16 | // 17 | // conn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", 18 | // appConf.String("database::db_user"), 19 | // appConf.String("database::db_passwd"), 20 | // appConf.String("database::db_host"), 21 | // appConf.String("database::db_port"), 22 | // appConf.String("database::db_name"), 23 | // appConf.String("database::db_charset")) 24 | // orm.RegisterDataBase("default", "mysql", conn) 25 | // 26 | // //自动建表 27 | // name := "default" 28 | // err = orm.RunSyncdb(name, false, true) 29 | // if err != nil { 30 | // fmt.Println(err) 31 | // } 32 | // orm.RunCommand() 33 | //} 34 | 35 | //返回带前缀的表名 36 | func TableName(str string) string { 37 | appConf, err := config.NewConfig("ini", "conf/app.conf") 38 | if err != nil { 39 | panic(err) 40 | } 41 | return appConf.String("database::") + str 42 | } 43 | -------------------------------------------------------------------------------- /models/common.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // Predefined model error codes. 4 | const ( 5 | ErrDatabase = -1 6 | ErrSystem = -2 7 | ErrDupRows = -3 8 | ErrNotFound = -4 9 | ) 10 | 11 | type BaseModel struct { 12 | CodeInfo CodeInfo 13 | } 14 | 15 | // CodeInfo definition. 16 | type CodeInfo struct { 17 | Code int `json:"code"` 18 | Info string `json:"info"` 19 | } 20 | 21 | // NewErrorInfo return a CodeInfo represents error. 22 | func NewErrorInfo(info string) *CodeInfo { 23 | return &CodeInfo{-1, info} 24 | } 25 | 26 | // NewSuccessInfo return a CodeInfo represents OK. 27 | func NewSuccessInfo(info string) *CodeInfo { 28 | return &CodeInfo{0, info} 29 | } 30 | -------------------------------------------------------------------------------- /models/device.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | "strings" 6 | "reflect" 7 | "fmt" 8 | "errors" 9 | "time" 10 | ) 11 | 12 | type Device struct { 13 | Id int `json:"id, omitempty" orm:"column(id);pk;unique;auto_increment;int(11)"` 14 | UserId int `json:"user_id" orm:"column(user_id);size(11)"` 15 | DeviceName string `json:"device_name" orm:"column(device_name);unique;size(32)"` 16 | Address string `json:"address" orm:"column(address);size(50)"` 17 | Status int `json:"status" orm:"column(status);size(1)"`// 0: enabled, 1:disabled 18 | CreatedAt int64 `json:"created_at, omitempty" orm:"column(created_at);size(11)"` 19 | UpdatedAt int64 `json:"updated_at, omitempty" orm:"column(updated_at);size(11)"` 20 | Latitude string `json:"latitude, omitempty" orm:"column(latitude);size(12)"` 21 | Longitude string `json:"longitude, omitempty" orm:"column(longitude);size(12)"` 22 | AirAdCount int64 `json:"airad_count, omitempty" orm:"column(airad_count);size(64)"` 23 | //User *User `json:"user_id" orm:"rel(fk)"` 24 | //AirAd []*AirAd `orm:"reverse(many)"` // 设置一对多的反向关系 25 | } 26 | 27 | type DeviceRequestStruct struct { 28 | UserId int `json:"userId"` 29 | Offset int `json:"offset"` 30 | Limit int `json:"limit"` 31 | Fields string `json:"fields"` 32 | } 33 | 34 | func init() { 35 | orm.RegisterModel(new(Device)) 36 | } 37 | 38 | func Devices() orm.QuerySeter { 39 | return orm.NewOrm().QueryTable(new(Device)) 40 | } 41 | 42 | // AddDevice insert a new Device into database and returns 43 | // last inserted Id on success. 44 | func AddDevice(m *Device) (id int64, err error) { 45 | o := orm.NewOrm() 46 | 47 | CreatedAt := time.Now().UTC().Unix() 48 | UpdatedAt := CreatedAt 49 | 50 | device := Device{ 51 | DeviceName:m.DeviceName, 52 | UserId:m.UserId, 53 | Address:m.Address, 54 | Status:m.Status, 55 | CreatedAt:CreatedAt, 56 | UpdatedAt:UpdatedAt, 57 | Latitude:m.Latitude, 58 | Longitude:m.Longitude, 59 | //User *User `json:"user_id" orm:"rel(fk)"` 60 | //AirAd []*AirAd `orm:"reverse(many)"` 61 | } 62 | 63 | //var id int64 64 | id, err = o.Insert(&device) 65 | if err == nil{ 66 | return id, err 67 | } 68 | 69 | return 0, err 70 | } 71 | 72 | // 检测DeviceName是否存在 73 | func CheckDeviceName(deviceName string) bool { 74 | exist := Devices().Filter("DeviceName", deviceName).Exist() 75 | return exist 76 | } 77 | 78 | // GetDeviceById retrieves Device by Id. Returns error if 79 | // Id doesn't exist 80 | func GetDeviceById(id int) (v *Device, err error) { 81 | o := orm.NewOrm() 82 | v = &Device{Id: id} 83 | if err = o.QueryTable(new(Device)).Filter("Id", id).RelatedSel().One(v); err == nil { 84 | return v, nil 85 | } 86 | return nil, err 87 | } 88 | 89 | // GetDeviceByUser retrieves Device by User. Returns error if 90 | // Id doesn't exist 91 | func GetDevicesByUserId(userId int, fields []string, limit int, offset int) (devices []*Device, err error) { 92 | o := orm.NewOrm() 93 | if _, err = o.QueryTable(new(Device)).Filter("user_id", userId).Limit(limit, offset).All(&devices, fields...); err == nil { 94 | return devices, nil 95 | } 96 | return nil, err 97 | } 98 | 99 | // GetAllDevices retrieves all Device matches certain condition. Returns empty list if 100 | // no records exist 101 | func GetAllDevices(query map[string]string, fields []string, sortby []string, order []string, 102 | offset int, limit int, userId int) (ml []interface{}, totalCount int64, err error) { 103 | o := orm.NewOrm() 104 | qs := o.QueryTable(new(Device)) 105 | // query k=v 106 | for k, v := range query { 107 | // rewrite dot-notation to Object__Attribute 108 | k = strings.Replace(k, ".", "__", -1) 109 | qs = qs.Filter(k, v) 110 | } 111 | // order by: 112 | var sortFields []string 113 | if len(sortby) != 0 { 114 | if len(sortby) == len(order) { 115 | // 1) for each sort field, there is an associated order 116 | for i, v := range sortby { 117 | orderby := "" 118 | if order[i] == "desc" { 119 | orderby = "-" + v 120 | } else if order[i] == "asc" { 121 | orderby = v 122 | } else { 123 | return nil, 0, errors.New("Error: Invalid order. Must be either [asc|desc]") 124 | } 125 | sortFields = append(sortFields, orderby) 126 | } 127 | qs = qs.OrderBy(sortFields...) 128 | } else if len(sortby) != len(order) && len(order) == 1 { 129 | // 2) there is exactly one order, all the sorted fields will be sorted by this order 130 | for _, v := range sortby { 131 | orderby := "" 132 | if order[0] == "desc" { 133 | orderby = "-" + v 134 | } else if order[0] == "asc" { 135 | orderby = v 136 | } else { 137 | return nil, 0, errors.New("Error: Invalid order. Must be either [asc|desc]") 138 | } 139 | sortFields = append(sortFields, orderby) 140 | } 141 | } else if len(sortby) != len(order) && len(order) != 1 { 142 | return nil, 0, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") 143 | } 144 | } else { 145 | if len(order) != 0 { 146 | return nil, 0, errors.New("Error: unused 'order' fields") 147 | } 148 | } 149 | 150 | var l []Device 151 | qs = qs.OrderBy(sortFields...).RelatedSel() 152 | totalCount, err = qs.Filter("UserId", userId).Count() 153 | if _, err = qs.Filter("UserId", userId).Limit(limit, offset).All(&l, fields...); err == nil { 154 | if len(fields) == 0 { 155 | for _, v := range l { 156 | ml = append(ml, v) 157 | } 158 | } else { 159 | // trim unused fields 160 | for _, v := range l { 161 | m := make(map[string]interface{}) 162 | val := reflect.ValueOf(v) 163 | for _, fname := range fields { 164 | m[fname] = val.FieldByName(fname).Interface() 165 | } 166 | ml = append(ml, m) 167 | } 168 | } 169 | return ml, totalCount, nil 170 | } 171 | return nil, 0, err 172 | } 173 | 174 | // UpdateDevice updates Device by Id and returns error if 175 | // the record to be updated doesn't exist 176 | func UpdateDeviceById(m *Device) (err error) { 177 | o := orm.NewOrm() 178 | v := Device{Id: m.Id} 179 | // ascertain id exists in the database 180 | if err = o.Read(&v); err == nil { 181 | var num int64 182 | if num, err = o.Update(m); err == nil { 183 | fmt.Println("Number of records updated in database:", num) 184 | } 185 | } 186 | return 187 | } 188 | 189 | // UpdateDevice updates Device by AirAdCount and returns error if 190 | // the record to be updated doesn't exist 191 | func UpdateDeviceAirAdCount(m *Device) (err error) { 192 | o := orm.NewOrm() 193 | v := Device{Id: m.Id} 194 | m.AirAdCount += 1 195 | // ascertain id exists in the database 196 | if err = o.Read(&v); err == nil { 197 | var num int64 198 | if num, err = o.Update(m); err == nil { 199 | fmt.Println("Number of records updated in database:", num) 200 | } 201 | } 202 | return 203 | } 204 | 205 | 206 | // DeleteDevice deletes Device by Id and returns error if 207 | // the record to be deleted doesn't exist 208 | func DeleteDevice(id int) (err error) { 209 | o := orm.NewOrm() 210 | v := Device{Id: id} 211 | // ascertain id exists in the database 212 | if err = o.Read(&v); err == nil { 213 | var num int64 214 | if num, err = o.Delete(&Device{Id: id}); err == nil { 215 | fmt.Println("Number of records deleted in database:", num) 216 | } 217 | } 218 | return 219 | } -------------------------------------------------------------------------------- /models/messages.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | //"fmt" 5 | "time" 6 | "github.com/astaxie/beego" 7 | "github.com/astaxie/beego/orm" 8 | ) 9 | 10 | type Message struct { 11 | Id int64 `json:"id, omitempty" orm:"column(id);pk;unique;auto_increment"` 12 | UserId int64 `json:"user_id" orm:"column(user_id);size(11)"` 13 | ToUserId int64 `json:"to_user_id" orm:"column(to_user_id);size(11)"` 14 | Type int `json:"type, omitempty" orm:"column(type);size(4)"` 15 | SubType int `json:"sub_type, omitempty" orm:"column(sub_type);size(4)"` 16 | Title string `json:"title, omitempty" orm:"column(title);varbinary"` 17 | Url string `json:"url, omitempty" orm:"column(url);varbinary"` 18 | Viewed int `json:"viewed" orm:"column(viewed);size(1)"`// 1: viewed, 0:not-viewed 19 | CreatedAt int64 `json:"created_at, omitempty" orm:"column(created_at);size(11)"` 20 | } 21 | 22 | func (this *Message) TableName() string { 23 | return TableName("message") 24 | } 25 | func init() { 26 | orm.RegisterModel(new(Message)) 27 | } 28 | 29 | func Messages() orm.QuerySeter { 30 | return orm.NewOrm().QueryTable(new(Message)) 31 | } 32 | 33 | func AddMessages(m * Message)(id int64, err error) { 34 | o := orm.NewOrm() 35 | 36 | message := Message{ 37 | UserId: m.UserId, 38 | ToUserId: m.ToUserId, 39 | Type: m.Type, 40 | SubType: m.SubType, 41 | CreatedAt: time.Now().UTC().Unix(), 42 | Title: m.Title, 43 | Viewed: 0, 44 | Url: m.Url, 45 | } 46 | 47 | //var id int64 48 | id, err = o.Insert(&message) 49 | if err == nil { 50 | return id, err 51 | } 52 | 53 | return 0, err 54 | } 55 | 56 | func ListMessages(query map[string]string, page int, offset int) (msg []interface{}, totalCount int64, err error) { 57 | o := orm.NewOrm() 58 | qs := o.QueryTable(new(Message)) 59 | cond := orm.NewCondition() 60 | 61 | if query["toUserId"] != "" { 62 | cond = cond.And("ToUserId", query["toUserId"]) 63 | } 64 | if query["View"] != "" { 65 | cond = cond.And("View", query["View"]) 66 | } 67 | if query["Type"] != "" { 68 | cond = cond.And("Type", query["type"]) 69 | } 70 | 71 | qs = qs.SetCond(cond) 72 | if page < 1 { 73 | page = 1 74 | } 75 | if offset < 1 { 76 | offset, _ = beego.AppConfig.Int("pageOffset") 77 | } 78 | start := (page - 1) * offset 79 | 80 | 81 | if totalCount, err := qs.Limit(offset, start).All(&msg); err == nil { 82 | return msg, totalCount, nil 83 | } 84 | return nil, 0, err 85 | } 86 | 87 | //统计数量 88 | func CountMessages(query map[string]string) (num int64) { 89 | o := orm.NewOrm() 90 | qs := o.QueryTable(TableName("message")) 91 | cond := orm.NewCondition() 92 | if query["toUserId"] != "" { 93 | cond = cond.And("ToUserId", query["toUserId"]) 94 | } 95 | if query["View"] != "" { 96 | cond = cond.And("View", query["view"]) 97 | } 98 | if query["Type"] != "" { 99 | cond = cond.And("Type", query["type"]) 100 | } 101 | if num, err := qs.SetCond(cond).Count(); err == nil { 102 | return num 103 | } 104 | return 0 105 | } 106 | 107 | func ChangeMessageStatus(id int64, viewed int) (err error) { 108 | o := orm.NewOrm() 109 | v := Message{Id: id} 110 | // ascertain id exists in the database 111 | if err := o.Read(&v); err == nil { 112 | if _, err = o.Update(Message{Viewed:viewed}); err == nil { 113 | return nil 114 | } 115 | } 116 | return err 117 | } 118 | 119 | func ChangeMessageStatusAll(toUserId int64) error { 120 | o := orm.NewOrm() 121 | _, err := o.Raw("UPDATE "+ TableName("message") + " SET Viewed=1 WHERE ToUserId=? AND Viewed=0", toUserId).Exec() 122 | return err 123 | } 124 | 125 | func DeleteMessages(ids string) error { 126 | o := orm.NewOrm() 127 | _, err := o.Raw("DELETE FROM " + TableName("message") + " WHERE id IN(" + ids + ")").Exec() 128 | return err 129 | } -------------------------------------------------------------------------------- /models/mqtt.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | 9 | "github.com/astaxie/beego/orm" 10 | ) 11 | 12 | type Mqtt struct { 13 | Id int `json:"id, omitempty" orm:"column(id);pk;unique;auto_increment"` 14 | DeviceId int `json:"user_id" orm:"column(device_id);size(11)"` 15 | MqttOptionId int `json:"mqtt_option_id" orm:"column(mqtt_option_id);size(11)"` 16 | // QoS is the QoS of the fixed header. 17 | QoS byte `json:"qos, omitempty" orm:"column(qos);varbinary"` 18 | // Retain is the Retain of the fixed header. 19 | Retain bool `json:"retain, omitempty" orm:"column(retain);varbinary"` 20 | // TopicName is the Topic Name of the variable header. 21 | TopicName string `json:"topic_name, omitempty" orm:"column(topic_name);varbinary"` 22 | // Message is the Application Message of the payload. 23 | //Message []byte 24 | // TopicFilter is the Topic Filter of the Subscription. 25 | TopicFilter string `json:"topic_filter, omitempty" orm:"column(topic_filter);varbinary"` 26 | } 27 | 28 | func init() { 29 | orm.RegisterModel(new(Mqtt)) 30 | } 31 | 32 | func Mqtts() orm.QuerySeter { 33 | return orm.NewOrm().QueryTable(new(Mqtt)) 34 | } 35 | 36 | // AddMqtt insert a new Mqtt into database and returns 37 | // last inserted Id on success. 38 | func AddMqtt(m *Mqtt) (id int64, err error) { 39 | o := orm.NewOrm() 40 | id, err = o.Insert(m) 41 | return 42 | } 43 | 44 | // GetMqttById retrieves Mqtt by Id. Returns error if 45 | // Id doesn't exist 46 | func GetMqttById(id int) (v *Mqtt, err error) { 47 | o := orm.NewOrm() 48 | v = &Mqtt{Id: id} 49 | if err = o.QueryTable(new(Mqtt)).Filter("Id", id).RelatedSel().One(v); err == nil { 50 | return v, nil 51 | } 52 | return nil, err 53 | } 54 | 55 | // GetAllMqtt retrieves all Mqtt matches certain condition. Returns empty list if 56 | // no records exist 57 | func GetAllMqtt(query map[string]string, fields []string, sortby []string, order []string, 58 | offset int64, limit int64) (ml []interface{}, err error) { 59 | o := orm.NewOrm() 60 | qs := o.QueryTable(new(Mqtt)) 61 | // query k=v 62 | for k, v := range query { 63 | // rewrite dot-notation to Object__Attribute 64 | k = strings.Replace(k, ".", "__", -1) 65 | qs = qs.Filter(k, v) 66 | } 67 | // order by: 68 | var sortFields []string 69 | if len(sortby) != 0 { 70 | if len(sortby) == len(order) { 71 | // 1) for each sort field, there is an associated order 72 | for i, v := range sortby { 73 | orderby := "" 74 | if order[i] == "desc" { 75 | orderby = "-" + v 76 | } else if order[i] == "asc" { 77 | orderby = v 78 | } else { 79 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 80 | } 81 | sortFields = append(sortFields, orderby) 82 | } 83 | qs = qs.OrderBy(sortFields...) 84 | } else if len(sortby) != len(order) && len(order) == 1 { 85 | // 2) there is exactly one order, all the sorted fields will be sorted by this order 86 | for _, v := range sortby { 87 | orderby := "" 88 | if order[0] == "desc" { 89 | orderby = "-" + v 90 | } else if order[0] == "asc" { 91 | orderby = v 92 | } else { 93 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 94 | } 95 | sortFields = append(sortFields, orderby) 96 | } 97 | } else if len(sortby) != len(order) && len(order) != 1 { 98 | return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") 99 | } 100 | } else { 101 | if len(order) != 0 { 102 | return nil, errors.New("Error: unused 'order' fields") 103 | } 104 | } 105 | 106 | var l []Mqtt 107 | qs = qs.OrderBy(sortFields...).RelatedSel() 108 | if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil { 109 | if len(fields) == 0 { 110 | for _, v := range l { 111 | ml = append(ml, v) 112 | } 113 | } else { 114 | // trim unused fields 115 | for _, v := range l { 116 | m := make(map[string]interface{}) 117 | val := reflect.ValueOf(v) 118 | for _, fname := range fields { 119 | m[fname] = val.FieldByName(fname).Interface() 120 | } 121 | ml = append(ml, m) 122 | } 123 | } 124 | return ml, nil 125 | } 126 | return nil, err 127 | } 128 | 129 | // UpdateMqtt updates Mqtt by Id and returns error if 130 | // the record to be updated doesn't exist 131 | func UpdateMqttById(m *Mqtt) (err error) { 132 | o := orm.NewOrm() 133 | v := Mqtt{Id: m.Id} 134 | // ascertain id exists in the database 135 | if err = o.Read(&v); err == nil { 136 | var num int64 137 | if num, err = o.Update(m); err == nil { 138 | fmt.Println("Number of records updated in database:", num) 139 | } 140 | } 141 | return 142 | } 143 | 144 | // DeleteMqtt deletes Mqtt by Id and returns error if 145 | // the record to be deleted doesn't exist 146 | func DeleteMqtt(id int) (err error) { 147 | o := orm.NewOrm() 148 | v := Mqtt{Id: id} 149 | // ascertain id exists in the database 150 | if err = o.Read(&v); err == nil { 151 | var num int64 152 | if num, err = o.Delete(&Mqtt{Id: id}); err == nil { 153 | fmt.Println("Number of records deleted in database:", num) 154 | } 155 | } 156 | return 157 | } 158 | -------------------------------------------------------------------------------- /models/mqttoption.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | 9 | "github.com/astaxie/beego/orm" 10 | "time" 11 | ) 12 | 13 | type MqttOption struct { 14 | Id int `json:"id, omitempty" orm:"column(id);pk;unique;auto_increment;int(11)"` 15 | // ClientID is the Client Identifier of the payload. 16 | ClientID string `json:"client_id, omitempty" orm:"column(client_id);varbinary"` 17 | // CONNACKTimeout is timeout in seconds for the Client 18 | // to wait for receiving the CONNACK Packet after sending 19 | // the CONNECT Packet. 20 | ConnAckTimeout time.Duration `json:"conn_ack_timeout, omitempty" orm:"column(conn_ack_timeout);size(64)"` 21 | // UserName is the User Name of the payload. 22 | UserName string `json:"user_name, omitempty" orm:"column(user_name);size(32)"` 23 | // Password is the Password of the payload. 24 | Password string `json:"password, omitempty" orm:"column(password);size(128)"` 25 | // CleanSession is the Clean Session of the variable header. 26 | CleanSession bool `json:"clean_session, omitempty" orm:"column(clean_session)"` 27 | // KeepAlive is the Keep Alive of the variable header. 28 | KeepAlive uint16 `json:"keep_alive, omitempty" orm:"column(keep_alive)"` 29 | // WillTopic is the Will Topic of the payload. 30 | WillTopic string `json:"will_topic, omitempty" orm:"column(will_topic);varbinary"` 31 | // WillMessage is the Will Message of the payload. 32 | WillMessage string `json:"will_message, omitempty" orm:"column(will_message);varbinary"` 33 | // WillQoS is the Will QoS of the variable header. 34 | WillQoS bool `json:"will_qos, omitempty" orm:"column(will_qos)"` 35 | // WillRetain is the Will Retain of the variable header. 36 | WillRetain bool `json:"will_retain, omitempty" orm:"column(will_retain)"` 37 | } 38 | 39 | func init() { 40 | orm.RegisterModel(new(MqttOption)) 41 | } 42 | 43 | func MqttOptions() orm.QuerySeter { 44 | return orm.NewOrm().QueryTable(new(MqttOption)) 45 | } 46 | 47 | // AddMqttOption insert a new MqttOption into database and returns 48 | // last inserted Id on success. 49 | func AddMqttOption(m *MqttOption) (id int64, err error) { 50 | o := orm.NewOrm() 51 | id, err = o.Insert(m) 52 | return 53 | } 54 | 55 | // GetMqttOptionById retrieves MqttOption by Id. Returns error if 56 | // Id doesn't exist 57 | func GetMqttOptionById(id int) (v *MqttOption, err error) { 58 | o := orm.NewOrm() 59 | v = &MqttOption{Id: id} 60 | if err = o.QueryTable(new(MqttOption)).Filter("Id", id).RelatedSel().One(v); err == nil { 61 | return v, nil 62 | } 63 | return nil, err 64 | } 65 | 66 | // GetAllMqttOption retrieves all MqttOption matches certain condition. Returns empty list if 67 | // no records exist 68 | func GetAllMqttOption(query map[string]string, fields []string, sortby []string, order []string, 69 | offset int64, limit int64) (ml []interface{}, err error) { 70 | o := orm.NewOrm() 71 | qs := o.QueryTable(new(MqttOption)) 72 | // query k=v 73 | for k, v := range query { 74 | // rewrite dot-notation to Object__Attribute 75 | k = strings.Replace(k, ".", "__", -1) 76 | qs = qs.Filter(k, v) 77 | } 78 | // order by: 79 | var sortFields []string 80 | if len(sortby) != 0 { 81 | if len(sortby) == len(order) { 82 | // 1) for each sort field, there is an associated order 83 | for i, v := range sortby { 84 | orderby := "" 85 | if order[i] == "desc" { 86 | orderby = "-" + v 87 | } else if order[i] == "asc" { 88 | orderby = v 89 | } else { 90 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 91 | } 92 | sortFields = append(sortFields, orderby) 93 | } 94 | qs = qs.OrderBy(sortFields...) 95 | } else if len(sortby) != len(order) && len(order) == 1 { 96 | // 2) there is exactly one order, all the sorted fields will be sorted by this order 97 | for _, v := range sortby { 98 | orderby := "" 99 | if order[0] == "desc" { 100 | orderby = "-" + v 101 | } else if order[0] == "asc" { 102 | orderby = v 103 | } else { 104 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 105 | } 106 | sortFields = append(sortFields, orderby) 107 | } 108 | } else if len(sortby) != len(order) && len(order) != 1 { 109 | return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") 110 | } 111 | } else { 112 | if len(order) != 0 { 113 | return nil, errors.New("Error: unused 'order' fields") 114 | } 115 | } 116 | 117 | var l []MqttOption 118 | qs = qs.OrderBy(sortFields...).RelatedSel() 119 | if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil { 120 | if len(fields) == 0 { 121 | for _, v := range l { 122 | ml = append(ml, v) 123 | } 124 | } else { 125 | // trim unused fields 126 | for _, v := range l { 127 | m := make(map[string]interface{}) 128 | val := reflect.ValueOf(v) 129 | for _, fname := range fields { 130 | m[fname] = val.FieldByName(fname).Interface() 131 | } 132 | ml = append(ml, m) 133 | } 134 | } 135 | return ml, nil 136 | } 137 | return nil, err 138 | } 139 | 140 | // UpdateMqttOption updates MqttOption by Id and returns error if 141 | // the record to be updated doesn't exist 142 | func UpdateMqttOptionById(m *MqttOption) (err error) { 143 | o := orm.NewOrm() 144 | v := MqttOption{Id: m.Id} 145 | // ascertain id exists in the database 146 | if err = o.Read(&v); err == nil { 147 | var num int64 148 | if num, err = o.Update(m); err == nil { 149 | fmt.Println("Number of records updated in database:", num) 150 | } 151 | } 152 | return 153 | } 154 | 155 | // DeleteMqttOption deletes MqttOption by Id and returns error if 156 | // the record to be deleted doesn't exist 157 | func DeleteMqttOption(id int) (err error) { 158 | o := orm.NewOrm() 159 | v := MqttOption{Id: id} 160 | // ascertain id exists in the database 161 | if err = o.Read(&v); err == nil { 162 | var num int64 163 | if num, err = o.Delete(&MqttOption{Id: id}); err == nil { 164 | fmt.Println("Number of records deleted in database:", num) 165 | } 166 | } 167 | return 168 | } 169 | -------------------------------------------------------------------------------- /models/object.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | var ( 10 | Objects map[string]*Object 11 | ) 12 | 13 | type Object struct { 14 | ObjectId string 15 | Score int64 16 | PlayerName string 17 | } 18 | 19 | func init() { 20 | Objects = make(map[string]*Object) 21 | Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} 22 | Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} 23 | } 24 | 25 | func AddOne(object Object) (ObjectId string) { 26 | object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) 27 | Objects[object.ObjectId] = &object 28 | return object.ObjectId 29 | } 30 | 31 | func GetOne(ObjectId string) (object *Object, err error) { 32 | if v, ok := Objects[ObjectId]; ok { 33 | return v, nil 34 | } 35 | return nil, errors.New("ObjectId Not Exist") 36 | } 37 | 38 | func GetAll() map[string]*Object { 39 | return Objects 40 | } 41 | 42 | func Update(ObjectId string, Score int64) (err error) { 43 | if v, ok := Objects[ObjectId]; ok { 44 | v.Score = Score 45 | return nil 46 | } 47 | return errors.New("ObjectId Not Exist") 48 | } 49 | 50 | func Delete(ObjectId string) { 51 | delete(Objects, ObjectId) 52 | } 53 | 54 | -------------------------------------------------------------------------------- /models/user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "github.com/astaxie/beego/orm" 6 | "reflect" 7 | "strings" 8 | "fmt" 9 | "github.com/rubinliudongpo/airad/utils" 10 | "time" 11 | //"github.com/astaxie/beego" 12 | "github.com/astaxie/beego" 13 | ) 14 | 15 | func (u *User) TableName() string { 16 | return TableName("user") 17 | } 18 | 19 | func init() { 20 | orm.RegisterModel(new(User)) 21 | } 22 | 23 | type User struct { 24 | Id int `json:"id" orm:"column(id);pk;unique;auto_increment;int(11)"` 25 | Username string `json:"username" orm:"column(username);unique;size(32)"` 26 | Password string `json:"password" orm:"column(password);size(128)"` 27 | Avatar string `json:"avatar, omitempty" orm:"column(avatar);varbinary"` 28 | Salt string `json:"salt" orm:"column(salt);size(128)"` 29 | Token string `json:"token" orm:"column(token);size(256)"` 30 | Gender int `json:"gender" orm:"column(gender);size(1)"` // 0:Male, 1: Female, 2: undefined 31 | Age int `json:"age" orm:"column(age):size(3)"` 32 | Address string `json:"address" orm:"column(address);size(50)"` 33 | Email string `json:"email" orm:"column(email);size(50)"` 34 | LastLogin int64 `json:"last_login" orm:"column(last_login);size(11)"` 35 | Status int `json:"status" orm:"column(status);size(1)"`// 0: enabled, 1:disabled 36 | CreatedAt int64 `json:"created_at" orm:"column(created_at);size(11)"` 37 | UpdatedAt int64 `json:"updated_at" orm:"column(updated_at);size(11)"` 38 | DeviceCount int `json:"device_count" orm:"column(device_count);size(64);default(0)"` 39 | //Device []*Device `orm:"reverse(many)"` // 设置一对多的反向关系 40 | } 41 | 42 | func Users() orm.QuerySeter { 43 | return orm.NewOrm().QueryTable(new(User)) 44 | } 45 | 46 | // 检测用户是否存在 47 | func CheckUserId(userId int) bool { 48 | exist := Users().Filter("Id", userId).Exist() 49 | return exist 50 | } 51 | 52 | // 检测用户是否存在 53 | func CheckUserName(username string) bool { 54 | exist := Users().Filter("Username", username).Exist() 55 | return exist 56 | } 57 | 58 | // 检测用户是否存在 59 | func CheckUserIdAndToken(userId int, token string) bool { 60 | exist := Users().Filter("Id", userId).Filter("Token", token).Exist() 61 | return exist 62 | } 63 | 64 | 65 | // 检测用户是否存在 66 | func CheckEmail(email string) bool { 67 | exist := Users().Filter("Email", email).Exist() 68 | return exist 69 | } 70 | 71 | // CheckPass compare input password. 72 | func (u *User) CheckPassword(password string) (ok bool, err error) { 73 | hash, err := utils.GeneratePassHash(password, u.Salt) 74 | if err != nil { 75 | return false, err 76 | } 77 | 78 | return u.Password == hash, nil 79 | } 80 | 81 | // 根据用户ID获取用户 82 | func GetUserById(id int) (v *User, err error) { 83 | o := orm.NewOrm() 84 | v = &User{Id: id} 85 | if err = o.QueryTable(new(User)).Filter("Id", id).RelatedSel().One(v); err == nil { 86 | return v, nil 87 | } 88 | return nil, err 89 | } 90 | 91 | 92 | // 根据用户名字获取用户 93 | func GetUserByUserName(username string) (v *User, err error) { 94 | o := orm.NewOrm() 95 | v = &User{Username: username} 96 | if err = o.QueryTable(new(User)).Filter("Username", username).RelatedSel().One(v); err == nil { 97 | return v, nil 98 | } 99 | return nil, err 100 | } 101 | 102 | // GetAllUser retrieves all User matches certain condition. Returns empty list if 103 | // no records exist 104 | func GetAllUser(query map[string]string, fields []string, sortby []string, order []string, 105 | offset int, limit int) (ml []interface{}, err error) { 106 | o := orm.NewOrm() 107 | qs := o.QueryTable(new(User)) 108 | // query k=v 109 | for k, v := range query { 110 | // rewrite dot-notation to Object__Attribute 111 | k = strings.Replace(k, ".", "__", -1) 112 | qs = qs.Filter(k, v) 113 | } 114 | // order by: 115 | var sortFields []string 116 | if len(sortby) != 0 { 117 | if len(sortby) == len(order) { 118 | // 1) for each sort field, there is an associated order 119 | for i, v := range sortby { 120 | orderby := "" 121 | if order[i] == "desc" { 122 | orderby = "-" + v 123 | } else if order[i] == "asc" { 124 | orderby = v 125 | } else { 126 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 127 | } 128 | sortFields = append(sortFields, orderby) 129 | } 130 | qs = qs.OrderBy(sortFields...) 131 | } else if len(sortby) != len(order) && len(order) == 1 { 132 | // 2) there is exactly one order, all the sorted fields will be sorted by this order 133 | for _, v := range sortby { 134 | orderby := "" 135 | if order[0] == "desc" { 136 | orderby = "-" + v 137 | } else if order[0] == "asc" { 138 | orderby = v 139 | } else { 140 | return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") 141 | } 142 | sortFields = append(sortFields, orderby) 143 | } 144 | } else if len(sortby) != len(order) && len(order) != 1 { 145 | return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") 146 | } 147 | } else { 148 | if len(order) != 0 { 149 | return nil, errors.New("Error: unused 'order' fields") 150 | } 151 | } 152 | 153 | var l []User 154 | qs = qs.OrderBy(sortFields...).RelatedSel() 155 | if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil { 156 | if len(fields) == 0 { 157 | for _, v := range l { 158 | ml = append(ml, v) 159 | } 160 | } else { 161 | // trim unused fields 162 | for _, v := range l { 163 | m := make(map[string]interface{}) 164 | val := reflect.ValueOf(v) 165 | for _, fname := range fields { 166 | m[fname] = val.FieldByName(fname).Interface() 167 | } 168 | ml = append(ml, m) 169 | } 170 | } 171 | return ml, nil 172 | } 173 | return nil, err 174 | } 175 | 176 | func GetUserByToken(token string) (bool, User) { 177 | o := orm.NewOrm() 178 | var user User 179 | err := o.QueryTable(user).Filter("Token", token).One(&user) 180 | return err != orm.ErrNoRows, user 181 | } 182 | 183 | func Login(username string, password string) (bool, *User) { 184 | o := orm.NewOrm() 185 | user, err := GetUserByUserName(username) 186 | if err != nil { 187 | return false, nil 188 | } 189 | passwordHash, err := utils.GeneratePassHash(password, user.Salt) 190 | if err != nil { 191 | return false, nil 192 | } 193 | err = o.QueryTable(user).Filter("Username", username).Filter("Password", passwordHash).One(user) 194 | return err != orm.ErrNoRows, user 195 | 196 | } 197 | 198 | func GetUserByUsername(username string) (err error, user *User) { 199 | o := orm.NewOrm() 200 | user = &User{Username: username} 201 | if err := o.QueryTable(user).Filter("Username", username).One(&user); err == nil { 202 | return nil, user 203 | } 204 | return err, nil 205 | } 206 | 207 | func AddUser(m *User) (*User, error) { 208 | o := orm.NewOrm() 209 | salt, err := utils.GenerateSalt() 210 | if err != nil { 211 | return nil, err 212 | } 213 | 214 | passwordHash, err := utils.GeneratePassHash(m.Password, salt) 215 | if err != nil { 216 | return nil, err 217 | } 218 | CreatedAt := time.Now().UTC().Unix() 219 | UpdatedAt := CreatedAt 220 | LastLogin := CreatedAt 221 | 222 | et := utils.EasyToken{ 223 | Username: m.Username, 224 | Uid: 0, 225 | Expires: time.Now().Unix() + 2 * 3600, 226 | } 227 | token, err := et.GetToken() 228 | user := User{ 229 | Username:m.Username, 230 | Password: passwordHash, 231 | Salt:salt, 232 | Token:token, 233 | Gender:m.Gender, 234 | Age:m.Age, 235 | Address:m.Address, 236 | Email:m.Email, 237 | LastLogin:LastLogin, 238 | Status:m.Status, 239 | CreatedAt:CreatedAt, 240 | UpdatedAt:UpdatedAt, 241 | } 242 | _, err = o.Insert(&user) 243 | if err == nil{ 244 | return &user, err 245 | } 246 | 247 | return nil, err 248 | } 249 | 250 | func UpdateUser(user *User) { 251 | o := orm.NewOrm() 252 | o.Update(user) 253 | } 254 | 255 | // UpdateDevice updates User by DeviceCount and returns error if 256 | // the record to be updated doesn't exist 257 | func UpdateUserDeviceCount(m *User) (err error) { 258 | o := orm.NewOrm() 259 | v := User{Id: m.Id} 260 | m.DeviceCount += 1 261 | // ascertain id exists in the database 262 | if err = o.Read(&v); err == nil { 263 | var num int64 264 | if num, err = o.Update(m); err == nil { 265 | fmt.Println("Number of records updated in database:", num) 266 | } 267 | } 268 | return 269 | } 270 | 271 | // updates User's Token and returns error if 272 | // the record to be updated doesn't exist 273 | func UpdateUserToken(m *User, token string) (err error) { 274 | o := orm.NewOrm() 275 | v := User{Id: m.Id} 276 | m.Token = token 277 | // ascertain id exists in the database 278 | if err = o.Read(&v); err == nil { 279 | var num int64 280 | if num, err = o.Update(m); err == nil { 281 | fmt.Println("Number of records updated in database:", num) 282 | } 283 | } 284 | return err 285 | } 286 | 287 | // updates User's LastLogin and returns error if 288 | // the record to be updated doesn't exist 289 | func UpdateUserLastLogin(m *User) (err error) { 290 | o := orm.NewOrm() 291 | v := User{Id: m.Id} 292 | lastLogin := time.Now().UTC().Unix() 293 | m.LastLogin = lastLogin 294 | // ascertain id exists in the database 295 | if err = o.Read(&v); err == nil { 296 | var num int64 297 | if num, err = o.Update(m); err == nil { 298 | fmt.Println("Number of records updated in database:", num) 299 | } 300 | } 301 | return err 302 | } 303 | 304 | // UpdateUser updates User by Id and returns error if 305 | // the record to be updated doesn't exist 306 | func UpdateUserById(m *User) (err error) { 307 | o := orm.NewOrm() 308 | v := User{Id: m.Id} 309 | // ascertain id exists in the database 310 | if err = o.Read(&v); err == nil { 311 | var num int64 312 | if num, err = o.Update(m); err == nil { 313 | fmt.Println("Number of records updated in database:", num) 314 | } 315 | } 316 | return 317 | } 318 | 319 | // DeleteUser deletes User by Id and returns error if 320 | // the record to be deleted doesn't exist 321 | func DeleteUser(id int) (err error) { 322 | o := orm.NewOrm() 323 | v := User{Id: id} 324 | // ascertain id exists in the database 325 | if err = o.Read(&v); err == nil { 326 | var num int64 327 | if num, err = o.Delete(&AirAd{Id: id}); err == nil { 328 | fmt.Println("Number of records deleted in database:", num) 329 | } 330 | } 331 | return 332 | } 333 | 334 | 335 | func GetUsername(id int) string { 336 | var err error 337 | var username string 338 | 339 | err = utils.GetCache("GetUsername.id."+fmt.Sprintf("%d", id), &username) 340 | if err != nil { 341 | cacheExpire, _ := beego.AppConfig.Int("cache_expire") 342 | var user User 343 | o := orm.NewOrm() 344 | o.QueryTable(TableName("user")).Filter("Id", id).One(&user, "username") 345 | username = user.Username 346 | utils.SetCache("GetRealname.id."+fmt.Sprintf("%d", id), username, cacheExpire) 347 | } 348 | return username 349 | } 350 | 351 | //func HashPassword(password string) (string, error) { 352 | // bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) 353 | // return string(bytes), err 354 | //} 355 | // 356 | //func CheckPasswordHash(password, hash string) bool { 357 | // err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) 358 | // return err == nil 359 | //} 360 | 361 | 362 | 363 | //func generateToken() (tokenString string, err error) { 364 | // /* Create the token */ 365 | // token := jwt.New(jwt.SigningMethodHS256) 366 | // 367 | // /* Create a map to store our claims 368 | // claims := token.Claims.(jwt.MapClaims) 369 | // 370 | // /* Set token claims */ 371 | // claims["admin"] = true 372 | // claims["name"] = "Ado Kukic" 373 | // claims["exp"] = time.Now().Add(time.Hour * 24).Unix() 374 | // 375 | // /* Sign the token with our secret */ 376 | // tokenString, _ := token.SignedString(mySigningKey) 377 | //} -------------------------------------------------------------------------------- /pictures/airad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/pictures/airad.png -------------------------------------------------------------------------------- /pictures/airad_swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/pictures/airad_swagger.png -------------------------------------------------------------------------------- /routers/router.go: -------------------------------------------------------------------------------- 1 | // @APIVersion 1.0.0 2 | // @Title beego Test API 3 | // @Description beego has a very cool tools to autogenerate documents for your API 4 | // @Contact astaxie@gmail.com 5 | // @TermsOfServiceUrl http://beego.me/ 6 | // @License Apache 2.0 7 | // @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html 8 | package routers 9 | 10 | import ( 11 | "github.com/astaxie/beego" 12 | 13 | "github.com/rubinliudongpo/airad/controllers" 14 | ) 15 | 16 | func init() { 17 | beego.Router("/", &controllers.MainController{}) 18 | beego.Router("/login", &controllers.UserController{}, "post:Login") 19 | ns := beego.NewNamespace("/v1", 20 | beego.NSNamespace("/user", beego.NSInclude(&controllers.UserController{},),), 21 | beego.NSNamespace("/airad", beego.NSInclude(&controllers.AirAdController{},),), 22 | beego.NSNamespace("/device", beego.NSInclude(&controllers.DeviceController{},),), 23 | ) 24 | beego.AddNamespace(ns) 25 | //beego.InsertFilter("/permission/list", beego.BeforeRouter, filters.HasPermission) 26 | beego.Router("/v1/device/getdevicebyuserid", &controllers.DeviceController{}, "POST:GetDevicesByUserId") 27 | } 28 | -------------------------------------------------------------------------------- /swagger/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/swagger/favicon-16x16.png -------------------------------------------------------------------------------- /swagger/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubinliudongpo/airad/3968aa1f7cefb098976544aa463db6535204f15a/swagger/favicon-32x32.png -------------------------------------------------------------------------------- /swagger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 11 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 | 70 | 71 | 72 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /swagger/oauth2-redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 54 | -------------------------------------------------------------------------------- /swagger/swagger-ui-bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;AAu/FA;AA6+FA;;;;;;;;;;;;;;;;;;;;;;;;;;AAyTA;;;;;;AAoIA;AAi7FA;AAmtCA;AAi0IA;AA0oJA;AAgwFA;AAyrGA;AA0lFA;AA4nFA;AA+9CA;AA+gDA;AAwrCA;AA60EA;;;;;AA6oCA;AAsyJA;;;;;;;;;;;;;;AA64EA;AA4mIA;AAquJA;AA2qHA;AA2mGA;AAiiEA;AAq4DA;AAg3DA;AAoPA;;;;;;AAk7FA;AA07FA;;;;;AAi8CA;AAgsFA;AAs2CA;AAglCA;AAu9CA;AAy8EA;AAsiCA;AA+yFA;;;;;;;;;AAgkDA;AA2zIA;AAu7FA;AAmrFA;AAu0EA","sourceRoot":""} -------------------------------------------------------------------------------- /swagger/swagger-ui-standalone-preset.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA8QA;AAmvGA;AAuxFA;;;;;;AAocA;AAkvFA;AAu+CA;AAo+CA;AAgrCA;AAuyEA","sourceRoot":""} -------------------------------------------------------------------------------- /swagger/swagger-ui.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";.swagger-ui html{box-sizing:border-box}.swagger-ui *,.swagger-ui :after,.swagger-ui :before{box-sizing:inherit}.swagger-ui body{margin:0;background:#fafafa}.swagger-ui .wrapper{width:100%;max-width:1460px;margin:0 auto;padding:0 20px}.swagger-ui .opblock-tag-section{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.swagger-ui .opblock-tag{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;border-bottom:1px solid rgba(59,65,81,.3);-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock-tag:hover{background:rgba(0,0,0,.02)}.swagger-ui .opblock-tag{font-size:24px;margin:0 0 5px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock-tag.no-desc span{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui .opblock-tag svg{transition:all .4s}.swagger-ui .opblock-tag small{font-size:14px;font-weight:400;padding:0 10px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parаmeter__type{font-size:12px;padding:5px 0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .view-line-link{position:relative;top:3px;width:20px;margin:0 5px;cursor:pointer;transition:all .5s}.swagger-ui .opblock{margin:0 0 15px;border:1px solid #000;border-radius:4px;box-shadow:0 0 3px rgba(0,0,0,.19)}.swagger-ui .opblock.is-open .opblock-summary{border-bottom:1px solid #000}.swagger-ui .opblock .opblock-section-header{padding:8px 20px;background:hsla(0,0%,100%,.8);box-shadow:0 1px 2px rgba(0,0,0,.1)}.swagger-ui .opblock .opblock-section-header,.swagger-ui .opblock .opblock-section-header label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock .opblock-section-header label{font-size:12px;font-weight:700;margin:0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-section-header label span{padding:0 10px 0 0}.swagger-ui .opblock .opblock-section-header h4{font-size:14px;margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary-method{font-size:14px;font-weight:700;min-width:80px;padding:6px 15px;text-align:center;border-radius:3px;background:#000;text-shadow:0 1px 0 rgba(0,0,0,.1);font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:16px;display:-webkit-box;display:-ms-flexbox;display:flex;padding:0 10px;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock .opblock-summary-path .view-line-link,.swagger-ui .opblock .opblock-summary-path__deprecated .view-line-link{position:relative;top:2px;width:0;margin:0;cursor:pointer;transition:all .5s}.swagger-ui .opblock .opblock-summary-path:hover .view-line-link,.swagger-ui .opblock .opblock-summary-path__deprecated:hover .view-line-link{width:18px;margin:0 5px}.swagger-ui .opblock .opblock-summary-path__deprecated{text-decoration:line-through}.swagger-ui .opblock .opblock-summary-description{font-size:13px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary{display:-webkit-box;display:-ms-flexbox;display:flex;padding:5px;cursor:pointer;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock.opblock-post{border-color:#49cc90;background:rgba(73,204,144,.1)}.swagger-ui .opblock.opblock-post .opblock-summary-method{background:#49cc90}.swagger-ui .opblock.opblock-post .opblock-summary{border-color:#49cc90}.swagger-ui .opblock.opblock-put{border-color:#fca130;background:rgba(252,161,48,.1)}.swagger-ui .opblock.opblock-put .opblock-summary-method{background:#fca130}.swagger-ui .opblock.opblock-put .opblock-summary{border-color:#fca130}.swagger-ui .opblock.opblock-delete{border-color:#f93e3e;background:rgba(249,62,62,.1)}.swagger-ui .opblock.opblock-delete .opblock-summary-method{background:#f93e3e}.swagger-ui .opblock.opblock-delete .opblock-summary{border-color:#f93e3e}.swagger-ui .opblock.opblock-get{border-color:#61affe;background:rgba(97,175,254,.1)}.swagger-ui .opblock.opblock-get .opblock-summary-method{background:#61affe}.swagger-ui .opblock.opblock-get .opblock-summary{border-color:#61affe}.swagger-ui .opblock.opblock-patch{border-color:#50e3c2;background:rgba(80,227,194,.1)}.swagger-ui .opblock.opblock-patch .opblock-summary-method{background:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary{border-color:#50e3c2}.swagger-ui .opblock.opblock-head{border-color:#9012fe;background:rgba(144,18,254,.1)}.swagger-ui .opblock.opblock-head .opblock-summary-method{background:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary{border-color:#9012fe}.swagger-ui .opblock.opblock-options{border-color:#0d5aa7;background:rgba(13,90,167,.1)}.swagger-ui .opblock.opblock-options .opblock-summary-method{background:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary{border-color:#0d5aa7}.swagger-ui .opblock.opblock-deprecated{opacity:.6;border-color:#ebebeb;background:hsla(0,0%,92%,.1)}.swagger-ui .opblock.opblock-deprecated .opblock-summary-method{background:#ebebeb}.swagger-ui .opblock.opblock-deprecated .opblock-summary{border-color:#ebebeb}.swagger-ui .opblock .opblock-schemes{padding:8px 20px}.swagger-ui .opblock .opblock-schemes .schemes-title{padding:0 10px 0 0}.swagger-ui .tab{display:-webkit-box;display:-ms-flexbox;display:flex;margin:20px 0 10px;padding:0;list-style:none}.swagger-ui .tab li{font-size:12px;min-width:100px;min-width:90px;padding:0;cursor:pointer;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .tab li:first-of-type{position:relative;padding-left:0}.swagger-ui .tab li:first-of-type:after{position:absolute;top:0;right:6px;width:1px;height:100%;content:"";background:rgba(0,0,0,.2)}.swagger-ui .tab li.active{font-weight:700}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-title_normal{padding:15px 20px}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-description-wrapper h4,.swagger-ui .opblock-title_normal,.swagger-ui .opblock-title_normal h4{font-size:12px;margin:0 0 5px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper p,.swagger-ui .opblock-title_normal p{font-size:14px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .execute-wrapper{padding:20px;text-align:right}.swagger-ui .execute-wrapper .btn{width:100%;padding:8px 40px}.swagger-ui .body-param-options{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.swagger-ui .body-param-options .body-param-edit{padding:10px 0}.swagger-ui .body-param-options label{padding:8px 0}.swagger-ui .body-param-options label select{margin:3px 0 0}.swagger-ui .responses-inner{padding:20px}.swagger-ui .responses-inner h4,.swagger-ui .responses-inner h5{font-size:12px;margin:10px 0 5px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .response-col_status{font-size:14px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .response-col_status .response-undocumented{font-size:11px;font-family:Source Code Pro,monospace;font-weight:600;color:#999}.swagger-ui .response-col_description__inner span{font-size:12px;font-style:italic;display:block;margin:10px 0;padding:10px;border-radius:4px;background:#41444e;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .response-col_description__inner span p{margin:0}.swagger-ui .opblock-body pre{font-size:12px;margin:0;padding:10px;word-wrap:break-word;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;white-space:pre-wrap;border-radius:4px;background:#41444e;overflow-wrap:break-word;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .opblock-body pre span{color:#fff!important}.swagger-ui .opblock-body pre .headerline{display:block}.swagger-ui .scheme-container{margin:0 0 20px;padding:30px 0;background:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.15)}.swagger-ui .scheme-container .schemes{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .scheme-container .schemes>label{font-size:12px;font-weight:700;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:-20px 15px 0 0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .scheme-container .schemes>label select{min-width:130px;text-transform:uppercase}.swagger-ui .loading-container{padding:40px 0 60px}.swagger-ui .loading-container .loading{position:relative}.swagger-ui .loading-container .loading:after{font-size:10px;font-weight:700;position:absolute;top:50%;left:50%;content:"loading";-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-transform:uppercase;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .loading-container .loading:before{position:absolute;top:50%;left:50%;display:block;width:60px;height:60px;margin:-30px;content:"";-webkit-animation:rotation 1s infinite linear,opacity .5s;animation:rotation 1s infinite linear,opacity .5s;opacity:1;border:2px solid rgba(85,85,85,.1);border-top-color:rgba(0,0,0,.6);border-radius:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden}@-webkit-keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes blinker{50%{opacity:0}}@keyframes blinker{50%{opacity:0}}.swagger-ui .btn{font-size:14px;font-weight:700;padding:5px 23px;transition:all .3s;border:2px solid #888;border-radius:4px;background:transparent;box-shadow:0 1px 2px rgba(0,0,0,.1);font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .btn[disabled]{cursor:not-allowed;opacity:.3}.swagger-ui .btn:hover{box-shadow:0 0 5px rgba(0,0,0,.3)}.swagger-ui .btn.cancel{border-color:#ff6060;font-family:Titillium Web,sans-serif;color:#ff6060}.swagger-ui .btn.authorize{line-height:1;display:inline;color:#49cc90;border-color:#49cc90}.swagger-ui .btn.authorize span{float:left;padding:4px 20px 0 0}.swagger-ui .btn.authorize svg{fill:#49cc90}.swagger-ui .btn.execute{-webkit-animation:pulse 2s infinite;animation:pulse 2s infinite;color:#fff;border-color:#4990e2}@-webkit-keyframes pulse{0%{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,.8)}70%{box-shadow:0 0 0 5px rgba(73,144,226,0)}to{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,0)}}@keyframes pulse{0%{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,.8)}70%{box-shadow:0 0 0 5px rgba(73,144,226,0)}to{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,0)}}.swagger-ui .btn-group{display:-webkit-box;display:-ms-flexbox;display:flex;padding:30px}.swagger-ui .btn-group .btn{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui .btn-group .btn:first-child{border-radius:4px 0 0 4px}.swagger-ui .btn-group .btn:last-child{border-radius:0 4px 4px 0}.swagger-ui .authorization__btn{padding:0 10px;border:none;background:none}.swagger-ui .authorization__btn.locked{opacity:1}.swagger-ui .authorization__btn.unlocked{opacity:.4}.swagger-ui .expand-methods,.swagger-ui .expand-operation{border:none;background:none}.swagger-ui .expand-methods svg,.swagger-ui .expand-operation svg{width:20px;height:20px}.swagger-ui .expand-methods{padding:0 10px}.swagger-ui .expand-methods:hover svg{fill:#444}.swagger-ui .expand-methods svg{transition:all .3s;fill:#777}.swagger-ui button{cursor:pointer;outline:none}.swagger-ui select{font-size:14px;font-weight:700;padding:5px 40px 5px 10px;border:2px solid #41444e;border-radius:4px;background:#f7f7f7 url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+ICAgIDxwYXRoIGQ9Ik0xMy40MTggNy44NTljLjI3MS0uMjY4LjcwOS0uMjY4Ljk3OCAwIC4yNy4yNjguMjcyLjcwMSAwIC45NjlsLTMuOTA4IDMuODNjLS4yNy4yNjgtLjcwNy4yNjgtLjk3OSAwbC0zLjkwOC0zLjgzYy0uMjctLjI2Ny0uMjctLjcwMSAwLS45NjkuMjcxLS4yNjguNzA5LS4yNjguOTc4IDBMMTAgMTFsMy40MTgtMy4xNDF6Ii8+PC9zdmc+) right 10px center no-repeat;background-size:20px;box-shadow:0 1px 2px 0 rgba(0,0,0,.25);font-family:Titillium Web,sans-serif;color:#3b4151;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui select[multiple]{margin:5px 0;padding:5px;background:#f7f7f7}.swagger-ui .opblock-body select{min-width:230px}.swagger-ui label{font-size:12px;font-weight:700;margin:0 0 5px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui input[type=email],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text]{min-width:100px;margin:5px 0;padding:8px 10px;border:1px solid #d9d9d9;border-radius:4px;background:#fff}.swagger-ui input[type=email].invalid,.swagger-ui input[type=password].invalid,.swagger-ui input[type=search].invalid,.swagger-ui input[type=text].invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}.swagger-ui textarea{font-size:12px;width:100%;min-height:280px;padding:10px;border:none;border-radius:4px;outline:none;background:hsla(0,0%,100%,.8);font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui textarea:focus{border:2px solid #61affe}.swagger-ui textarea.curl{font-size:12px;min-height:100px;margin:0;padding:10px;resize:none;border-radius:4px;background:#41444e;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .checkbox{padding:5px 0 10px;transition:opacity .5s;color:#333}.swagger-ui .checkbox label{display:-webkit-box;display:-ms-flexbox;display:flex}.swagger-ui .checkbox p{font-weight:400!important;font-style:italic;margin:0!important;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .checkbox input[type=checkbox]{display:none}.swagger-ui .checkbox input[type=checkbox]+label>.item{position:relative;top:3px;display:inline-block;width:16px;height:16px;margin:0 8px 0 0;padding:5px;cursor:pointer;border-radius:1px;background:#e8e8e8;box-shadow:0 0 0 2px #e8e8e8;-webkit-box-flex:0;-ms-flex:none;flex:none}.swagger-ui .checkbox input[type=checkbox]+label>.item:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .checkbox input[type=checkbox]:checked+label>.item{background:#e8e8e8 url("data:image/svg+xml;charset=utf-8,%3Csvg width='10' height='8' viewBox='3 7 10 8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2341474E' fill-rule='evenodd' d='M6.333 15L3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z'/%3E%3C/svg%3E") 50% no-repeat}.swagger-ui .dialog-ux{position:fixed;z-index:9999;top:0;right:0;bottom:0;left:0}.swagger-ui .dialog-ux .backdrop-ux{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.8)}.swagger-ui .dialog-ux .modal-ux{position:absolute;z-index:9999;top:50%;left:50%;width:100%;min-width:300px;max-width:650px;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border:1px solid #ebebeb;border-radius:4px;background:#fff;box-shadow:0 10px 30px 0 rgba(0,0,0,.2)}.swagger-ui .dialog-ux .modal-ux-content{overflow-y:auto;max-height:540px;padding:20px}.swagger-ui .dialog-ux .modal-ux-content p{font-size:12px;margin:0 0 5px;color:#41444e;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-content h4{font-size:18px;font-weight:600;margin:15px 0 0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-header{display:-webkit-box;display:-ms-flexbox;display:flex;padding:12px 0;border-bottom:1px solid #ebebeb;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .dialog-ux .modal-ux-header .close-modal{padding:0 10px;border:none;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui .dialog-ux .modal-ux-header h3{font-size:20px;font-weight:600;margin:0;padding:0 20px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .model{font-size:12px;font-weight:300;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .model-toggle{font-size:10px;position:relative;top:6px;display:inline-block;margin:auto .3em;cursor:pointer;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:50% 50%;transform-origin:50% 50%}.swagger-ui .model-toggle.collapsed{-webkit-transform:rotate(0deg);transform:rotate(0deg)}.swagger-ui .model-toggle:after{display:block;width:20px;height:20px;content:"";background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") 50% no-repeat;background-size:100%}.swagger-ui .model-jump-to-path{position:relative;cursor:pointer}.swagger-ui .model-jump-to-path .view-line-link{position:absolute;top:-.4em;cursor:pointer}.swagger-ui .model-title{position:relative}.swagger-ui .model-title:hover .model-hint{visibility:visible}.swagger-ui .model-hint{position:absolute;top:-1.8em;visibility:hidden;padding:.1em .5em;white-space:nowrap;color:#ebebeb;border-radius:4px;background:rgba(0,0,0,.7)}.swagger-ui section.models{margin:30px 0;border:1px solid rgba(59,65,81,.3);border-radius:4px}.swagger-ui section.models.is-open{padding:0 0 20px}.swagger-ui section.models.is-open h4{margin:0 0 5px;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui section.models.is-open h4 svg{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui section.models h4{font-size:16px;display:-webkit-box;display:-ms-flexbox;display:flex;margin:0;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;font-family:Titillium Web,sans-serif;color:#777;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui section.models h4 svg{transition:all .4s}.swagger-ui section.models h4 span{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui section.models h4:hover{background:rgba(0,0,0,.02)}.swagger-ui section.models h5{font-size:16px;margin:0 0 10px;font-family:Titillium Web,sans-serif;color:#777}.swagger-ui section.models .model-jump-to-path{position:relative;top:5px}.swagger-ui section.models .model-container{margin:0 20px 15px;transition:all .5s;border-radius:4px;background:rgba(0,0,0,.05)}.swagger-ui section.models .model-container:hover{background:rgba(0,0,0,.07)}.swagger-ui section.models .model-container:first-of-type{margin:20px}.swagger-ui section.models .model-container:last-of-type{margin:0 20px}.swagger-ui section.models .model-box{background:none}.swagger-ui .model-box{padding:10px;border-radius:4px;background:rgba(0,0,0,.1)}.swagger-ui .model-box .model-jump-to-path{position:relative;top:4px}.swagger-ui .model-title{font-size:16px;font-family:Titillium Web,sans-serif;color:#555}.swagger-ui span>span.model,.swagger-ui span>span.model .brace-close{padding:0 0 0 10px}.swagger-ui .prop-type{color:#55a}.swagger-ui .prop-enum{display:block}.swagger-ui .prop-format{color:#999}.swagger-ui table{width:100%;padding:0 10px;border-collapse:collapse}.swagger-ui table.model tbody tr td{padding:0;vertical-align:top}.swagger-ui table.model tbody tr td:first-of-type{width:100px;padding:0}.swagger-ui table.headers td{font-size:12px;font-weight:300;vertical-align:middle;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui table tbody tr td{padding:10px 0 0;vertical-align:top}.swagger-ui table tbody tr td:first-of-type{width:20%;padding:10px 0}.swagger-ui table thead tr td,.swagger-ui table thead tr th{font-size:12px;font-weight:700;padding:12px 0;text-align:left;border-bottom:1px solid rgba(59,65,81,.2);font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parameters-col_description p{font-size:14px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parameters-col_description input[type=text]{width:100%;max-width:340px}.swagger-ui .parameter__name{font-size:16px;font-weight:400;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .parameter__name.required{font-weight:700}.swagger-ui .parameter__name.required:after{font-size:10px;position:relative;top:-6px;padding:5px;content:"required";color:rgba(255,0,0,.6)}.swagger-ui .parameter__in{font-size:12px;font-style:italic;font-family:Source Code Pro,monospace;font-weight:600;color:#888}.swagger-ui .table-container{padding:20px}.swagger-ui .topbar{padding:8px 30px;background-color:#89bf04}.swagger-ui .topbar .topbar-wrapper{-ms-flex-align:center}.swagger-ui .topbar .topbar-wrapper,.swagger-ui .topbar a{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;align-items:center}.swagger-ui .topbar a{font-size:1.5em;font-weight:700;max-width:300px;text-decoration:none;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-align:center;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .topbar a span{margin:0;padding:0 10px}.swagger-ui .topbar .download-url-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:3;-ms-flex:3;flex:3}.swagger-ui .topbar .download-url-wrapper input[type=text]{width:100%;min-width:350px;margin:0;border:2px solid #547f00;border-radius:4px 0 0 4px;outline:none}.swagger-ui .topbar .download-url-wrapper .download-url-button{font-size:16px;font-weight:700;padding:4px 40px;border:none;border-radius:0 4px 4px 0;background:#547f00;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .info{margin:50px 0}.swagger-ui .info hgroup.main{margin:0 0 20px}.swagger-ui .info hgroup.main a{font-size:12px}.swagger-ui .info li,.swagger-ui .info p,.swagger-ui .info table{font-size:14px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info h1,.swagger-ui .info h2,.swagger-ui .info h3,.swagger-ui .info h4,.swagger-ui .info h5{font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info code{padding:3px 5px;border-radius:4px;background:rgba(0,0,0,.05);font-family:Source Code Pro,monospace;font-weight:600;color:#9012fe}.swagger-ui .info a{font-size:14px;transition:all .4s;font-family:Open Sans,sans-serif;color:#4990e2}.swagger-ui .info a:hover{color:#1f69c0}.swagger-ui .info>div{margin:0 0 5px}.swagger-ui .info .base-url{font-size:12px;font-weight:300!important;margin:0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .info .title{font-size:36px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info .title small{font-size:10px;position:relative;top:-5px;display:inline-block;margin:0 0 0 5px;padding:2px 4px;vertical-align:super;border-radius:57px;background:#7d8492}.swagger-ui .info .title small pre{margin:0;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .auth-btn-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px 0;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.swagger-ui .auth-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.swagger-ui .auth-wrapper .authorize{padding-right:20px}.swagger-ui .auth-container{margin:0 0 10px;padding:10px 20px;border-bottom:1px solid #ebebeb}.swagger-ui .auth-container:last-of-type{margin:0;padding:10px 20px;border:0}.swagger-ui .auth-container h4{margin:5px 0 15px!important}.swagger-ui .auth-container .wrapper{margin:0;padding:0}.swagger-ui .auth-container input[type=password],.swagger-ui .auth-container input[type=text]{min-width:230px}.swagger-ui .auth-container .errors{font-size:12px;padding:10px;border-radius:4px;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .scopes h2{font-size:14px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .scope-def{padding:0 0 20px}.swagger-ui .errors-wrapper{margin:20px;padding:10px 20px;-webkit-animation:scaleUp .5s;animation:scaleUp .5s;border:2px solid #f93e3e;border-radius:4px;background:rgba(249,62,62,.1)}.swagger-ui .errors-wrapper .error-wrapper{margin:0 0 10px}.swagger-ui .errors-wrapper .errors h4{font-size:14px;margin:0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .errors-wrapper .errors small{color:#666}.swagger-ui .errors-wrapper hgroup{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .errors-wrapper hgroup h4{font-size:20px;margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}@-webkit-keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.swagger-ui .Resizer.vertical.disabled{display:none} 2 | /*# sourceMappingURL=swagger-ui.css.map*/ -------------------------------------------------------------------------------- /swagger/swagger-ui.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"swagger-ui.css","sources":[],"mappings":"","sourceRoot":""} -------------------------------------------------------------------------------- /swagger/swagger-ui.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AA0yCA;AAoyHA;AAmyHA;AAykGA;AA+9BA;AA6iCA;AAojCA;AAu5BA","sourceRoot":""} -------------------------------------------------------------------------------- /swagger/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "beego Test API", 5 | "description": "beego has a very cool tools to autogenerate documents for your API", 6 | "version": "1.0.0", 7 | "termsOfService": "http://beego.me/", 8 | "contact": { 9 | "email": "astaxie@gmail.com" 10 | }, 11 | "license": { 12 | "name": "Apache 2.0", 13 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 14 | } 15 | }, 16 | "basePath": "/v1", 17 | "paths": { 18 | "/airad/": { 19 | "get": { 20 | "tags": [ 21 | "airad" 22 | ], 23 | "description": "get AirAd", 24 | "operationId": "AirAdController.GetAll", 25 | "parameters": [ 26 | { 27 | "in": "query", 28 | "name": "query", 29 | "description": "Filter. e.g. col1:v1,col2:v2 ...", 30 | "type": "string" 31 | }, 32 | { 33 | "in": "query", 34 | "name": "fields", 35 | "description": "Fields returned. e.g. col1,col2 ...", 36 | "type": "string" 37 | }, 38 | { 39 | "in": "query", 40 | "name": "sortby", 41 | "description": "Sorted-by fields. e.g. col1,col2 ...", 42 | "type": "string" 43 | }, 44 | { 45 | "in": "query", 46 | "name": "order", 47 | "description": "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ...", 48 | "type": "string" 49 | }, 50 | { 51 | "in": "query", 52 | "name": "limit", 53 | "description": "Limit the size of result set. Must be an integer", 54 | "type": "string" 55 | }, 56 | { 57 | "in": "query", 58 | "name": "offset", 59 | "description": "Start position of result set. Must be an integer", 60 | "type": "string" 61 | } 62 | ], 63 | "responses": { 64 | "200": { 65 | "description": "", 66 | "schema": { 67 | "$ref": "#/definitions/models.AirAd" 68 | } 69 | }, 70 | "403": { 71 | "description": "" 72 | } 73 | } 74 | }, 75 | "post": { 76 | "tags": [ 77 | "airad" 78 | ], 79 | "description": "create AirAd", 80 | "operationId": "AirAdController.Create", 81 | "parameters": [ 82 | { 83 | "in": "body", 84 | "name": "body", 85 | "description": "body for AirAd content", 86 | "required": true, 87 | "schema": { 88 | "$ref": "#/definitions/models.AirAd" 89 | } 90 | } 91 | ], 92 | "responses": { 93 | "201": { 94 | "description": "", 95 | "schema": { 96 | "$ref": "#/definitions/models.AirAd" 97 | } 98 | }, 99 | "403": { 100 | "description": "body is empty" 101 | } 102 | } 103 | } 104 | }, 105 | "/airad/{id}": { 106 | "get": { 107 | "tags": [ 108 | "airad" 109 | ], 110 | "description": "get AirAd by id", 111 | "operationId": "AirAdController.GetOne", 112 | "parameters": [ 113 | { 114 | "in": "path", 115 | "name": "id", 116 | "description": "The key for staticblock", 117 | "required": true, 118 | "type": "string" 119 | } 120 | ], 121 | "responses": { 122 | "200": { 123 | "description": "", 124 | "schema": { 125 | "$ref": "#/definitions/models.AirAd" 126 | } 127 | }, 128 | "403": { 129 | "description": ":id is empty" 130 | } 131 | } 132 | }, 133 | "put": { 134 | "tags": [ 135 | "airad" 136 | ], 137 | "description": "update the AirAd", 138 | "operationId": "AirAdController.Put", 139 | "parameters": [ 140 | { 141 | "in": "path", 142 | "name": "id", 143 | "description": "The id you want to update", 144 | "required": true, 145 | "type": "string" 146 | }, 147 | { 148 | "in": "body", 149 | "name": "body", 150 | "description": "body for AirAd content", 151 | "required": true, 152 | "schema": { 153 | "$ref": "#/definitions/models.AirAd" 154 | } 155 | } 156 | ], 157 | "responses": { 158 | "200": { 159 | "description": "", 160 | "schema": { 161 | "$ref": "#/definitions/models.AirAd" 162 | } 163 | }, 164 | "403": { 165 | "description": ":id is not int" 166 | } 167 | } 168 | }, 169 | "delete": { 170 | "tags": [ 171 | "airad" 172 | ], 173 | "description": "delete the AirAd", 174 | "operationId": "AirAdController.Delete", 175 | "parameters": [ 176 | { 177 | "in": "path", 178 | "name": "id", 179 | "description": "The id you want to delete", 180 | "required": true, 181 | "type": "string" 182 | } 183 | ], 184 | "responses": { 185 | "200": { 186 | "description": "{string} delete success!" 187 | }, 188 | "403": { 189 | "description": "id is empty" 190 | } 191 | } 192 | } 193 | }, 194 | "/user/": { 195 | "get": { 196 | "tags": [ 197 | "user" 198 | ], 199 | "description": "get all Users", 200 | "operationId": "UserController.GetAll", 201 | "responses": { 202 | "200": { 203 | "description": "", 204 | "schema": { 205 | "$ref": "#/definitions/models.User" 206 | } 207 | } 208 | } 209 | }, 210 | "post": { 211 | "tags": [ 212 | "user" 213 | ], 214 | "description": "create users", 215 | "operationId": "UserController.CreateUser", 216 | "parameters": [ 217 | { 218 | "in": "body", 219 | "name": "body", 220 | "description": "body for user content", 221 | "required": true, 222 | "schema": { 223 | "$ref": "#/definitions/models.User" 224 | } 225 | } 226 | ], 227 | "responses": { 228 | "200": { 229 | "description": "{int} models.User.Id" 230 | }, 231 | "403": { 232 | "description": "body is empty" 233 | } 234 | } 235 | } 236 | }, 237 | "/user/login": { 238 | "get": { 239 | "tags": [ 240 | "user" 241 | ], 242 | "description": "Logs user into the system", 243 | "operationId": "UserController.Login", 244 | "parameters": [ 245 | { 246 | "in": "query", 247 | "name": "username", 248 | "description": "The username for login", 249 | "required": true, 250 | "type": "string" 251 | }, 252 | { 253 | "in": "query", 254 | "name": "password", 255 | "description": "The password for login", 256 | "required": true, 257 | "type": "string" 258 | } 259 | ], 260 | "responses": { 261 | "200": { 262 | "description": "{string} login success" 263 | }, 264 | "403": { 265 | "description": "user not exist" 266 | } 267 | } 268 | } 269 | }, 270 | "/user/logout": { 271 | "get": { 272 | "tags": [ 273 | "user" 274 | ], 275 | "description": "Logs out current logged in user session", 276 | "operationId": "UserController.logout", 277 | "responses": { 278 | "200": { 279 | "description": "{string} logout success" 280 | } 281 | } 282 | } 283 | }, 284 | "/user/{id}": { 285 | "get": { 286 | "tags": [ 287 | "user" 288 | ], 289 | "description": "get User by id", 290 | "operationId": "UserController.GetOne", 291 | "parameters": [ 292 | { 293 | "in": "path", 294 | "name": "id", 295 | "description": "The key for staticblock", 296 | "required": true, 297 | "type": "string" 298 | } 299 | ], 300 | "responses": { 301 | "200": { 302 | "description": "", 303 | "schema": { 304 | "$ref": "#/definitions/models.AirAd" 305 | } 306 | }, 307 | "403": { 308 | "description": ":id is empty" 309 | } 310 | } 311 | } 312 | }, 313 | "/user/{uid}": { 314 | "put": { 315 | "tags": [ 316 | "user" 317 | ], 318 | "description": "update the user", 319 | "operationId": "UserController.Update", 320 | "parameters": [ 321 | { 322 | "in": "path", 323 | "name": "uid", 324 | "description": "The uid you want to update", 325 | "required": true, 326 | "type": "string" 327 | }, 328 | { 329 | "in": "body", 330 | "name": "body", 331 | "description": "body for user content", 332 | "required": true, 333 | "schema": { 334 | "$ref": "#/definitions/models.User" 335 | } 336 | } 337 | ], 338 | "responses": { 339 | "200": { 340 | "description": "", 341 | "schema": { 342 | "$ref": "#/definitions/models.User" 343 | } 344 | }, 345 | "403": { 346 | "description": ":uid is not int" 347 | } 348 | } 349 | }, 350 | "delete": { 351 | "tags": [ 352 | "user" 353 | ], 354 | "description": "delete the user", 355 | "operationId": "UserController.Delete", 356 | "parameters": [ 357 | { 358 | "in": "path", 359 | "name": "uid", 360 | "description": "The uid you want to delete", 361 | "required": true, 362 | "type": "string" 363 | } 364 | ], 365 | "responses": { 366 | "200": { 367 | "description": "{string} delete success!" 368 | }, 369 | "403": { 370 | "description": "uid is empty" 371 | } 372 | } 373 | } 374 | } 375 | }, 376 | "definitions": { 377 | "models.AirAd": { 378 | "title": "AirAd", 379 | "type": "object", 380 | "properties": { 381 | "aqi_quality": { 382 | "type": "string" 383 | }, 384 | "co": { 385 | "type": "string" 386 | }, 387 | "created_at": { 388 | "type": "integer", 389 | "format": "int64" 390 | }, 391 | "humidity": { 392 | "type": "string" 393 | }, 394 | "id": { 395 | "type": "integer", 396 | "format": "int64" 397 | }, 398 | "latitude": { 399 | "type": "string" 400 | }, 401 | "longitude": { 402 | "type": "string" 403 | }, 404 | "nh3": { 405 | "type": "string" 406 | }, 407 | "o3": { 408 | "type": "string" 409 | }, 410 | "pm10": { 411 | "type": "string" 412 | }, 413 | "pm25": { 414 | "type": "string" 415 | }, 416 | "so2": { 417 | "type": "string" 418 | }, 419 | "suggest": { 420 | "type": "string" 421 | }, 422 | "temperature": { 423 | "type": "string" 424 | } 425 | } 426 | }, 427 | "models.Object": { 428 | "title": "Object", 429 | "type": "object", 430 | "properties": { 431 | "ObjectId": { 432 | "type": "string" 433 | }, 434 | "PlayerName": { 435 | "type": "string" 436 | }, 437 | "Score": { 438 | "type": "integer", 439 | "format": "int64" 440 | } 441 | } 442 | }, 443 | "models.User": { 444 | "title": "User", 445 | "type": "object", 446 | "properties": { 447 | "address": { 448 | "type": "string" 449 | }, 450 | "age": { 451 | "type": "integer", 452 | "format": "int64" 453 | }, 454 | "email": { 455 | "type": "string" 456 | }, 457 | "gender": { 458 | "type": "int, 0:Male, 1: Female, 2: undefined" 459 | }, 460 | "password": { 461 | "type": "string" 462 | }, 463 | "status": { 464 | "type": "int, 0: enabled, 1:disabled", 465 | "format": "int64" 466 | }, 467 | "username": { 468 | "type": "string" 469 | } 470 | } 471 | } 472 | }, 473 | "tags": [ 474 | { 475 | "name": "user", 476 | "description": "Operations about Users\n" 477 | }, 478 | { 479 | "name": "airad", 480 | "description": "AirAdController operations for AirAd\n" 481 | } 482 | ] 483 | } -------------------------------------------------------------------------------- /swagger/swagger.yml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | info: 3 | title: beego Test API 4 | description: beego has a very cool tools to autogenerate documents for your API 5 | version: 1.0.0 6 | termsOfService: http://beego.me/ 7 | contact: 8 | email: astaxie@gmail.com 9 | license: 10 | name: Apache 2.0 11 | url: http://www.apache.org/licenses/LICENSE-2.0.html 12 | basePath: /v1 13 | paths: 14 | /airad/: 15 | get: 16 | tags: 17 | - airad 18 | description: get AirAd 19 | operationId: AirAdController.GetAll 20 | parameters: 21 | - in: query 22 | name: query 23 | description: Filter. e.g. col1:v1,col2:v2 ... 24 | type: string 25 | - in: query 26 | name: fields 27 | description: Fields returned. e.g. col1,col2 ... 28 | type: string 29 | - in: query 30 | name: sortby 31 | description: Sorted-by fields. e.g. col1,col2 ... 32 | type: string 33 | - in: query 34 | name: order 35 | description: Order corresponding to each sortby field, if single value, apply 36 | to all sortby fields. e.g. desc,asc ... 37 | type: string 38 | - in: query 39 | name: limit 40 | description: Limit the size of result set. Must be an integer 41 | type: string 42 | - in: query 43 | name: offset 44 | description: Start position of result set. Must be an integer 45 | type: string 46 | responses: 47 | "200": 48 | description: "" 49 | schema: 50 | $ref: '#/definitions/models.AirAd' 51 | "403": 52 | description: "" 53 | post: 54 | tags: 55 | - airad 56 | description: create AirAd 57 | operationId: AirAdController.Create 58 | parameters: 59 | - in: body 60 | name: body 61 | description: body for AirAd content 62 | required: true 63 | schema: 64 | $ref: '#/definitions/models.AirAd' 65 | responses: 66 | "201": 67 | description: "" 68 | schema: 69 | $ref: '#/definitions/models.AirAd' 70 | "403": 71 | description: body is empty 72 | /airad/{id}: 73 | get: 74 | tags: 75 | - airad 76 | description: get AirAd by id 77 | operationId: AirAdController.GetOne 78 | parameters: 79 | - in: path 80 | name: id 81 | description: The key for staticblock 82 | required: true 83 | type: string 84 | responses: 85 | "200": 86 | description: "" 87 | schema: 88 | $ref: '#/definitions/models.AirAd' 89 | "403": 90 | description: :id is empty 91 | put: 92 | tags: 93 | - airad 94 | description: update the AirAd 95 | operationId: AirAdController.Put 96 | parameters: 97 | - in: path 98 | name: id 99 | description: The id you want to update 100 | required: true 101 | type: string 102 | - in: body 103 | name: body 104 | description: body for AirAd content 105 | required: true 106 | schema: 107 | $ref: '#/definitions/models.AirAd' 108 | responses: 109 | "200": 110 | description: "" 111 | schema: 112 | $ref: '#/definitions/models.AirAd' 113 | "403": 114 | description: :id is not int 115 | delete: 116 | tags: 117 | - airad 118 | description: delete the AirAd 119 | operationId: AirAdController.Delete 120 | parameters: 121 | - in: path 122 | name: id 123 | description: The id you want to delete 124 | required: true 125 | type: string 126 | responses: 127 | "200": 128 | description: '{string} delete success!' 129 | "403": 130 | description: id is empty 131 | /user/: 132 | get: 133 | tags: 134 | - user 135 | description: get all Users 136 | operationId: UserController.GetAll 137 | responses: 138 | "200": 139 | description: "" 140 | schema: 141 | $ref: '#/definitions/models.User' 142 | post: 143 | tags: 144 | - user 145 | description: create users 146 | operationId: UserController.CreateUser 147 | parameters: 148 | - in: body 149 | name: body 150 | description: body for user content 151 | required: true 152 | schema: 153 | $ref: '#/definitions/models.User' 154 | responses: 155 | "200": 156 | description: '{int} models.User.Id' 157 | "403": 158 | description: body is empty 159 | /user/{id}: 160 | get: 161 | tags: 162 | - user 163 | description: get User by id 164 | operationId: UserController.GetOne 165 | parameters: 166 | - in: path 167 | name: id 168 | description: The key for staticblock 169 | required: true 170 | type: string 171 | responses: 172 | "200": 173 | description: "" 174 | schema: 175 | $ref: '#/definitions/models.AirAd' 176 | "403": 177 | description: :id is empty 178 | /user/{uid}: 179 | put: 180 | tags: 181 | - user 182 | description: update the user 183 | operationId: UserController.Update 184 | parameters: 185 | - in: path 186 | name: uid 187 | description: The uid you want to update 188 | required: true 189 | type: string 190 | - in: body 191 | name: body 192 | description: body for user content 193 | required: true 194 | schema: 195 | $ref: '#/definitions/models.User' 196 | responses: 197 | "200": 198 | description: "" 199 | schema: 200 | $ref: '#/definitions/models.User' 201 | "403": 202 | description: :uid is not int 203 | delete: 204 | tags: 205 | - user 206 | description: delete the user 207 | operationId: UserController.Delete 208 | parameters: 209 | - in: path 210 | name: uid 211 | description: The uid you want to delete 212 | required: true 213 | type: string 214 | responses: 215 | "200": 216 | description: '{string} delete success!' 217 | "403": 218 | description: uid is empty 219 | /user/login: 220 | get: 221 | tags: 222 | - user 223 | description: Logs user into the system 224 | operationId: UserController.Login 225 | parameters: 226 | - in: query 227 | name: username 228 | description: The username for login 229 | required: true 230 | type: string 231 | - in: query 232 | name: password 233 | description: The password for login 234 | required: true 235 | type: string 236 | responses: 237 | "200": 238 | description: '{string} login success' 239 | "403": 240 | description: user not exist 241 | /user/logout: 242 | get: 243 | tags: 244 | - user 245 | description: Logs out current logged in user session 246 | operationId: UserController.logout 247 | responses: 248 | "200": 249 | description: '{string} logout success' 250 | definitions: 251 | models.AirAd: 252 | title: AirAd 253 | type: object 254 | properties: 255 | aqi_quality: 256 | type: string 257 | co: 258 | type: string 259 | created_at: 260 | type: integer 261 | format: int64 262 | humidity: 263 | type: string 264 | id: 265 | type: integer 266 | format: int64 267 | latitude: 268 | type: string 269 | longitude: 270 | type: string 271 | nh3: 272 | type: string 273 | o3: 274 | type: string 275 | pm10: 276 | type: string 277 | pm25: 278 | type: string 279 | so2: 280 | type: string 281 | suggest: 282 | type: string 283 | temperature: 284 | type: string 285 | models.Object: 286 | title: Object 287 | type: object 288 | properties: 289 | ObjectId: 290 | type: string 291 | PlayerName: 292 | type: string 293 | Score: 294 | type: integer 295 | format: int64 296 | models.User: 297 | title: User 298 | type: object 299 | properties: 300 | address: 301 | type: string 302 | age: 303 | type: integer 304 | format: int64 305 | created_at: 306 | type: integer 307 | format: int64 308 | email: 309 | type: string 310 | gender: 311 | type: string 312 | id: 313 | type: integer 314 | format: int64 315 | last_login: 316 | type: integer 317 | format: int64 318 | password: 319 | type: string 320 | status: 321 | type: integer 322 | format: int64 323 | token: 324 | type: string 325 | updated_at: 326 | type: integer 327 | format: int64 328 | username: 329 | type: string 330 | tags: 331 | - name: user 332 | description: | 333 | Operations about Users 334 | - name: airad 335 | description: | 336 | AirAdController operations for AirAd 337 | -------------------------------------------------------------------------------- /tests/default_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | "runtime" 8 | "path/filepath" 9 | _ "airad/routers" 10 | 11 | "github.com/astaxie/beego" 12 | . "github.com/smartystreets/goconvey/convey" 13 | ) 14 | 15 | func init() { 16 | _, file, _, _ := runtime.Caller(1) 17 | apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) 18 | beego.TestBeegoInit(apppath) 19 | } 20 | 21 | // TestGet is a sample to run an endpoint test 22 | func TestGet(t *testing.T) { 23 | r, _ := http.NewRequest("GET", "/v1/object", nil) 24 | w := httptest.NewRecorder() 25 | beego.BeeApp.Handlers.ServeHTTP(w, r) 26 | 27 | beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String()) 28 | 29 | Convey("Subject: Test Station Endpoint\n", t, func() { 30 | Convey("Status Code Should Be 200", func() { 31 | So(w.Code, ShouldEqual, 200) 32 | }) 33 | Convey("The Result Should Not Be Empty", func() { 34 | So(w.Body.Len(), ShouldBeGreaterThan, 0) 35 | }) 36 | }) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /utils/airad.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "strings" 7 | ) 8 | 9 | func GetNeedsStatus(status int) string { 10 | var txt string 11 | switch status { 12 | case 1: 13 | txt = "草稿" 14 | case 2: 15 | txt = "激活" 16 | case 3: 17 | txt = "已变更" 18 | case 4: 19 | txt = "待关闭" 20 | case 5: 21 | txt = "已关闭" 22 | } 23 | return txt 24 | } 25 | 26 | func GetNeedsSource(source int) string { 27 | var txt string 28 | switch source { 29 | case 1: 30 | txt = "客户" 31 | case 2: 32 | txt = "用户" 33 | case 3: 34 | txt = "产品经理" 35 | case 4: 36 | txt = "市场" 37 | case 5: 38 | txt = "客服" 39 | case 6: 40 | txt = "竞争对手" 41 | case 7: 42 | txt = "合作伙伴" 43 | case 8: 44 | txt = "开发人员" 45 | case 9: 46 | txt = "测试人员" 47 | case 10: 48 | txt = "其他" 49 | } 50 | return txt 51 | } 52 | 53 | func GetNeedsStage(stage int) string { 54 | var txt string 55 | switch stage { 56 | case 1: 57 | txt = "未开始" 58 | case 2: 59 | txt = "已计划" 60 | case 3: 61 | txt = "已立项" 62 | case 4: 63 | txt = "研发中" 64 | case 5: 65 | txt = "研发完毕" 66 | case 6: 67 | txt = "测试中" 68 | case 7: 69 | txt = "测试完毕" 70 | case 8: 71 | txt = "已验收" 72 | case 9: 73 | txt = "已发布" 74 | } 75 | return txt 76 | } 77 | 78 | func GetTaskStatus(status int) string { 79 | var txt string 80 | switch status { 81 | case 1: 82 | txt = "未开始" 83 | case 2: 84 | txt = "进行中" 85 | case 3: 86 | txt = "已完成" 87 | case 4: 88 | txt = "已暂停" 89 | case 5: 90 | txt = "已取消" 91 | case 6: 92 | txt = "已关闭" 93 | } 94 | return txt 95 | } 96 | 97 | func GetTaskType(tasktype int) string { 98 | var txt string 99 | switch tasktype { 100 | case 1: 101 | txt = "设计" 102 | case 2: 103 | txt = "开发" 104 | case 3: 105 | txt = "测试" 106 | case 4: 107 | txt = "研究" 108 | case 5: 109 | txt = "讨论" 110 | case 6: 111 | txt = "界面" 112 | case 7: 113 | txt = "事务" 114 | case 8: 115 | txt = "其他" 116 | } 117 | return txt 118 | } 119 | 120 | func GetTestStatus(status int) string { 121 | var txt string 122 | switch status { 123 | case 1: 124 | txt = "设计如此" 125 | case 2: 126 | txt = "重复Bug" 127 | case 3: 128 | txt = "外部原因" 129 | case 4: 130 | txt = "已解决" 131 | case 5: 132 | txt = "无法重现" 133 | case 6: 134 | txt = "延期处理" 135 | case 7: 136 | txt = "不予解决" 137 | } 138 | return txt 139 | } 140 | 141 | func GetOs(os string) string { 142 | var txt string 143 | switch os { 144 | case "all": 145 | txt = "全部" 146 | case "windows": 147 | txt = "windows" 148 | case "win8": 149 | txt = "Windows 8" 150 | case "vista": 151 | txt = "Windows Vista" 152 | case "win7": 153 | txt = "Windows 7" 154 | case "winxp": 155 | txt = "Windows XP" 156 | case "win2012": 157 | txt = "Windows 2012" 158 | case "win2008": 159 | txt = "Windows 2008" 160 | case "win2003": 161 | txt = "Windows 2003" 162 | case "win2000": 163 | txt = "Windows 2000" 164 | case "android": 165 | txt = "Android" 166 | case "ios": 167 | txt = "IOS" 168 | case "wp8": 169 | txt = "WP8" 170 | case "wp7": 171 | txt = "WP7" 172 | case "symbian": 173 | txt = "Symbian" 174 | case "linux": 175 | txt = "Linux" 176 | case "freebsd": 177 | txt = "FreeBSD" 178 | case "osx": 179 | txt = "OS X" 180 | case "unix": 181 | txt = "Unix" 182 | case "other": 183 | txt = "其他" 184 | } 185 | return txt 186 | } 187 | 188 | func GetBrowser(browser string) string { 189 | var txt string 190 | switch browser { 191 | case "all": 192 | txt = "全部" 193 | case "ie": 194 | txt = "IE系列" 195 | case "ie11": 196 | txt = "IE11" 197 | case "ie10": 198 | txt = "IE10" 199 | case "ie9": 200 | txt = "IE9" 201 | case "ie8": 202 | txt = "IE8" 203 | case "ie7": 204 | txt = "IE7" 205 | case "ie6": 206 | txt = "IE6" 207 | case "chrome": 208 | txt = "chrome" 209 | case "firefox": 210 | txt = "firefox" 211 | case "opera": 212 | txt = "opera" 213 | case "safari": 214 | txt = "safari" 215 | case "maxthon": 216 | txt = "傲游" 217 | case "uc": 218 | txt = "UC" 219 | case "other": 220 | txt = "其他" 221 | } 222 | return txt 223 | } 224 | 225 | func GetAvatarSource(avatar string) string { 226 | if "" == avatar { 227 | return "/static/uploadfile/2016-8/17/picture.jpg" 228 | } 229 | return strings.Replace(avatar, "-cropper", "", -1) 230 | } 231 | 232 | func GetAvatar(avatar string) string { 233 | if "" == avatar { 234 | return fmt.Sprintf("/static/img/avatar/%d.jpg", rand.Intn(5)) 235 | } 236 | return avatar 237 | } 238 | func GetEdu(edu int) string { 239 | var txt string 240 | switch edu { 241 | case 1: 242 | txt = "小学" 243 | case 2: 244 | txt = "中专" 245 | case 3: 246 | txt = "初中" 247 | case 4: 248 | txt = "高中" 249 | case 5: 250 | txt = "技校" 251 | case 6: 252 | txt = "大专" 253 | case 7: 254 | txt = "本科" 255 | case 8: 256 | txt = "硕士" 257 | case 9: 258 | txt = "博士" 259 | case 10: 260 | txt = "博士后" 261 | } 262 | return txt 263 | } 264 | 265 | func GetWorkYear(year int) string { 266 | var txt string 267 | switch year { 268 | case 1: 269 | txt = "应届毕业生" 270 | case 2: 271 | txt = "1年以下" 272 | case 3: 273 | txt = "1-2年" 274 | case 4: 275 | txt = "3-5年" 276 | case 5: 277 | txt = "6-7年" 278 | case 6: 279 | txt = "8-10年" 280 | case 7: 281 | txt = "10年以上" 282 | } 283 | return txt 284 | } 285 | 286 | func GetResumeStatus(status int) string { 287 | var txt string 288 | switch status { 289 | case 1: 290 | txt = "入档" 291 | case 2: 292 | txt = "通知面试" 293 | case 3: 294 | txt = "违约" 295 | case 4: 296 | txt = "录用" 297 | case 5: 298 | txt = "不录用" 299 | } 300 | return txt 301 | } 302 | 303 | func GetLeaveType(ltype int) string { 304 | var txt string 305 | switch ltype { 306 | case 1: 307 | txt = "事假" 308 | case 2: 309 | txt = "病假" 310 | case 3: 311 | txt = "年假" 312 | case 4: 313 | txt = "调休" 314 | case 5: 315 | txt = "婚假" 316 | case 6: 317 | txt = "产假" 318 | case 7: 319 | txt = "陪产假" 320 | case 8: 321 | txt = "路途假" 322 | case 9: 323 | txt = "其他" 324 | } 325 | return txt 326 | } 327 | 328 | func GetCheckworkType(ctype int) string { 329 | var txt string 330 | switch ctype { 331 | case 1: 332 | txt = "正常" 333 | case 2: 334 | txt = "迟到" 335 | case 3: 336 | txt = "早退" 337 | case 4: 338 | txt = "加班" 339 | } 340 | return txt 341 | } 342 | 343 | func GetMessageType(ctype int) string { 344 | var txt string 345 | switch ctype { 346 | case 1: 347 | txt = "评论" 348 | case 2: 349 | txt = "赞" 350 | case 3: 351 | txt = "审批" 352 | case 4: 353 | txt = "新加" 354 | } 355 | return txt 356 | } 357 | 358 | //11知识评论12相册评论21知识赞22相册赞31请假审批32加班33报销34出差35外出36物品 359 | func GetMessageSubtype(subtype int) string { 360 | var txt string 361 | switch subtype { 362 | case 11: 363 | txt = "知识" 364 | case 12: 365 | txt = "相册" 366 | case 21: 367 | txt = "知识" 368 | case 22: 369 | txt = "相册" 370 | case 31: 371 | txt = "请假" 372 | case 32: 373 | txt = "加班" 374 | case 33: 375 | txt = "报销" 376 | case 34: 377 | txt = "出差" 378 | case 35: 379 | txt = "外出" 380 | case 36: 381 | txt = "物品" 382 | } 383 | return txt 384 | } 385 | -------------------------------------------------------------------------------- /utils/bootStrap.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "fmt" 7 | "github.com/astaxie/beego" 8 | "os/signal" 9 | 10 | ) 11 | 12 | func InitBootStrap() { 13 | graceful, _ := beego.AppConfig.Bool("Graceful") 14 | if !graceful { 15 | sigs := make(chan os.Signal, 1) 16 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 17 | go handleSignals(sigs) 18 | } 19 | beego.SetLogger("file", `{"filename":"logs/logs.log"}`) 20 | 21 | if beego.BConfig.RunMode == "dev" { 22 | beego.BConfig.WebConfig.DirectoryIndex = true 23 | beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger" 24 | beego.SetLevel(beego.LevelDebug) 25 | } else if (beego.BConfig.RunMode == "prod") { 26 | beego.SetLevel(beego.LevelInformational) 27 | } 28 | //beego.InsertFilter("/*", beego.BeforeRouter, FilterUser) 29 | } 30 | 31 | func handleSignals(c chan os.Signal) { 32 | switch <-c { 33 | case syscall.SIGINT, syscall.SIGTERM: 34 | fmt.Println("Shutdown quickly, bye...") 35 | case syscall.SIGQUIT: 36 | fmt.Println("Shutdown gracefully, bye...") 37 | // do graceful shutdown 38 | } 39 | os.Exit(0) 40 | } 41 | 42 | //var FilterUser = func(ctx *context.Context) { 43 | // _, ok := ctx.Input.Session("userLogin").(string) 44 | // if !ok && ctx.Request.RequestURI != "/" { 45 | // ctx.Redirect(302, "/") 46 | // } 47 | //} 48 | 49 | -------------------------------------------------------------------------------- /utils/cache.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "errors" 7 | //"fmt" 8 | "time" 9 | 10 | "github.com/astaxie/beego" 11 | "github.com/astaxie/beego/cache" 12 | _ "github.com/astaxie/beego/cache/memcache" 13 | _ "github.com/astaxie/beego/cache/redis" 14 | ) 15 | 16 | var cc cache.Cache 17 | 18 | func InitCache() { 19 | cacheConfig := beego.AppConfig.String("cache") 20 | cc = nil 21 | 22 | if "redis" == cacheConfig { 23 | initRedis() 24 | } else { 25 | initMemcache() 26 | } 27 | 28 | //fmt.Println("[cache] use", cacheConfig) 29 | } 30 | 31 | func initMemcache() { 32 | var err error 33 | cc, err = cache.NewCache("memcache", `{"conn":"`+beego.AppConfig.String("memcache_host")+`"}`) 34 | 35 | if err != nil { 36 | beego.Info(err) 37 | } 38 | 39 | } 40 | 41 | func initRedis() { 42 | // cc = &cache.Cache{} 43 | var err error 44 | 45 | defer func() { 46 | if r := recover(); r != nil { 47 | //fmt.Println("initial redis error caught: %v\n", r) 48 | cc = nil 49 | } 50 | }() 51 | 52 | cc, err = cache.NewCache("redis", `{"conn":"`+beego.AppConfig.String("redis_host")+`", 53 | "password":"`+beego.AppConfig.String("redis_password")+`"}`) 54 | 55 | if err != nil { 56 | //fmt.Println(err) 57 | } 58 | } 59 | 60 | func SetCache(key string, value interface{}, timeout int) error { 61 | data, err := Encode(value) 62 | if err != nil { 63 | return err 64 | } 65 | if cc == nil { 66 | return errors.New("cc is nil") 67 | } 68 | 69 | defer func() { 70 | if r := recover(); r != nil { 71 | //fmt.Println("set cache error caught: %v\n", r) 72 | cc = nil 73 | } 74 | }() 75 | timeouts := time.Duration(timeout) * time.Second 76 | err = cc.Put(key, data, timeouts) 77 | if err != nil { 78 | //fmt.Println("Cache失败,key:", key) 79 | return err 80 | } else { 81 | //fmt.Println("Cache成功,key:", key) 82 | return nil 83 | } 84 | } 85 | 86 | func GetCache(key string, to interface{}) error { 87 | if cc == nil { 88 | return errors.New("cc is nil") 89 | } 90 | 91 | defer func() { 92 | if r := recover(); r != nil { 93 | //fmt.Println("get cache error caught: %v\n", r) 94 | cc = nil 95 | } 96 | }() 97 | 98 | data := cc.Get(key) 99 | if data == nil { 100 | return errors.New("Cache不存在") 101 | } 102 | // log.Pinkln(data) 103 | err := Decode(data.([]byte), to) 104 | if err != nil { 105 | //fmt.Println("获取Cache失败", key, err) 106 | } else { 107 | //fmt.Println("获取Cache成功", key) 108 | } 109 | 110 | return err 111 | } 112 | 113 | func DelCache(key string) error { 114 | if cc == nil { 115 | return errors.New("cc is nil") 116 | } 117 | 118 | defer func() { 119 | if r := recover(); r != nil { 120 | //fmt.Println("get cache error caught: %v\n", r) 121 | cc = nil 122 | } 123 | }() 124 | 125 | err := cc.Delete(key) 126 | if err != nil { 127 | return errors.New("Cache删除失败") 128 | } else { 129 | //fmt.Println("删除Cache成功 " + key) 130 | return nil 131 | } 132 | } 133 | 134 | // -------------------- 135 | // Encode 136 | // 用gob进行数据编码 137 | // 138 | func Encode(data interface{}) ([]byte, error) { 139 | buf := bytes.NewBuffer(nil) 140 | enc := gob.NewEncoder(buf) 141 | err := enc.Encode(data) 142 | if err != nil { 143 | return nil, err 144 | } 145 | return buf.Bytes(), nil 146 | } 147 | 148 | // ------------------- 149 | // Decode 150 | // 用gob进行数据解码 151 | // 152 | func Decode(data []byte, to interface{}) error { 153 | buf := bytes.NewBuffer(data) 154 | dec := gob.NewDecoder(buf) 155 | return dec.Decode(to) 156 | } 157 | -------------------------------------------------------------------------------- /utils/cropper.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | //"fmt" 5 | //"graphics" 6 | "image" 7 | "image/jpeg" 8 | "log" 9 | //"net/http" 10 | "os" 11 | //"strconv" 12 | "strings" 13 | 14 | //"code.google.com/p/graphics-go/graphics" 15 | "github.com/BurntSushi/graphics-go/graphics" 16 | ) 17 | 18 | //http://studygolang.com/articles/3375 19 | //http://studygolang.com/articles/4307 20 | //http://studygolang.com/articles/2581 21 | //http://studygolang.com/articles/2453 22 | func DoImageHandler(url string, newdx int) { 23 | src, err := LoadImage("." + url) 24 | //bound := src.Bounds() 25 | //dx := bound.Dx() 26 | //dy := bound.Dy() 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | //fmt.Println(dx, dy, newdx) 31 | // 缩略图的大小 32 | dst := image.NewRGBA(image.Rect(640, 640, 200, 200)) 33 | //dst := image.NewRGBA(image.Rect(0, 0, newdx, newdx*dy/dx)) 34 | // 产生缩略图,等比例缩放 35 | //err = graphics.Scale(dst, src) 36 | err = graphics.Thumbnail(dst, src) 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | filen := strings.Replace(url, ".", "-cropper.", -1) 42 | file, err := os.Create("." + filen) 43 | defer file.Close() 44 | 45 | err = jpeg.Encode(file, dst, &jpeg.Options{100}) //图像质量值为100,是最好的图像显示 46 | 47 | //header := w.Header() 48 | //header.Add("Content-Type", "image/jpeg") 49 | 50 | //png.Encode(w, dst) 51 | } 52 | 53 | // Load Image decodes an image from a file of image. 54 | func LoadImage(path string) (img image.Image, err error) { 55 | file, err := os.Open(path) 56 | if err != nil { 57 | return 58 | } 59 | defer file.Close() 60 | img, _, err = image.Decode(file) 61 | return 62 | } 63 | 64 | /*file, err := os.Open("./" + filepath) 65 | if err != nil { 66 | fmt.Println(err) 67 | } 68 | defer file.Close() 69 | 70 | file1, err := os.Create(dir + "/" + "test1.jpg") 71 | if err != nil { 72 | fmt.Println(err) 73 | } 74 | defer file1.Close() 75 | 76 | m, _, _ := image.Decode(file) // 图片文件解码 77 | rgbImg := m.(*image.YCbCr) 78 | subImg := rgbImg.SubImage(image.Rect(0, 0, 200, 200)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 79 | err = jpeg.Encode(file1, subImg, &jpeg.Options{100}) //图像质量值为100,是最好的图像显示 80 | if err != nil { 81 | fmt.Println(err) 82 | } 83 | */ 84 | -------------------------------------------------------------------------------- /utils/date.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | /* 8 | func GetDate(timestamp int64) string { 9 | tm := time.Unix(timestamp, 0) 10 | return tm.Format("2006-01-02 15:04") 11 | } 12 | func GetDateMH(timestamp int64) string { 13 | tm := time.Unix(timestamp, 0) 14 | return tm.Format("01-02 03:04") 15 | }*/ 16 | 17 | func GetDateFormat(timestamp int64, format string) string { 18 | if timestamp <= 0 { 19 | return "" 20 | } 21 | tm := time.Unix(timestamp, 0) 22 | return tm.Format(format) 23 | } 24 | 25 | func GetDate(timestamp int64) string { 26 | if timestamp <= 0 { 27 | return "" 28 | } 29 | tm := time.Unix(timestamp, 0) 30 | return tm.Format("2006-01-02") 31 | } 32 | 33 | func GetDateMH(timestamp int64) string { 34 | if timestamp <= 0 { 35 | return "" 36 | } 37 | tm := time.Unix(timestamp, 0) 38 | return tm.Format("2006-01-02 15:04") 39 | } 40 | 41 | func GetTimeParse(times string) int64 { 42 | if "" == times { 43 | return 0 44 | } 45 | loc, _ := time.LoadLocation("Local") 46 | parse, _ := time.ParseInLocation("2006-01-02 15:04", times, loc) 47 | return parse.Unix() 48 | } 49 | 50 | func GetDateParse(dates string) int64 { 51 | if "" == dates { 52 | return 0 53 | } 54 | loc, _ := time.LoadLocation("Local") 55 | parse, _ := time.ParseInLocation("2006-01-02", dates, loc) 56 | return parse.Unix() 57 | } 58 | -------------------------------------------------------------------------------- /utils/encrypt.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/rand" 6 | "encoding/base64" 7 | "encoding/hex" 8 | "io" 9 | ) 10 | 11 | //md5方法 12 | func Md5(s string) string { 13 | h := md5.New() 14 | h.Write([]byte(s)) 15 | return hex.EncodeToString(h.Sum(nil)) 16 | } 17 | 18 | //Guid方法 19 | func GetGuid() string { 20 | b := make([]byte, 48) 21 | 22 | if _, err := io.ReadFull(rand.Reader, b); err != nil { 23 | return "" 24 | } 25 | return Md5(base64.URLEncoding.EncodeToString(b)) 26 | } 27 | -------------------------------------------------------------------------------- /utils/hashUtils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/base64" 6 | "fmt" 7 | "io" 8 | "crypto/rand" 9 | "golang.org/x/crypto/scrypt" 10 | ) 11 | 12 | const pwHashBytes = 64 13 | 14 | func Sha1(input string) string { 15 | if input == "" { 16 | return "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc" 17 | } 18 | return fmt.Sprintf("%x", sha1.Sum([]byte(input))) 19 | } 20 | 21 | func Secret2Password(username, secret string) string { 22 | return Sha1(Sha1(secret[:8]) + Sha1(username) + Sha1(secret[8:])) 23 | } 24 | 25 | func Base64(input string) string { 26 | return base64.StdEncoding.EncodeToString([]byte(input)) 27 | } 28 | 29 | func GenerateSalt() (salt string, err error) { 30 | buf := make([]byte, pwHashBytes) 31 | if _, err := io.ReadFull(rand.Reader, buf); err != nil { 32 | return "", err 33 | } 34 | 35 | return fmt.Sprintf("%x", buf), nil 36 | } 37 | 38 | func GeneratePassHash(password string, salt string) (hash string, err error) { 39 | h, err := scrypt.Key([]byte(password), []byte(salt), 16384, 8, 1, pwHashBytes) 40 | if err != nil { 41 | return "", err 42 | } 43 | 44 | return fmt.Sprintf("%x", h), nil 45 | } 46 | -------------------------------------------------------------------------------- /utils/jwt.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | "github.com/astaxie/beego/config" 6 | "github.com/dgrijalva/jwt-go" 7 | "log" 8 | ) 9 | 10 | type EasyToken struct { 11 | Username string 12 | Uid int64 13 | Expires int64 14 | } 15 | 16 | var ( 17 | verifyKey string 18 | ErrAbsent = "token absent" // 令牌不存在 19 | ErrInvalid = "token invalid" // 令牌无效 20 | ErrExpired = "token expired" // 令牌过期 21 | ErrOther = "other error" // 其他错误 22 | ) 23 | 24 | func init() { 25 | appConf, err := config.NewConfig("ini", "conf/app.conf") 26 | if err != nil { 27 | panic(err) 28 | } 29 | verifyKey = appConf.String("jwt::token") 30 | } 31 | 32 | func (e EasyToken) GetToken() (string, error) { 33 | claims := &jwt.StandardClaims{ 34 | ExpiresAt: e.Expires, //time.Unix(c.ExpiresAt, 0) 35 | Issuer: e.Username, 36 | } 37 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 38 | tokenString, err := token.SignedString([]byte(verifyKey)) 39 | if err != nil { 40 | log.Println(err) 41 | } 42 | return tokenString, err 43 | } 44 | 45 | func (e EasyToken) ValidateToken(tokenString string) (bool, error) { 46 | if tokenString == "" { 47 | return false, errors.New(ErrAbsent) 48 | } 49 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { 50 | return []byte(verifyKey), nil 51 | }) 52 | if token == nil { 53 | return false, errors.New(ErrInvalid) 54 | } 55 | if token.Valid { 56 | return true, nil 57 | } else if ve, ok := err.(*jwt.ValidationError); ok { 58 | if ve.Errors&jwt.ValidationErrorMalformed != 0 { 59 | return false, errors.New(ErrInvalid) 60 | } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { 61 | return false, errors.New(ErrExpired) 62 | } else { 63 | return false, errors.New(ErrOther) 64 | } 65 | } else { 66 | return false, errors.New(ErrOther) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | // 随机数生成 10 | // @Param min int 最小值 11 | // @Param max int 最大值 12 | // @return string 13 | func RandInt(min int, max int) string { 14 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 15 | num := r.Intn((max - min)) + min 16 | if num < min || num > max { 17 | RandInt(min, max) 18 | } 19 | return fmt.Sprintf("%d", num) 20 | } 21 | -------------------------------------------------------------------------------- /utils/sql.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | "github.com/astaxie/beego/orm" 6 | "fmt" 7 | ) 8 | 9 | func InitSql() { 10 | dbuser := beego.AppConfig.String("db.user") 11 | dbpassword := beego.AppConfig.String("db.password") 12 | dbhost := beego.AppConfig.String("db.host") 13 | dbport := beego.AppConfig.String("db.port") 14 | dbname := beego.AppConfig.String("db.name") 15 | if beego.AppConfig.String("runmode") == "dev" { 16 | orm.Debug = true 17 | } 18 | dsn := dbuser + ":" + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?charset=utf8mb4" 19 | orm.RegisterDriver("mysql", orm.DRMySQL) 20 | orm.RegisterDataBase("default", "mysql", dsn) 21 | if err := orm.RunSyncdb("default", false, true); err != nil { 22 | fmt.Println(err) 23 | } 24 | orm.RunCommand() 25 | } 26 | -------------------------------------------------------------------------------- /utils/template.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | 6 | 7 | ) 8 | 9 | func InitTemplate() { 10 | //beego.AddFuncMap("getUsername", models.GetUsername) 11 | 12 | beego.AddFuncMap("getDate", GetDate) 13 | beego.AddFuncMap("getDateMH", GetDateMH) 14 | 15 | beego.AddFuncMap("getOs", GetOs) 16 | beego.AddFuncMap("getBrowser", GetBrowser) 17 | beego.AddFuncMap("getAvatarSource", GetAvatarSource) 18 | beego.AddFuncMap("getAvatar", GetAvatar) 19 | } 20 | -------------------------------------------------------------------------------- /utils/validator.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "github.com/astaxie/beego/validation" 6 | ) 7 | 8 | func CheckUsernamePassword(username string, password string) (errorMessage string) { 9 | valid := validation.Validation{} 10 | //表单验证 11 | valid.Required(username, "Username").Message("用户名必填") 12 | valid.Required(password, "Password").Message("密码必填") 13 | 14 | if valid.HasErrors() { 15 | // 如果有错误信息,证明验证没通过 16 | for _, err := range valid.Errors { 17 | //c.Ctx.ResponseWriter.WriteHeader(403) 18 | //c.Data["json"] = Response{403001, 403001,err.Message, ""} 19 | //c.ServeJSON() 20 | return fmt.Sprintf("%s", err.Message) 21 | } 22 | } 23 | return fmt.Sprintf("%s", "ok") 24 | } 25 | 26 | func CheckNewUserPost(Username string, Password string, Age int, 27 | Gender int, Address string, Email string) (errorMessage string) { 28 | valid := validation.Validation{} 29 | //表单验证 30 | valid.Required(Username, "Username").Message("用户名必填") 31 | valid.AlphaNumeric(Username, "Username").Message("用户名必须是数字或字符") 32 | valid.Required(Password, "Password").Message("密码必填") 33 | valid.MinSize(Password, 6,"Password").Message("密码不能少于6位") 34 | valid.MaxSize(Password, 20,"Password").Message("密码不能多于20位") 35 | valid.Required(Age, "Age").Message("年龄必填") 36 | valid.Range(Age, 1,100, "Age").Message("年龄在1到100岁") 37 | valid.Range(Gender, 0,2, "Gender").Message("性别不正确") 38 | valid.Required(Address, "Address").Message("地址必填") 39 | valid.MinSize(Address, 6,"Address").Message("地址不能少于6位") 40 | valid.MaxSize(Address, 50,"Address").Message("地址不能多于50位") 41 | valid.Required(Email, "Email").Message("邮箱必填") 42 | valid.Email(Email, "Email").Message("邮箱格式不正确") 43 | 44 | if valid.HasErrors() { 45 | // 如果有错误信息,证明验证没通过 46 | for _, err := range valid.Errors { 47 | //c.Ctx.ResponseWriter.WriteHeader(403) 48 | //c.Data["json"] = Response{403001, 403001,err.Message, ""} 49 | //c.ServeJSON() 50 | return fmt.Sprintf("%s", err.Message) 51 | } 52 | } 53 | return fmt.Sprintf("%s", "ok") 54 | } 55 | 56 | func CheckNewDevicePost(userId int, deviceName string, address string, 57 | status int, latitude string, longitude string) (errorMessage string) { 58 | valid := validation.Validation{} 59 | //表单验证 60 | valid.Required(userId, "UserId").Message("用户ID必填") 61 | valid.Required(deviceName, "DeviceName").Message("设备名必填") 62 | valid.AlphaNumeric(deviceName, "DeviceName").Message("设备名必须是数字或字符") 63 | valid.Required(address, "Address").Message("地址必填") 64 | valid.MinSize(address, 6,"Address").Message("地址不能少于6位") 65 | valid.MaxSize(address, 50,"Address").Message("地址不能多于50位") 66 | valid.Range(status, 0, 1 ,"Status").Message("状态必填") 67 | valid.Required(latitude, "Latitude").Message("纬度必填") 68 | valid.Required(longitude, "Longitude").Message("经度必填") 69 | if valid.HasErrors() { 70 | // 如果有错误信息,证明验证没通过 71 | for _, err := range valid.Errors { 72 | //c.Ctx.ResponseWriter.WriteHeader(403) 73 | //c.Data["json"] = Response{403001, 403001,err.Message, ""} 74 | //c.ServeJSON() 75 | return fmt.Sprintf("%s", err.Message) 76 | } 77 | } 78 | return fmt.Sprintf("%s", "ok") 79 | } 80 | 81 | func CheckUserDevicePost(userId int, limit int, offset int) (errorMessage string){ 82 | valid := validation.Validation{} 83 | valid.Required(userId, "UserId").Message("用户ID必填") 84 | valid.Min(userId, 1, "UserId").Message("用户ID必须是数字") 85 | //valid.Required(limit, "Limit").Message("Limit必填") 86 | valid.Range(limit, 0, 20,"Limit").Message("Limit必须是数字") 87 | //valid.Required(offset, "Offset").Message("Offset必填") 88 | valid.Range(offset, 0, 20,"Offset").Message("Offset必须是数字") 89 | if valid.HasErrors() { 90 | // 如果有错误信息,证明验证没通过 91 | for _, err := range valid.Errors { 92 | //c.Ctx.ResponseWriter.WriteHeader(403) 93 | //c.Data["json"] = Response{403001, 403001,err.Message, ""} 94 | //c.ServeJSON() 95 | return fmt.Sprintf("%s", err.Message) 96 | } 97 | } 98 | return fmt.Sprintf("%s", "ok") 99 | 100 | } 101 | 102 | func CheckNewAirAdPost(deviceId int, co string, humidity string, temperature string, 103 | pm25 string, pm10 string, nh3 string, o3 string, suggest string, aqiQuality string)(errorMessage string) { 104 | valid := validation.Validation{} 105 | //表单验证 106 | valid.Required(deviceId, "DeviceId").Message("用户ID必填") 107 | valid.Required(co, "Co").Message("设备名必填") 108 | valid.Required(humidity, "Humidity").Message("地址必填") 109 | valid.Required(temperature, "DeviceId").Message("用户ID必填") 110 | valid.Required(pm25, "Co").Message("设备名必填") 111 | valid.Required(pm10, "Humidity").Message("地址必填") 112 | valid.Required(o3, "DeviceId").Message("用户ID必填") 113 | valid.Required(suggest, "Co").Message("设备名必填") 114 | valid.Required(aqiQuality, "Humidity").Message("地址必填") 115 | valid.Required(nh3, "DeviceId").Message("用户ID必填") 116 | 117 | if valid.HasErrors() { 118 | // 如果有错误信息,证明验证没通过 119 | for _, err := range valid.Errors { 120 | //c.Ctx.ResponseWriter.WriteHeader(403) 121 | //c.Data["json"] = Response{403001, 403001,err.Message, ""} 122 | //c.ServeJSON() 123 | return fmt.Sprintf("%s", err.Message) 124 | } 125 | } 126 | return fmt.Sprintf("%s", "ok") 127 | } -------------------------------------------------------------------------------- /views/index.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Beego 6 | 7 | 8 | 62 | 63 | 64 | 65 |
66 |
67 |
68 |
69 |

欢迎来到空气质量AQI实时发布广告系统!

70 |

71 | Beego is a simple & powerful Go web framework which is inspired by tornado and sinatra. 72 |
73 | Official website: {{.Website}} 74 |
75 | Contact me: {{.Email}} 76 |

77 |
78 |
79 |
80 |
81 | 82 | 83 | --------------------------------------------------------------------------------