update route

This commit is contained in:
a624669980@163.com 2022-07-12 09:45:19 +08:00
parent ce00e8f3f0
commit 0bb624debc
16 changed files with 461 additions and 557 deletions

10
main.go
View File

@ -24,7 +24,6 @@ var sqliteDB *gorm.DB
var configFlag = flag.String("c", "", "config address")
var dbFlag = flag.String("db", "", "db path")
var showUserInfo = flag.Bool("show-user-info", false, "show user info")
var resetUser = flag.Bool("ru", false, "reset user")
var user = flag.String("user", "", "user name")
@ -63,13 +62,6 @@ func init() {
// @BasePath /v1
func main() {
service.NotifyMsg = make(chan notify.Message, 10)
if *showUserInfo {
fmt.Println("CasaOS User Info")
fmt.Println("UserName:" + config.UserInfo.UserName)
fmt.Println("Password:" + config.UserInfo.PWD)
return
}
fmt.Println("Reset User", *resetUser)
if *resetUser {
if user == nil || len(*user) == 0 {
@ -85,7 +77,7 @@ func main() {
userData.Password = encryption.GetMD5ByStr(password)
service.MyService.User().UpdateUserPassword(userData)
fmt.Println("User reset successful")
fmt.Println("UserName:" + userData.UserName)
fmt.Println("UserName:" + userData.Username)
fmt.Println("Password:" + password)
return
}

View File

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-04 14:26:07
* @LastEditTime: 2022-07-11 18:10:53
* @FilePath: /CasaOS/pkg/sqlite/db.go
* @Description:
* @Website: https://www.casaos.io
@ -42,6 +42,17 @@ func GetDb(dbPath string) *gorm.DB {
return nil
}
gdb = db
db.Exec(`alter table o_user rename to old_user;
create table o_users ( id integer primary key,username text,password text,role text,email text,nickname text,avatar text,description text,created_at datetime,updated_at datetime);
insert into o_users select id,user_name,password,role,email,nick_name,avatar,description,created_at,updated_at from old_user;
drop table old_user;
drop table o_user;
`)
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.UserDBModel{})
db.Exec("DROP TABLE IF EXISTS o_application")
db.Exec("DROP TABLE IF EXISTS o_friend")

View File

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-04 18:15:09
* @LastEditTime: 2022-07-11 17:41:22
* @FilePath: /CasaOS/pkg/utils/jwt/jwt.go
* @Description:
* @Website: https://www.casaos.io
@ -17,7 +17,7 @@ import (
)
type Claims struct {
UserName string `json:"username"`
Username string `json:"username"`
PassWord string `json:"password"`
Id int `json:"id"`
jwt.RegisteredClaims

View File

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-17 14:01:25
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-04 18:14:28
* @LastEditTime: 2022-07-11 18:21:40
* @FilePath: /CasaOS/pkg/utils/jwt/jwt_helper.go
* @Description:
* @Website: https://www.casaos.io
@ -62,7 +62,7 @@ func GetAccessToken(username, pwd string, id int) string {
}
func GetRefreshToken(username, pwd string, id int) string {
token, err := GenerateToken(username, pwd, id, "fresh", 7*24*time.Hour*time.Duration(1))
token, err := GenerateToken(username, pwd, id, "refresh", 7*24*time.Hour*time.Duration(1))
if err == nil {
return token
} else {

View File

@ -145,9 +145,9 @@ func MoveUserToDB() {
if len(config.UserInfo.UserName) > 0 && service.MyService.User().GetUserInfoByUserName(config.UserInfo.UserName).Id == 0 {
user := model2.UserDBModel{}
user.UserName = config.UserInfo.UserName
user.Username = config.UserInfo.UserName
user.Email = config.UserInfo.Email
user.NickName = config.UserInfo.NickName
user.Nickname = config.UserInfo.NickName
user.Password = encryption.GetMD5ByStr(config.UserInfo.PWD)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)

View File

@ -26,7 +26,6 @@ func InitRouter() *gin.Engine {
r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode)
// @tiger - 为了方便未来的模块化迭代,前端输出需要独立端口,不要和 API 端口公用。
r.StaticFS("/ui", http.FS(web.Static))
r.GET("/", WebUIHome)
// r.StaticFS("/assets", http.Dir("./static/assets"))
@ -35,28 +34,18 @@ func InitRouter() *gin.Engine {
// c.Redirect(http.StatusMovedPermanently, "ui/")
//})
r.POST("/v1/user/register/:key", v1.PostUserRegister)
r.POST("/v1/user/login", v1.PostUserLogin) //
r.GET("/v1/users/names", v1.GetUserAllUserName) //all/name
// @tiger - 1不要把同一个词汇按单词来分割。2同领域的 API 应该放在同路径下。
r.GET("/v1/sys/init_check", v1.GetSystemInitCheck) // 这里改成 /v1/sys/init_check //init/check
//r.GET("/v1/guide/check", v1.GetGuideCheck) // 这里改成 /v1/sys/guide_check
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // 这里改成 /v1/sys/debug //debug
r.GET("/v1/user/:id/avatar/", v1.GetUserAvatar)
// @tiger - 如果遵循 RESTful image 本身并不是资源,而是属性;资源是 user
// 所以正规的方法是 改成 /v1/user/:id 然后返回 user 对象,具体 image 由前端自行抽取
// 不正规的方式是 改成 /v1/user/:id/image假定 image 也是资源
r.POST("/v1/user/register", v1.PostUserRegister)
r.POST("/v1/user/login", v1.PostUserLogin)
r.GET("/v1/users/name", v1.GetUserAllUsername) //all/name
r.POST("/v1/user/refresh", v1.PostUserRefreshToken)
// No short-term modifications
r.GET("/v1/user/image", v1.GetUserImage)
// @tiger - 不要把同一个词汇按单词来分割,改成 /v1/sys/socket_port
r.GET("/v1/sys/socket_port", v1.GetSystemSocketPort) //sys/socket_port
r.GET("/v1/user/status", v1.GetUserStatus) //init/check
//r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
// @tiger - nice-to-have开源项目应该删除所有注释代码增加代码整洁性。或者增加注释说明
//r.POST("/v1/user/refresh/token", v1.PostUserRefreshToken)
r.GET("/v1/sys/socket-port", v1.GetSystemSocketPort) //sys/socket_port
v1Group := r.Group("/v1")
@ -67,186 +56,177 @@ func InitRouter() *gin.Engine {
{
v1UserGroup.GET("/current", v1.GetUserInfo)
v1UserGroup.PUT("/current", v1.PutUserInfo)
// @tiger - RESTful 规范下所有对 user 的写操作,都应该 POST /v1/user/:id
// - 不需要每个更改的属性建一个 API
// id不用传,是否直接用/代替
v1UserGroup.PUT("/", v1.PutUserName)
//v1UserGroup.PUT("/password", v1.PutUserPwd)
//v1UserGroup.PUT("/nick", v1.PutUserNick) // 改成 /nickname
//v1UserGroup.PUT("/desc", v1.PutUserDesc) // 改成 /description
v1UserGroup.GET("/current/custom/:key", v1.GetUserCustomConf)
v1UserGroup.POST("/current/custom/:key", v1.PostUserCustomConf)
v1UserGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf)
// @tiger - RESTful 规范建议是 GET /v1/users/?username=xxxx
// 这是一个查询 API返回一个 users 数组(即使 username 是唯一的)
// 之所以不用 /v1/user/:username 是因为和 /v1/user/:id 路由冲突
//
// 当前这个设计的问题是GET 不应该同时接收 request body。
// GET 方法应该只接收 URL 参数
v1UserGroup.GET("/info", v1.GetUserInfoByUserName)
v1UserGroup.POST("/current/image/:key", v1.PostUserUploadImage)
//v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
v1UserGroup.DELETE("/current/image", v1.DeleteUserImage)
// @tiger - 改成 /user/current/custom/... 和上面的 current 对应
// 如果未来想获得其它用户的 custom 数据,可以用 /v1/user/:id/custom/... 来保持统一
v1UserGroup.GET("/custom/:key", v1.GetUserCustomConf)
v1UserGroup.POST("/custom/:key", v1.PostUserCustomConf)
v1UserGroup.DELETE("/custom/:key", v1.DeleteUserCustomConf)
// @tiger - 下面这两个 API 从感知上很难区分。
// 如果前者是负责上传,后者负责指定的话,那么
// 前者应该用一个统一的和目的无关的用户文件上传 API而不是针对 image file 的
v1UserGroup.POST("/upload/image/:key", v1.PostUserUploadImage)
v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
v1UserGroup.DELETE("/image", v1.DeleteUserImage)
// @tiger - 应该用上面提到的统一的文件上传 API 先上传头像文件,然后
// 用类似上面第二个 API 的方式指定头像文件。这样整体 API 体验更加统一。
v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
v1UserGroup.GET("/avatar", v1.GetUserAvatar)
// @tiger - 删除用户直接用 DELETE /v1/user/:id不需要在路径中用谓语
v1UserGroup.DELETE("/delete/:id", v1.DeleteUser)
//v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
//v1UserGroup.GET("/avatar", v1.GetUserAvatar)
v1UserGroup.DELETE("/:id", v1.DeleteUser)
v1UserGroup.GET("/:username", v1.GetUserInfoByUsername)
}
v1UsersGroup := v1Group.Group("/users")
v1UsersGroup.Use()
{
v1UsersGroup.DELETE("", v1.DeleteUserAll)
}
v1AppGroup := v1Group.Group("/app")
v1AppGroup.Use()
{
// @tiger - 按照 RESTFul 规范,改成 GET /v1/apps?installed=true
//获取我的已安装的列表
v1AppGroup.GET("/my/list", v1.MyAppList)
v1AppGroup.GET("/:id", v1.AppInfo)
}
v1AppsGroup := v1Group.Group("/apps")
v1AppsGroup.Use()
{
v1AppsGroup.GET("/", v1.AppList) //list
// @tiger - 按照 RESTFul 规范,改成 GET /v1/apps/usage
v1AppGroup.GET("/usage", v1.AppUsageList)
v1AppsGroup.GET("/usage", v1.AppUsageList)
}
v1ContainerGroup := v1Group.Group("/container")
v1ContainerGroup.Use()
{
v1ContainerGroup.GET("/", v1.MyAppList) ///my/list
v1ContainerGroup.POST("/", v1.InstallApp) //app/install
v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) //app/uninstall/:id
// @tiger - 按照 RESTFul 规范,改成 GET /v1/app/:id
//app详情
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
//v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo) ///update/:id/info
v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting
// @tiger - 按照 RESTFul 规范,改成 GET /v1/apps?installed=false
//获取未安装的列表
v1AppGroup.GET("/list", v1.AppList)
v1ContainerGroup.GET("/:id/logs", v1.ContainerLog) // /app/logs/:id
// there are problems, temporarily do not deal with
v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) //app/terminal/:id
v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id
// @tiger - 这个信息和应用无关,应该挪到 /v1/sys/port/avaiable
//获取端口
v1AppGroup.GET("/port", v1.GetPort)
v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) //app/install/config
// @tiger - RESTFul 路径中尽量不要有动词,同时这个信息和应用无关,应该挪到 /v1/sys/port/:port
//检查端口
v1AppGroup.GET("/check/:port", v1.PortCheck)
v1ContainerGroup.GET("/:id/state", v1.GetContainerState) //app/state/:id ?state=install_progress
// @tiger - 应用分类和应用不是一类资源,应该挪到 GET /v1/app_categories
v1AppGroup.GET("/category", v1.CategoryList)
//Not used
v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
//Not used
v1ContainerGroup.POST("/share", v1.ShareAppFile)
// @tiger - Docker Terminal 和应用不是一类资源,应该挪到 GET /v1/container/:id/terminal
// 另外这个返回的不是一个 HTTP 响应,应该返回一个 wss://... 的 URL给前端由前端另行处理
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
// @tiger - 所有跟 Docker 有关的 API应该挪到 /v1/container 下
//app容器详情
v1AppGroup.GET("/info/:id", v1.ContainerInfo) // 改成 GET /v1/container/:id
//app容器日志
v1AppGroup.GET("/logs/:id", v1.ContainerLog) // 改成 GET /v1/container/:id/log
//暂停或启动容器
v1AppGroup.PUT("/state/:id", v1.ChangAppState) // 改成 PUT /v1/container/:id/state
//安装app
v1AppGroup.POST("/install", v1.InstallApp)
//卸载app
v1AppGroup.DELETE("/uninstall/:id", v1.UnInstallApp)
//获取进度
v1AppGroup.GET("/state/:id", v1.GetContainerState)
//更新容器配置
v1AppGroup.PUT("/update/:id/setting", v1.UpdateSetting)
//获取可能新数据
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
// @tiger - rely -> dependency - 依赖是什么意思?
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
// @tiger - 按照 RESTFul 规范,改成 GET /v1/container/:id/config
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
v1AppGroup.POST("/share", v1.ShareAppFile)
}
v1AppCategoriesGroup := v1Group.Group("/app-categories")
v1AppCategoriesGroup.Use()
{
v1AppCategoriesGroup.GET("/", v1.CategoryList)
}
v1SysGroup := v1Group.Group("/sys")
v1SysGroup.Use()
{
v1SysGroup.GET("/version/check", v1.GetSystemCheckVersion)
v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
v1SysGroup.GET("/version", v1.GetSystemCheckVersion) //version/check
v1SysGroup.POST("/update", v1.SystemUpdate)
v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) //hardware/info
v1SysGroup.GET("/wsssh", v1.WsSsh)
v1SysGroup.GET("/config", v1.GetSystemConfig)
//v1SysGroup.GET("/config", v1.GetSystemConfig) //delete
//v1SysGroup.POST("/config", v1.PostSetSystemConfig)
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) //error/logs
//v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete
//v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete
v1SysGroup.POST("/stop", v1.PostKillCasaOS)
v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
v1SysGroup.PUT("/usb/:status", v1.PutSystemUSBAutoMount)
v1SysGroup.GET("/usb/status", v1.GetSystemUSBAutoMount)
v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
v1SysGroup.GET("/network", v1.GetSystemNetInfo)
v1SysGroup.PUT("/usb-auto-mount", v1.PutSystemUSBAutoMount) ///sys/usb/:status
v1SysGroup.GET("/usb-auto-mount", v1.GetSystemUSBAutoMount) ///sys/usb/status
v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
}
v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use()
{
v1PortGroup.GET("/", v1.GetPort) //app/port
v1PortGroup.GET("/state/:port", v1.PortCheck) //app/check/:port
}
v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use()
{
v1FileGroup.PUT("/rename", v1.RenamePath)
v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.GET("/", v1.GetDownloadSingleFile) //download/:path
v1FileGroup.POST("/", v1.PostCreateFile)
v1FileGroup.PUT("/", v1.PutFileContent)
v1FileGroup.PUT("/name", v1.RenamePath) //file/rename
v1FileGroup.GET("/content", v1.GetFilerContent) //file/read
//File uploads need to be handled separately, and will not be modified here
v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/upload", v1.GetFileUpload)
v1FileGroup.GET("/dirpath", v1.DirPath)
//create folder
v1FileGroup.POST("/mkdir", v1.MkdirAll)
v1FileGroup.POST("/create", v1.PostCreateFile)
v1FileGroup.GET("/download", v1.GetDownloadFile)
v1FileGroup.GET("/download/*path", v1.GetDownloadSingleFile)
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
v1FileGroup.DELETE("/delete", v1.DeleteFile)
v1FileGroup.PUT("/update", v1.PutFileContent)
v1FileGroup.GET("/image", v1.GetFileImage)
v1FileGroup.DELETE("/operate/:id", v1.DeleteOperateFileOrDir)
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
}
v1FolderGroup := v1Group.Group("/folder")
v1FolderGroup.Use()
{
v1FolderGroup.GET("/", v1.DirPath) ///file/dirpath
v1FolderGroup.POST("/", v1.MkdirAll) ///file/mkdir
}
v1BatchGroup := v1Group.Group("/batch")
v1BatchGroup.Use()
{
v1BatchGroup.DELETE("/", v1.DeleteFile) //file/delete
v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) //file/operate
v1BatchGroup.GET("/", v1.GetDownloadFile)
}
v1ImageGroup := v1Group.Group("/image")
v1ImageGroup.Use()
{
v1ImageGroup.GET("/", v1.GetFileImage)
}
v1DiskGroup := v1Group.Group("/disk")
v1DiskGroup.Use()
{
v1DiskGroup.GET("/check", v1.GetDiskCheck)
//v1DiskGroup.GET("/check", v1.GetDiskCheck) //delete
v1DiskGroup.GET("/", v1.GetDiskInfo)
v1DiskGroup.GET("/list", v1.GetDiskList)
v1DiskGroup.POST("/", v1.PostMountDisk)
//获取磁盘详情
v1DiskGroup.GET("/info", v1.GetDiskInfo)
// //format storage
// v1DiskGroup.POST("/format", v1.PostDiskFormat)
//format storage
v1DiskGroup.POST("/format", v1.PostDiskFormat)
// //mount SATA disk
// v1DiskGroup.POST("/mount", v1.PostMountDisk)
// add storage
v1DiskGroup.POST("/storage", v1.PostDiskAddPartition)
// //umount sata disk
// v1DiskGroup.POST("/umount", v1.PostDiskUmount)
//mount SATA disk
v1DiskGroup.POST("/mount", v1.PostMountDisk)
//umount sata disk
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
//获取可以格式化的内容
v1DiskGroup.GET("/type", v1.FormatDiskType)
//删除分区
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
v1DiskGroup.GET("/usb", v1.GetUSBList)
//v1DiskGroup.GET("/type", v1.FormatDiskType)//delete
v1DiskGroup.DELETE("/part", v1.RemovePartition) //disk/delpart
}
v1StorageGroup := v1Group.Group("/storage")
v1StorageGroup.Use()
{
v1StorageGroup.POST("/", v1.PostDiskAddPartition)
//v1StorageGroup.GET("/", v1.GetStorageList)
}
v1DisksGroup := v1Group.Group("/disks")
v1DisksGroup.Use()
{
//v1UsbGroup.GET("/", v1.GetUSBList)
v1DisksGroup.GET("/", v1.GetDiskList)
}
v1Group.GET("/sync/config", v1.GetSyncConfig)
}
return r

View File

@ -118,8 +118,8 @@ func MyAppList(c *gin.Context) {
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
data := make(map[string]interface{}, 2)
data["list"] = list // @tiger - list 不清楚是什么意思,可以提高一下描述性
data["local"] = unTranslation // @tiger - local 不清楚是什么意思,可以提高一下描述性
data["casaos-apps"] = list
data["local-apps"] = unTranslation
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
@ -132,7 +132,6 @@ func MyAppList(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /app/usage [get]
func AppUsageList(c *gin.Context) {
// @tiger - 关于出参的问题,见 GetHardwareUsageSteam - 另外 steam 是不是应该为 stream?
list := service.MyService.App().GetHardwareUsage()
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}

View File

@ -9,8 +9,8 @@ import (
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
@ -28,7 +28,38 @@ var diskMap = make(map[string]string)
// @Success 200 {string} string "ok"
// @Router /disk/list [get]
func GetDiskList(c *gin.Context) {
js := make(map[string]string)
c.BindJSON(&js)
t := js["type"]
list := service.MyService.Disk().LSBLK(false)
if t == "usb" {
data := []model.DriveUSB{}
for _, v := range list {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
data = append(data, temp)
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
return
}
dbList := service.MyService.Disk().GetSerialAll()
part := make(map[string]int64, len(dbList))
for _, v := range dbList {
@ -191,49 +222,6 @@ func GetDiskInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
}
// @Summary format storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "e.g. /dev/sda1"
// @Param pwd formData string true "user password"
// @Param volume formData string true "mount point"
// @Success 200 {string} string "ok"
// @Router /disk/format [post]
func PostDiskFormat(c *gin.Context) {
path := c.PostForm("path")
t := "ext4"
pwd := c.PostForm("pwd")
volume := c.PostForm("volume")
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if len(path) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
diskMap[path] = "busying"
service.MyService.Disk().UmountPointAndRemoveDir(path)
format := service.MyService.Disk().FormatDisk(path, t)
if len(format) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
delete(diskMap, path)
return
}
service.MyService.Disk().MountDisk(path, volume)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 获取支持的格式
// @Produce application/json
// @Accept application/json
@ -256,7 +244,9 @@ func FormatDiskType(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /disk/delpart [delete]
func RemovePartition(c *gin.Context) {
path := c.PostForm("path")
js := make(map[string]string)
c.BindJSON(&js)
path := js["path"]
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
@ -280,9 +270,11 @@ func RemovePartition(c *gin.Context) {
// @Router /disk/storage [post]
func PostDiskAddPartition(c *gin.Context) {
name := c.PostForm("name")
path := c.PostForm("path")
format, _ := strconv.ParseBool(c.PostForm("format"))
js := make(map[string]string)
c.BindJSON(&js)
path := js["path"]
name := js["name"]
format, _ := strconv.ParseBool(js["format"])
if len(name) == 0 || len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
@ -348,38 +340,96 @@ func PostDiskAddPartition(c *gin.Context) {
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "for example: /dev/sda1"
// @Param path body string true "for example: /dev/sda1"
// @Param action body string true "mount,umount,format"
// @Param serial formData string true "disk id"
// @Success 200 {string} string "ok"
// @Router /disk/mount [post]
func PostMountDisk(c *gin.Context) {
// for example: path=/dev/sda1
path := c.PostForm("path")
serial := c.PostForm("serial")
id := c.GetHeader("user_id")
js := make(map[string]string)
c.BindJSON(&js)
mountPath := "/DATA/volume"
var list = service.MyService.Disk().GetSerialAll()
var pathMapList = make(map[string]string, len(list))
for _, v := range list {
pathMapList[v.MountPoint] = "1"
}
for i := 0; i < len(list)+1; i++ {
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
mountPath = mountPath + strconv.Itoa(i)
break
path := js["path"]
serial := js["serial"]
action := js["action"]
t := "ext4"
password := js["password"]
volume := js["volume"]
user := service.MyService.User().GetUserAllInfoById(id)
// volume := js["volume"]
if action == "mount" {
mountPath := "/DATA/volume"
var list = service.MyService.Disk().GetSerialAll()
var pathMapList = make(map[string]string, len(list))
for _, v := range list {
pathMapList[v.MountPoint] = "1"
}
for i := 0; i < len(list)+1; i++ {
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
mountPath = mountPath + strconv.Itoa(i)
break
}
}
//mount dir
service.MyService.Disk().MountDisk(path, mountPath)
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path
m.UUID = serial
m.State = 0
service.MyService.Disk().SaveMountPoint(m)
} else if action == "umount" {
if len(path) == 0 || len(volume) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if encryption.GetMD5ByStr(password) != user.Password {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
service.MyService.Disk().UmountPointAndRemoveDir(path)
//delete data
service.MyService.Disk().DeleteMountPoint(path, volume)
service.MyService.Disk().RemoveLSBLKCache()
} else if action == "format" {
if encryption.GetMD5ByStr(password) != user.Password {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if len(path) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
diskMap[path] = "busying"
service.MyService.Disk().UmountPointAndRemoveDir(path)
format := service.MyService.Disk().FormatDisk(path, t)
if len(format) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
delete(diskMap, path)
return
}
service.MyService.Disk().MountDisk(path, volume)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
}
//mount dir
service.MyService.Disk().MountDisk(path, mountPath)
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path
m.UUID = serial
m.State = 0
//service.MyService.Disk().SaveMountPoint(m)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
@ -395,28 +445,6 @@ func PostMountDisk(c *gin.Context) {
// @Router /disk/umount [post]
func PostDiskUmount(c *gin.Context) {
path := c.PostForm("path")
mountPoint := c.PostForm("volume")
pwd := c.PostForm("pwd")
if len(path) == 0 || len(mountPoint) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
service.MyService.Disk().UmountPointAndRemoveDir(path)
//delete data
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
service.MyService.Disk().RemoveLSBLKCache()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
@ -462,38 +490,3 @@ func GetDiskCheck(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary check mount point
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/usb [get]
func GetUSBList(c *gin.Context) {
list := service.MyService.Disk().LSBLK(false)
data := []model.DriveUSB{}
for _, v := range list {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
data = append(data, temp)
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}

View File

@ -159,7 +159,7 @@ func InstallApp(c *gin.Context) {
m.Protocol = "http"
}
m.Label = strings.Replace(m.Name, " ", "_", -1)
if m.Origin != "custom" {
if m.Origin != CUSTOM {
oldName := m.Label
for i := 0; true; i++ {
if i != 0 {
@ -227,7 +227,7 @@ func InstallApp(c *gin.Context) {
}
}
}
if m.Origin == "custom" {
if m.Origin == CUSTOM {
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: common_err.DEVICE_NOT_EXIST, Message: device.Path + "," + common_err.GetMsg(common_err.DEVICE_NOT_EXIST)})
@ -268,7 +268,7 @@ func InstallApp(c *gin.Context) {
// installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
// installLog.Id = uuid.NewV4().String()
// service.MyService.Notify().AddLog(installLog)
if m.Origin != "custom" {
if m.Origin != CUSTOM {
for _, plugin := range appInfo.Plugins {
if plugin == "mysql" {
mid := uuid.NewV4().String()
@ -708,16 +708,23 @@ func UnInstallApp(c *gin.Context) {
// @Router /app/state/{id} [put]
func ChangAppState(c *gin.Context) {
appId := c.Param("id")
state := c.DefaultPostForm("state", "stop") // @tiger - 应该用 JSON 形式
js := make(map[string]string)
c.BindJSON(&js)
state := js["state"]
if len(appId) == 0 || len(state) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
var err error
if state == "stop" {
err = service.MyService.Docker().DockerContainerStop(appId)
} else if state == "start" {
if state == "start" {
err = service.MyService.Docker().DockerContainerStart(appId)
} else if state == "restart" {
service.MyService.Docker().DockerContainerStop(appId)
err = service.MyService.Docker().DockerContainerStart(appId)
} else {
err = service.MyService.Docker().DockerContainerStop(appId)
}
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
@ -1031,8 +1038,8 @@ func ContainerInfo(c *gin.Context) {
Status string `json:"status"`
StartedAt string `json:"started_at"`
CPUShares int64 `json:"cpu_shares"`
Memory int64 `json:"memory"` // @tiger - 改成 total_memory方便以后增加 free_memory 之类的字段
Restart string `json:"restart"` // @tiger - 改成 restart_policy?
Memory int64 `json:"total_memory"` // @tiger - 改成 total_memory方便以后增加 free_memory 之类的字段
Restart string `json:"restart_policy"` // @tiger - 改成 restart_policy?
}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
data := make(map[string]interface{}, 5)
data["app"] = appInfo // @tiget - 最佳实践是,返回 appid然后具体的 app 信息由前端另行获取
@ -1043,25 +1050,15 @@ func ContainerInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary 获取安装所需要的数据
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/config [get]
func GetDockerInstallConfig(c *gin.Context) {
func GetDockerNetworks(c *gin.Context) {
networks := service.MyService.Docker().DockerNetworkModelList()
data := make(map[string]interface{}, 2)
list := []map[string]string{}
for _, network := range networks {
if network.Driver != "null" {
list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
}
}
data["networks"] = list
data["memory"] = service.MyService.System().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary 获取依赖数据
@ -1078,7 +1075,6 @@ func ContainerRelyInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: appInfo})
}
// @Summary 获取可更新数据
// @Produce application/json
// @Accept application/json
// @Tags app

View File

@ -1,9 +1,6 @@
package v1
import (
"bufio"
"encoding/csv"
"fmt"
"io"
"io/ioutil"
"log"
@ -26,32 +23,6 @@ import (
uuid "github.com/satori/go.uuid"
)
func downloadReadFile(c *gin.Context) {
//http下载地址 csv
csvFileUrl := c.PostForm("file_name")
res, err := http.Get(csvFileUrl)
if err != nil {
c.String(400, err.Error())
return
}
defer res.Body.Close()
//读取csv
reader := csv.NewReader(bufio.NewReader(res.Body))
for {
line, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
c.String(400, err.Error())
return
}
//line 就是每一行的内容
fmt.Println(line)
//line[0] 就是第几列
fmt.Println(line[0])
}
}
// @Summary 读取文件
// @Produce application/json
// @Accept application/json
@ -312,8 +283,8 @@ func DirPath(c *gin.Context) {
func RenamePath(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
op := json["oldpath"]
np := json["newpath"]
op := json["old_path"]
np := json["new_path"]
if len(op) == 0 || len(np) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return

17
route/v1/storage.go Normal file
View File

@ -0,0 +1,17 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-11 16:02:29
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-11 16:02:55
* @FilePath: /CasaOS/route/v1/storage.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package v1
import "github.com/gin-gonic/gin"
func GetStorageList(c *gin.Context) {
}

View File

@ -21,7 +21,6 @@ import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
)
@ -66,11 +65,6 @@ func SystemUpdate(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
//Get system config
func GetSystemConfig(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: ""})
}
// @Summary get logs
// @Produce application/json
// @Accept application/json
@ -217,33 +211,6 @@ func PutCasaOSPort(c *gin.Context) {
})
}
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/init/check [get]
func GetSystemInitCheck(c *gin.Context) {
data := make(map[string]interface{}, 2)
if service.MyService.User().GetUserCount() > 0 {
data["initialized"] = true
data["key"] = ""
} else {
key := uuid.NewV4().String()
service.UserRegisterHash[key] = key
data["key"] = key
data["initialized"] = false
}
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}
// @Summary active killing casaos
// @Produce application/json
// @Accept application/json
@ -263,7 +230,7 @@ func PostKillCasaOS(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /sys/usb/off [put]
func PutSystemUSBAutoMount(c *gin.Context) {
status := c.Param("status")
status := c.Param("state")
if status == "on" {
service.MyService.System().UpdateUSBAutoMount("True")
service.MyService.System().ExecUSBAutoMountShell("True")
@ -540,26 +507,3 @@ func GetSystemNetInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
}
//********************************************* Soon to be removed ***********************************************
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /guide/check [get]
func GetGuideCheck(c *gin.Context) {
initUser := true
if service.MyService.User().GetUserCount() > 0 {
initUser = false
}
data := make(map[string]interface{}, 1)
data["need_init_user"] = initUser
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}

View File

@ -20,6 +20,7 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
uuid "github.com/satori/go.uuid"
"github.com/tidwall/gjson"
"github.com/IceWhaleTech/CasaOS/service"
@ -32,11 +33,9 @@ func PostUserRegister(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
// @tiger - user_name 改成 username
username := json["user_name"]
username := json["username"]
pwd := json["password"]
key := c.Param("key")
key := json["key"]
if _, ok := service.UserRegisterHash[key]; !ok {
c.JSON(http.StatusOK,
model.Result{Success: common_err.KEY_NOT_EXIST, Message: common_err.GetMsg(common_err.KEY_NOT_EXIST)})
@ -61,7 +60,7 @@ func PostUserRegister(c *gin.Context) {
}
user := model2.UserDBModel{}
user.UserName = username
user.Username = username
user.Password = encryption.GetMD5ByStr(config.UserInfo.PWD)
user.Role = "admin"
@ -90,10 +89,9 @@ func PostUserLogin(c *gin.Context) {
username := json["username"]
// @tiger - 字段命名要一直,在注册的时候如果用 password这里也要用 password
pwd := json["pwd"]
password := json["password"]
//check params is empty
if len(username) == 0 || len(pwd) == 0 {
if len(username) == 0 || len(password) == 0 {
c.JSON(http.StatusOK,
model.Result{
Success: common_err.ERROR,
@ -107,20 +105,20 @@ func PostUserLogin(c *gin.Context) {
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if user.Password != encryption.GetMD5ByStr(pwd) {
if user.Password != encryption.GetMD5ByStr(password) {
c.JSON(http.StatusOK,
model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
token := system_model.VerifyInformation{}
token.AccessToken = jwt.GetAccessToken(user.UserName, user.Password, user.Id)
token.RefreshToken = jwt.GetRefreshToken(user.UserName, user.Password, user.Id)
token.AccessToken = jwt.GetAccessToken(user.Username, user.Password, user.Id)
token.RefreshToken = jwt.GetRefreshToken(user.Username, user.Password, user.Id)
token.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
data := make(map[string]interface{}, 2)
user.Password = ""
data["token"] = token
// @tiger - 不建议直接透传数据库对象,而是适配到用于 API 输出的 model 对象
// TODO:1 Database fields cannot be external
data["user"] = user
c.JSON(http.StatusOK,
@ -169,24 +167,6 @@ func PutUserAvatar(c *gin.Context) {
})
}
/**
* @description: get user avatar by user id
* @param {query} id string user id
* @method: GET
*/
func GetUserAvatar(c *gin.Context) {
id := c.Param("id")
user := service.MyService.User().GetUserInfoById(id)
path := "default.png"
if user.Id > 0 {
path = user.Avatar
}
// @tiger - RESTful 规范下不应该返回文件本身内容而是返回文件的静态URL由前端去解析
c.File(path)
}
// @Summary edit user name
// @Produce application/json
// @Accept application/json
@ -195,25 +175,42 @@ func GetUserAvatar(c *gin.Context) {
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/name/:id [put]
func PutUserName(c *gin.Context) {
func PutUserInfo(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
json := model2.UserDBModel{}
c.BindJSON(&json)
userName := json["user_name"]
if len(userName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.UserName = userName
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
if len(json.Username) > 0 {
u := service.MyService.User().GetUserInfoByUserName(json.Username)
if u.Id > 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_EXIST, Message: common_err.GetMsg(common_err.USER_EXIST)})
return
}
}
if len(json.Password) > 0 {
user.Password = encryption.GetMD5ByStr(json.Password)
service.MyService.User().UpdateUserPassword(user)
}
if len(json.Avatar) == 0 {
json.Avatar = user.Avatar
}
if len(json.Role) == 0 {
json.Role = user.Role
}
if len(json.Description) == 0 {
json.Description = user.Description
}
if len(user.Nickname) == 0 {
json.Nickname = user.Nickname
}
service.MyService.User().UpdateUser(json)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json})
}
// @Summary edit user password
@ -263,8 +260,8 @@ func PutUserNick(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
nickName := json["nick_name"]
if len(nickName) == 0 {
Nickname := json["nick_name"]
if len(Nickname) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
@ -274,7 +271,7 @@ func PutUserNick(c *gin.Context) {
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.NickName = nickName
user.Nickname = Nickname
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
@ -319,44 +316,29 @@ func GetUserInfo(c *gin.Context) {
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
//*****
// @tiger - 应该和 PostUserLogin 中的 user 对象一致。而不是重构一系列字段。
var u = make(map[string]string, 5)
u["user_name"] = user.UserName // 改成 username
u["head"] = user.Avatar // 应该和 /v1/user/avatar/:id 一致,改成 avatar
u["email"] = user.Email
u["description"] = user.NickName
u["nick_name"] = user.NickName // 改成 nickname
u["id"] = strconv.Itoa(user.Id) // (nice-to-have) 最佳实践是用随机字符来代表 ID。顺序数字有可预测性
//**
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: u,
Data: user,
})
}
// @Summary get user info
// @Produce application/json
// @Accept application/json
// @Tags user
// @Success 200 {string} string "ok"
// @Router /user/info [get]
func GetUserInfoByUserName(c *gin.Context) {
json := make(map[string]string)
// @tiger 当前这个设计的问题是GET 不应该同时接收 request body。
// GET 方法应该只接收 URL 参数
c.BindJSON(&json)
userName := json["user_name"]
if len(userName) == 0 {
/**
* @description:
* @param {*gin.Context} c
* @param {string} Username
* @return {*}
* @method:
* @router:
*/
func GetUserInfoByUsername(c *gin.Context) {
Username := c.Param("Username")
if len(Username) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoByUserName(userName)
user := service.MyService.User().GetUserInfoByUserName(Username)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
@ -372,15 +354,15 @@ func GetUserInfoByUserName(c *gin.Context) {
}
/**
* @description: get all usernames
* @description: get all Usernames
* @method:GET
* @router:/user/all/name
*/
func GetUserAllUserName(c *gin.Context) {
func GetUserAllUsername(c *gin.Context) {
users := service.MyService.User().GetAllUserName()
names := []string{}
for _, v := range users {
names = append(names, v.UserName)
names = append(names, v.Username)
}
c.JSON(http.StatusOK,
model.Result{
@ -405,7 +387,7 @@ func GetUserCustomConf(c *gin.Context) {
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
// user := service.MyService.User().GetUserInfoByUserName(userName)
// user := service.MyService.User().GetUserInfoByUsername(Username)
if user.Id == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
@ -533,16 +515,20 @@ func PostUserFileImage(c *gin.Context) {
}
/**
* @description:create or update user's custom image
* @param {formData} file file "a file to be uploaded"
* @param {path} key string "file name"
* @method:POST
* @router:/user/upload/image/:key
* @description:
* @param {*gin.Context} c
* @param {file} file
* @param {string} key
* @param {string} type:avatar,background
* @return {*}
* @method:
* @router:
*/
func PostUserUploadImage(c *gin.Context) {
id := c.GetHeader("user_id")
f, err := c.FormFile("file")
key := c.Param("key")
t := c.PostForm("type")
if len(key) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
@ -565,6 +551,9 @@ func PostUserUploadImage(c *gin.Context) {
return
}
path := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + key + ext
if t == "avatar" {
path = config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/avatar" + ext
}
c.SaveUploadedFile(f, path)
data := make(map[string]string, 3)
data["path"] = path
@ -626,30 +615,68 @@ func DeleteUserImage(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
////refresh token
// func PostUserRefreshToken(c *gin.Context) {
// json := make(map[string]string)
// c.BindJSON(&json)
// refresh := json["refresh_token"]
// claims, err := jwt.ParseToken(refresh)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE), Data: err.Error()})
// return
// }
// if claims.VerifyExpiresAt(time.Now(), true) || claims.VerifyIssuer("refresh", true) {
// c.JSON(http.StatusOK, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE)})
// return
// }
// newToken := jwt.GetAccessToken(claims.UserName, claims.PassWord, claims.Id)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
// return
// }
// verifyInfo := system_model.VerifyInformation{}
// verifyInfo.AccessToken = newToken
// verifyInfo.RefreshToken = jwt.GetRefreshToken(claims.UserName, claims.PassWord, claims.Id)
// verifyInfo.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
/**
* @description:
* @param {*gin.Context} c
* @param {string} refresh_token
* @return {*}
* @method:
* @router:
*/
func PostUserRefreshToken(c *gin.Context) {
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: verifyInfo})
refresh := c.Query("refresh_token")
claims, err := jwt.ParseToken(refresh)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE), Data: err.Error()})
return
}
if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("refresh", true) {
c.JSON(http.StatusOK, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE)})
return
}
newToken := jwt.GetAccessToken(claims.Username, claims.PassWord, claims.Id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
verifyInfo := system_model.VerifyInformation{}
verifyInfo.AccessToken = newToken
verifyInfo.RefreshToken = jwt.GetRefreshToken(claims.Username, claims.PassWord, claims.Id)
verifyInfo.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
// }
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: verifyInfo})
}
func DeleteUserAll(c *gin.Context) {
service.MyService.User().DeleteAllUser()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/init/check [get]
func GetUserStatus(c *gin.Context) {
data := make(map[string]interface{}, 2)
if service.MyService.User().GetUserCount() > 0 {
data["initialized"] = true
data["key"] = ""
} else {
key := uuid.NewV4().String()
service.UserRegisterHash[key] = key
data["key"] = key
data["initialized"] = false
}
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}

View File

@ -36,7 +36,7 @@ type AppService interface {
GetSimpleContainerInfo(name string) (types.Container, error)
DelAppConfigDir(path string)
GetSystemAppList() []types.Container
GetHardwareUsageSteam()
GetHardwareUsageStream()
GetHardwareUsage() []model.DockerStatsModel
GetAppStats(id string) string
GetAllDBApps() []model2.AppListDBModel
@ -363,12 +363,12 @@ func (a *appStruct) GetAppStats(id string) string {
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
steam := true
stream := true
for !isFinish {
if steam {
steam = false
if stream {
stream = false
go func() {
a.GetHardwareUsageSteam()
a.GetHardwareUsageStream()
}()
}
runtime.Gosched()
@ -383,7 +383,7 @@ func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
}
func (a *appStruct) GetHardwareUsageSteam() {
func (a *appStruct) GetHardwareUsageStream() {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {

View File

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-23 15:43:07
* @LastEditTime: 2022-07-11 17:57:00
* @FilePath: /CasaOS/service/model/o_user.go
* @Description:
* @Website: https://www.casaos.io
@ -15,11 +15,11 @@ import "time"
//Soon to be removed
type UserDBModel struct {
Id int `gorm:"column:id;primary_key" json:"id"`
UserName string `json:"user_name"` // @tiger - user_name 改 username
Username string `json:"username"`
Password string `json:"password,omitempty"`
Role string `json:"role"`
Email string `json:"email"`
NickName string `json:"nick_name"` // @tiger - nick_name 改 nickname
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Description string `json:"description"`
CreatedAt time.Time `gorm:"<-:create;autoCreateTime" json:"created_at,omitempty"`
@ -27,5 +27,5 @@ type UserDBModel struct {
}
func (p *UserDBModel) TableName() string {
return "o_user"
return "o_users"
}

View File

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-03-18 11:40:55
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-23 19:45:49
* @LastEditTime: 2022-07-11 18:36:43
* @FilePath: /CasaOS/service/user.go
* @Description:
* @Website: https://www.casaos.io
@ -15,13 +15,11 @@ import (
"mime/multipart"
"os"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type UserService interface {
SetUser(username, pwd, token, email, desc, nickName string) error
UpLoadFile(file multipart.File, name string) error
CreateUser(m model.UserDBModel) model.UserDBModel
GetUserCount() (userCount int64)
@ -31,6 +29,7 @@ type UserService interface {
GetUserAllInfoById(id string) (m model.UserDBModel)
GetUserAllInfoByName(userName string) (m model.UserDBModel)
DeleteUserById(id string)
DeleteAllUser()
GetUserInfoByUserName(userName string) (m model.UserDBModel)
GetAllUserName() (list []model.UserDBModel)
}
@ -41,12 +40,15 @@ type userService struct {
db *gorm.DB
}
func (u *userService) DeleteAllUser() {
u.db.Where("1=1").Delete(&model.UserDBModel{})
}
func (u *userService) DeleteUserById(id string) {
u.db.Where("id= ?", id).Delete(&model.UserDBModel{})
}
func (u *userService) GetAllUserName() (list []model.UserDBModel) {
u.db.Select("user_name").Find(&list)
u.db.Select("username").Find(&list)
return
}
func (u *userService) CreateUser(m model.UserDBModel) model.UserDBModel {
@ -70,47 +72,19 @@ func (u *userService) GetUserAllInfoById(id string) (m model.UserDBModel) {
return
}
func (u *userService) GetUserAllInfoByName(userName string) (m model.UserDBModel) {
u.db.Where("user_name= ?", userName).First(&m)
u.db.Where("username= ?", userName).First(&m)
return
}
func (u *userService) GetUserInfoById(id string) (m model.UserDBModel) {
u.db.Select("user_name", "id", "role", "nick_name", "description", "avatar").Where("id= ?", id).First(&m)
u.db.Select("username", "id", "role", "nickname", "description", "avatar").Where("id= ?", id).First(&m)
return
}
func (u *userService) GetUserInfoByUserName(userName string) (m model.UserDBModel) {
u.db.Select("user_name", "id", "role", "nick_name", "description", "avatar").Where("user_name= ?", userName).First(&m)
u.db.Select("username", "id", "role", "nickname", "description", "avatar").Where("username= ?", userName).First(&m)
return
}
//设置用户名密码
func (u *userService) SetUser(username, pwd, token, email, desc, nickName string) error {
if len(username) > 0 {
config.Cfg.Section("user").Key("UserName").SetValue(username)
config.UserInfo.UserName = username
config.Cfg.Section("user").Key("Initialized").SetValue("true")
config.UserInfo.Initialized = true
}
if len(pwd) > 0 {
config.Cfg.Section("user").Key("PWD").SetValue(pwd)
config.UserInfo.PWD = pwd
}
if len(email) > 0 {
config.Cfg.Section("user").Key("Email").SetValue(email)
config.UserInfo.Email = email
}
if len(desc) > 0 {
config.Cfg.Section("user").Key("Description").SetValue(desc)
config.UserInfo.Description = desc
}
if len(nickName) > 0 {
config.Cfg.Section("user").Key("NickName").SetValue(nickName)
config.UserInfo.NickName = nickName
}
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
return nil
}
//上传文件
func (c *userService) UpLoadFile(file multipart.File, url string) error {
out, _ := os.OpenFile(url, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)