feat: 网站增加设置目录运行用户和用户组的功能 (#694)

This commit is contained in:
zhengkunwang223 2023-04-18 18:46:58 +08:00 committed by GitHub
parent 2dbc7f28fd
commit d660b7d315
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 24 deletions

View File

@ -626,3 +626,25 @@ func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Update Site Dir permission
// @Description 更新网站目录权限
// @Accept json
// @Param request body request.WebsiteUpdateDirPermission true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir/permission [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
var req request.WebsiteUpdateDirPermission
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateSitePermission(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}

View File

@ -150,3 +150,9 @@ type WebsiteUpdateDir struct {
ID uint `json:"id" validate:"required"`
SiteDir string `json:"siteDir" validate:"required"`
}
type WebsiteUpdateDirPermission struct {
ID uint `json:"id" validate:"required"`
User string `json:"user" validate:"required"`
Group string `json:"group" validate:"required"`
}

View File

@ -26,6 +26,9 @@ type Website struct {
RuntimeID uint `gorm:"type:integer" json:"runtimeID"`
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
User string `gorm:"type:varchar;" json:"user"`
Group string `gorm:"type:varchar;" json:"group"`
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
}

View File

@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
"gorm.io/gorm"
"os"
@ -62,6 +63,7 @@ type IWebsiteService interface {
GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error)
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
UpdateSiteDir(req request.WebsiteUpdateDir) error
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
}
func NewIWebsiteService() IWebsiteService {
@ -1075,3 +1077,25 @@ func (w WebsiteService) UpdateSiteDir(req request.WebsiteUpdateDir) error {
website.SiteDir = runDir
return websiteRepo.Save(context.Background(), &website)
}
func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermission) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.PrimaryDomain, "index")
if website.SiteDir != "/" {
absoluteIndexPath = path.Join(absoluteIndexPath, website.SiteDir)
}
chownCmd := fmt.Sprintf("chown -R %s:%s %s", req.User, req.Group, absoluteIndexPath)
if _, err := cmd.ExecWithTimeOut(chownCmd, 1*time.Second); err != nil {
return err
}
website.User = req.User
website.Group = req.Group
return websiteRepo.Save(context.Background(), &website)
}

View File

@ -276,7 +276,7 @@ var UpdateTableHost = &gormigrate.Migration{
}
var UpdateTableWebsite = &gormigrate.Migration{
ID: "20230417-update-table-website",
ID: "20230418-update-table-website",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Website{}); err != nil {
return err

View File

@ -50,5 +50,6 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
groupRouter.POST("/rewrite/update", baseApi.UpdateRewriteConfig)
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
}
}

View File

@ -18,6 +18,8 @@ export namespace Website {
webSiteSSL: SSL;
runtimeID: number;
rewrite: string;
user: string;
group: string;
}
export interface WebsiteDTO extends Website {
@ -299,4 +301,10 @@ export namespace Website {
id: number;
siteDir: string;
}
export interface DirPermissionUpdate {
id: number;
user: string;
group: string;
}
}

View File

@ -182,3 +182,7 @@ export const UpdateRewriteConfig = (req: Website.RewriteUpdate) => {
export const UpdateWebsiteDir = (req: Website.DirUpdate) => {
return http.post<any>(`/websites/dir/update`, req);
};
export const UpdateWebsiteDirPermission = (req: Website.DirPermissionUpdate) => {
return http.post<any>(`/websites/dir/permission`, req);
};

View File

@ -428,6 +428,9 @@ const message = {
remoteConn: 'External connection address',
remoteConnHelper2: 'Use this address for non-container or external connections',
localIP: 'Local IP',
userGroup: 'User/Group',
user: 'User',
uGroup: 'Group',
},
container: {
createContainer: 'Create container',

View File

@ -1172,7 +1172,10 @@ const message = {
runDir: '运行目录',
runDirHelper: '部分程序需要指定二级目录作为运行目录如ThinkPHP5Laravel',
runUserHelper:
'通过 PHP 运行环境部署的网站需要将 index 和子目录下的所有文件文件夹所有者和用户组设置为 1000命令chown -R 1000:1000 index',
'通过 PHP 运行环境部署的网站需要将 index 和子目录下的所有文件文件夹所有者和用户组设置为 1000',
userGroup: '运行用户/',
user: '用户',
uGroup: '用户组',
},
php: {
short_open_tag: '短标签支持',

View File

@ -15,7 +15,7 @@
</el-button>
</el-space>
</el-form-item>
<el-form-item v-if="configDir" :label="$t('website.runDir')" prop="runDir">
<el-form-item v-if="configDir" :label="$t('website.runDir')">
<el-space wrap>
<el-select v-model="update.siteDir">
<el-option :label="'/'" :value="'/'"></el-option>
@ -31,26 +31,26 @@
</el-button>
</el-space>
</el-form-item>
<el-form-item label="运行用户/组" prop="runDir">
<el-form-item :label="$t('website.userGroup')">
<el-space wrap>
<el-input v-model="update.siteDir" class="user-num-input">
<template #prepend>用户</template>
<el-input v-model="updatePermission.user" class="user-num-input">
<template #prepend>{{ $t('website.user') }}</template>
</el-input>
<el-input v-model="update.siteDir" class="user-num-input">
<template #prepend>用户组</template>
<el-input v-model="updatePermission.group" class="user-num-input">
<template #prepend>{{ $t('website.uGroup') }}</template>
</el-input>
<el-button type="primary" @click="submit(siteForm)">保存</el-button>
<el-button type="primary" @click="submitPermission()">
{{ $t('commons.button.save') }}
</el-button>
</el-space>
</el-form-item>
</el-form>
<el-form-item>
<el-alert :closable="false">
<template #default>
<span class="warnHelper">{{ $t('website.runDirHelper') }}</span>
</template>
</el-alert>
</el-form-item>
<el-alert :closable="false">
<template #default>
<span class="warnHelper">{{ $t('website.runDirHelper') }}</span>
<span class="warnHelper">{{ $t('website.runUserHelper') }}</span>
</template>
</el-alert>
<br />
<el-descriptions :title="$t('website.folderTitle')" :column="1" border>
<el-descriptions-item label="waf">{{ $t('website.wafFolder') }}</el-descriptions-item>
@ -58,18 +58,12 @@
<el-descriptions-item label="log">{{ $t('website.logFoler') }}</el-descriptions-item>
<el-descriptions-item label="index">{{ $t('website.indexFolder') }}</el-descriptions-item>
</el-descriptions>
<br />
<el-alert :closable="false">
<template #default>
<span class="warnHelper">{{ $t('website.runUserHelper') }}</span>
</template>
</el-alert>
</div>
</div>
</template>
<script lang="ts" setup>
import { GetFilesList } from '@/api/modules/files';
import { GetWebsite, UpdateWebsiteDir } from '@/api/modules/website';
import { GetWebsite, UpdateWebsiteDir, UpdateWebsiteDirPermission } from '@/api/modules/website';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
@ -93,6 +87,11 @@ const update = reactive({
id: 0,
siteDir: '/',
});
const updatePermission = reactive({
id: 0,
user: '1000',
group: '1000',
});
const siteForm = ref<FormInstance>();
const dirReq = reactive({
path: '/',
@ -113,6 +112,9 @@ const search = () => {
website.value = res.data;
update.id = website.value.id;
update.siteDir = website.value.siteDir;
updatePermission.id = website.value.id;
updatePermission.group = website.value.group === '' ? '1000' : website.value.group;
updatePermission.user = website.value.user === '' ? '1000' : website.value.user;
if (website.value.type === 'static' || website.value.runtimeID > 0) {
configDir.value = true;
dirReq.path = website.value.sitePath + '/index';
@ -142,6 +144,21 @@ const submit = async (formEl: FormInstance | undefined) => {
});
};
const submitPermission = async () => {
if (updatePermission.user === '' || updatePermission.group === '') {
return;
}
loading.value = true;
UpdateWebsiteDirPermission(updatePermission)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
search();
})
.finally(() => {
loading.value = false;
});
};
const getDirs = async () => {
loading.value = true;
await GetFilesList(dirReq)