Compare commits

..

2 Commits

  1. 7
      01.web/.gitignore
  2. 26
      01.web/src/views/advance/index.vue
  3. 26
      01.web/src/views/index/index.vue
  4. 2
      01.web/src/views/login/index.vue
  5. 99
      01.web/src/views/repositoryGroup/index.vue
  6. 732
      01.web/src/views/repositoryInfo/index.vue
  7. 100
      01.web/src/views/repositoryUser/index.vue
  8. 2
      01.web/webpack.dev.config.js
  9. 2
      02.php/app/service/Svngroup.php
  10. 2
      02.php/app/service/Svnuser.php
  11. 2
      02.php/app/util/SVNAdmin/Core.php
  12. 2
      02.php/config/version.php
  13. 13
      02.php/server/svnadmind.php
  14. 536
      README.md

7
01.web/.gitignore vendored

@ -1,7 +0,0 @@
.idea
.idea/
.DS_Store
node_modules/
.project
src/config/*.tmp
src/config/env.js

26
01.web/src/views/advance/index.vue

@ -12,13 +12,13 @@
</Col> </Col>
<Col span="1"> </Col> <Col span="1"> </Col>
<Col span="6"> <Col span="6">
<Tooltip <!-- <Tooltip
:transfer="true" :transfer="true"
max-width="360" max-width="360"
content="可在命令行模式下执行 server/insta.php 进行Subversion安装和初始化等操作" content="可在命令行模式下执行 server/insta.php 进行Subversion安装和初始化等操作"
> >
<Button type="info">tips</Button> <Button type="info">tips</Button>
</Tooltip> </Tooltip> -->
</Col> </Col>
<Col span="6"> </Col> <Col span="6"> </Col>
</Row> </Row>
@ -41,7 +41,7 @@
</Col> </Col>
<Col span="1"> </Col> <Col span="1"> </Col>
<Col span="6"> <Col span="6">
<Button <!-- <Button
:loading="loadingSvnserveStart" :loading="loadingSvnserveStart"
type="success" type="success"
v-if="formSvn.installed == 1" v-if="formSvn.installed == 1"
@ -54,7 +54,7 @@
v-if="formSvn.installed == 2" v-if="formSvn.installed == 2"
@click="Stop" @click="Stop"
>停止</Button >停止</Button
> > -->
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
@ -62,6 +62,7 @@
<Row> <Row>
<Col span="12"> <Col span="12">
<InputNumber <InputNumber
disabled
:min="1" :min="1"
v-model="tempBindPort" v-model="tempBindPort"
@on-change="ChangeEditPort" @on-change="ChangeEditPort"
@ -69,13 +70,13 @@
</Col> </Col>
<Col span="1"> </Col> <Col span="1"> </Col>
<Col span="6"> <Col span="6">
<Button <!-- <Button
type="warning" type="warning"
@click="EditPort" @click="EditPort"
:disabled="disabledEditPort" :disabled="disabledEditPort"
:loading="loadingEditPort" :loading="loadingEditPort"
>修改</Button >修改</Button
> > -->
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
@ -83,6 +84,7 @@
<Row> <Row>
<Col span="12"> <Col span="12">
<Input <Input
disabled
v-model="tempBindHost" v-model="tempBindHost"
@on-change="ChangeEditHost" @on-change="ChangeEditHost"
placeholder="默认地址:0.0.0.0" placeholder="默认地址:0.0.0.0"
@ -90,7 +92,7 @@
</Col> </Col>
<Col span="1"> </Col> <Col span="1"> </Col>
<Col span="6"> <Col span="6">
<Tooltip <!-- <Tooltip
:transfer="true" :transfer="true"
max-width="350" max-width="350"
content="请注意,如果您的机器为公网服务器且非弹性IP,则可能会绑定失败。原因与云服务器厂商分配公网IP给服务器的方式有关。如果绑定失败,建议配置使用自定义主机名代替检出地址。" content="请注意,如果您的机器为公网服务器且非弹性IP,则可能会绑定失败。原因与云服务器厂商分配公网IP给服务器的方式有关。如果绑定失败,建议配置使用自定义主机名代替检出地址。"
@ -102,7 +104,7 @@
:loading="loadingEditHost" :loading="loadingEditHost"
>修改</Button >修改</Button
> >
</Tooltip> </Tooltip> -->
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
@ -134,7 +136,7 @@
v-model="formSvn.enable" v-model="formSvn.enable"
@on-change="EditEnable" @on-change="EditEnable"
> >
<Radio label="bindHost">绑定主机</Radio> <Radio label="bindHost" disabled>绑定主机</Radio>
<Radio label="manageHost">自定义主机</Radio> <Radio label="manageHost">自定义主机</Radio>
</RadioGroup> </RadioGroup>
</Col> </Col>
@ -146,9 +148,9 @@
</TabPane> </TabPane>
<TabPane label="配置文件" name="2"> <TabPane label="配置文件" name="2">
<Card :bordered="false" :dis-hover="true" style="width: 620px"> <Card :bordered="false" :dis-hover="true" style="width: 620px">
<Alert <!-- <Alert
>可在命令行模式下执行 server/insta.php 进行目录更换操作 >可在命令行模式下执行 server/insta.php 进行目录更换操作
</Alert> </Alert> -->
<Form :label-width="160" label-position="left"> <Form :label-width="160" label-position="left">
<FormItem <FormItem
:label="item.key" :label="item.key"
@ -597,7 +599,7 @@ export default {
* 版本信息 * 版本信息
*/ */
version: { version: {
current_verson: "2.3.4", current_verson: "2.3.3",
php_version: "5.5 <= PHP < 8.0", php_version: "5.5 <= PHP < 8.0",
database: "MYSQL、SQLite", database: "MYSQL、SQLite",
github: "https://github.com/witersen/SvnAdminV2.0", github: "https://github.com/witersen/SvnAdminV2.0",

26
01.web/src/views/index/index.vue

@ -1,31 +1,9 @@
<template> <template>
<div> <div>
<Card <Card :bordered="false" :dis-hover="true" style="margin-bottom: 10px" v-if="display.part1">
:bordered="false"
:dis-hover="true"
style="margin-bottom: 10px"
v-if="display.part1"
>
<p slot="title"> <p slot="title">
<Icon type="md-bulb" /> <Icon type="md-bulb" />
<Tooltip {{ systemBrif.os }}
max-width="500"
placement="bottom"
:transfer="true"
:content="systemBrif.os"
>
<span
style="
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 450px;
display: inline-block;
"
>
{{ systemBrif.os }}
</span>
</Tooltip>
</p> </p>
<div> <div>
<Row> <Row>

2
01.web/src/views/login/index.vue

@ -5,7 +5,7 @@
<template> <template>
<div class="login"> <div class="login">
<div class="login-con"> <div class="login-con">
<Card icon="log-in" title="SVNAdmin V2.3.4" :bordered="false"> <Card icon="log-in" title="SVNAdmin V2.3.3" :bordered="false">
<div class="form-con"> <div class="form-con">
<Form <Form
ref="formUserLogin" ref="formUserLogin"

99
01.web/src/views/repositoryGroup/index.vue

@ -83,9 +83,6 @@
>分组名只能包含字母数字破折号下划线</Alert >分组名只能包含字母数字破折号下划线</Alert
> >
</FormItem> </FormItem>
<FormItem label="备注">
<Input v-model="formCreateGroup.svn_group_note"></Input>
</FormItem>
<FormItem> <FormItem>
<Button <Button
type="primary" type="primary"
@ -260,7 +257,6 @@ export default {
// //
formCreateGroup: { formCreateGroup: {
svn_group_name: "", svn_group_name: "",
svn_group_note: "",
}, },
// //
formEditGroupName: { formEditGroupName: {
@ -449,7 +445,6 @@ export default {
that.loadingCreateGroup = true; that.loadingCreateGroup = true;
var data = { var data = {
svn_group_name: that.formCreateGroup.svn_group_name, svn_group_name: that.formCreateGroup.svn_group_name,
svn_group_note: that.formCreateGroup.svn_group_note,
}; };
that.$axios that.$axios
.post("/api.php?c=Svngroup&a=CreateGroup&t=web", data) .post("/api.php?c=Svngroup&a=CreateGroup&t=web", data)
@ -515,98 +510,8 @@ export default {
DelGroup(svn_group_name) { DelGroup(svn_group_name) {
var that = this; var that = this;
that.$Modal.confirm({ that.$Modal.confirm({
render: (h) => { title: "删除SVN分组 - " + svn_group_name,
return h("div", [ content: "确定要删除该用户吗?<br/>该操作不可逆!",
h(
"div",
{
class: { "modal-title": true },
style: {
display: "flex",
height: "42px",
alignItems: "center",
},
},
[
h("Icon", {
props: {
type: "ios-help-circle",
},
style: {
width: "28px",
height: "28px",
fontSize: "28px",
color: "#f90",
},
}),
h(
"tooltip",
{
props: {
transfer: true,
placement: "bottom",
"max-width": "400",
},
},
[
h("span", {
style: {
marginLeft: "12px",
fontSize: "16px",
color: "#17233d",
fontWeight: 500,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
width: "285px",
display: "inline-block",
},
domProps: {
innerHTML: "删除SVN分组 - " + svn_group_name,
},
}),
h(
"div",
{
slot: "content",
style: {
fontSize: "10px",
},
},
[
h(
"p",
{
style: {
fontSize: "15px",
},
},
"删除SVN分组 - " + svn_group_name
),
]
),
]
),
]
),
h(
"div",
{
class: { "modal-content": true },
style: { paddingLeft: "40px" },
},
[
h("p", {
style: { marginBottom: "15px" },
domProps: {
innerHTML:
"确定要删除该分组吗?<br/>将会从所有仓库和分组下将该分组移除!<br/>该操作不可逆!",
},
}),
]
),
]);
},
onOk: () => { onOk: () => {
var data = { var data = {
svn_group_name: svn_group_name, svn_group_name: svn_group_name,

732
01.web/src/views/repositoryInfo/index.vue

@ -187,7 +187,7 @@
<!-- 对话框-仓库浏览 --> <!-- 对话框-仓库浏览 -->
<Modal v-model="modalViewRep" fullscreen :title="titleModalViewRep"> <Modal v-model="modalViewRep" fullscreen :title="titleModalViewRep">
<Row style="margin-bottom: 15px"> <Row style="margin-bottom: 15px">
<Col span="15"> <Col span="16">
<Breadcrumb> <Breadcrumb>
<BreadcrumbItem <BreadcrumbItem
v-for="(item, index) in breadRepPath.name" v-for="(item, index) in breadRepPath.name"
@ -197,20 +197,12 @@
> >
</Breadcrumb> </Breadcrumb>
</Col> </Col>
<Col span="1"> </Col>
<Col span="8"> <Col span="8">
<Tooltip <Input readonly v-model="tempCheckout">
style="width: 100%" <Button slot="append" icon="md-copy" @click="CopyCheckout"
max-width="450" >复制</Button
:content="tempCheckout" >
placement="bottom" </Input>
>
<Input readonly v-model="tempCheckout">
<Button slot="append" icon="md-copy" @click="CopyCheckout"
>复制</Button
>
</Input>
</Tooltip>
</Col> </Col>
</Row> </Row>
<Card :bordered="true" :dis-hover="true"> <Card :bordered="true" :dis-hover="true">
@ -296,12 +288,7 @@
</Scroll> </Scroll>
</Col> </Col>
<Col span="11"> <Col span="11">
<Card <Card :bordered="true" :dis-hover="true" style="height: 550px">
:bordered="true"
v-if="false"
:dis-hover="true"
style="height: 550px"
>
<Tabs type="card"> <Tabs type="card">
<TabPane label="用户"> <TabPane label="用户">
<Form :label-width="60"> <Form :label-width="60">
@ -391,88 +378,6 @@
</TabPane> </TabPane>
</Tabs> </Tabs>
</Card> </Card>
<Tooltip
style="width: 100%"
max-width="450"
:content="currentRepTreePriPath"
placement="bottom"
>
<Input v-model="currentRepTreePriPath">
<span slot="prepend">当前路径:</span>
</Input>
</Tooltip>
<Card
:bordered="true"
:dis-hover="true"
style="height: 500px; margin-top: 18px"
>
<Button icon="md-add" type="primary" ghost @click="ModalRepPathPri"
>路径授权</Button
>
<Table
border
:height="410"
size="small"
:columns="tableColumnRepPathPriInfo"
:data="tableDataRepPathPriInfo"
style="margin-top: 20px"
>
<template slot-scope="{ row }" slot="type">
<Tag
color="blue"
v-if="row.type == 1"
style="width: 65px; text-align: center"
>SVN用户</Tag
>
<Tag
color="geekblue"
v-if="row.type == 2"
style="width: 65px; text-align: center"
>SVN分组</Tag
>
<Tag
color="purple"
v-if="row.type == 3"
style="width: 65px; text-align: center"
>SVN别名</Tag
>
<Tag
color="red"
v-if="row.type == 4"
style="width: 65px; text-align: center"
>所有人</Tag
>
<Tag
color="magenta"
v-if="row.type == 5"
style="width: 65px; text-align: center"
>已授权</Tag
>
<Tag
color="volcano"
v-if="row.type == 6"
style="width: 65px; text-align: center"
>未授权</Tag
>
</template>
<template slot-scope="{ row }" slot="pri">
<RadioGroup type="button" size="small" button-style="solid">
<Radio label="rw">读写</Radio>
<Radio label="r">只读</Radio>
<Radio label="none">禁止</Radio>
</RadioGroup>
</template>
<template slot-scope="{ row }" slot="invert">
<Switch v-if="row.type == 1 || row.type == 2 || row.type == 3">
<Icon type="md-checkmark" slot="open"></Icon>
<Icon type="md-close" slot="close"></Icon>
</Switch>
</template>
<template slot-scope="{ row }" slot="action">
<Button type="error" size="small">删除</Button>
</template>
</Table>
</Card>
</Col> </Col>
</Row> </Row>
<div slot="footer"> <div slot="footer">
@ -1017,148 +922,6 @@
<Button type="primary" ghost @click="modalSetUUID = false">取消</Button> <Button type="primary" ghost @click="modalSetUUID = false">取消</Button>
</div> </div>
</Modal> </Modal>
<!-- 路径授权弹出框 -->
<Modal v-model="modalRepPathPri" :draggable="true" title="路径授权对象">
<Tabs size="small" class="custom-tabs-svn">
<TabPane :label="custom_tab_svn_user">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search placeholder="通过用户名搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAllUsers"
:data="tableDataAllUsers"
style="margin-bottom: 10px"
>
<template slot-scope="{ row }" slot="disabled">
<Tag color="blue" v-if="row.disabled == 0">正常</Tag>
<Tag color="red" v-else>禁用</Tag>
</template>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
<TabPane :label="custom_tab_svn_group">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search placeholder="通过分组名搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAllGroups"
:data="tableDataAllGroups"
style="margin-bottom: 10px"
>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
<TabPane :label="custom_tab_svn_aliase">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search placeholder="通过别名搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAllAliases"
:data="tableDataAllAliases"
style="margin-bottom: 10px"
>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
<TabPane :label="custom_tab_svn_all">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search disabled placeholder="通过符号搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAll"
:data="tableDataAll"
style="margin-bottom: 10px"
>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
<TabPane :label="custom_tab_svn_authenticated">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search disabled placeholder="通过符号搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAuthenticated"
:data="tableDataAuthenticated"
style="margin-bottom: 10px"
>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
<TabPane :label="custom_tab_svn_anonymous">
<Row style="margin-bottom: 15px">
<Col type="flex" justify="space-between" span="12"> </Col>
<Col span="12">
<Input search disabled placeholder="通过符号搜索..." />
</Col>
</Row>
<Table
highlight-row
border
:height="250"
size="small"
:columns="tableColumnAnonymous"
:data="tableDataAnonymous"
style="margin-bottom: 10px"
>
<template slot-scope="{ row, index }" slot="action">
<Tag color="primary">选择</Tag>
</template>
</Table>
</TabPane>
</Tabs>
<Alert show-icon>授权的对象权限默认为读写</Alert>
<Alert show-icon>为已授权的对象重复授权权限将会被覆盖为读写</Alert>
<div slot="footer">
<Button type="primary" ghost @click="modalRepPathPri = false"
>取消</Button
>
</div>
</Modal>
</div> </div>
</template> </template>
@ -1166,84 +929,6 @@
export default { export default {
data() { data() {
return { return {
custom_tab_svn_user: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#1890ff",
},
},
"SVN用户"
),
]);
},
custom_tab_svn_group: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#2f54eb",
},
},
"SVN分组"
),
]);
},
custom_tab_svn_aliase: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#722ed1",
},
},
"SVN别名"
),
]);
},
custom_tab_svn_all: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#f5222d",
},
},
"所有人"
),
]);
},
custom_tab_svn_authenticated: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#eb2f96",
},
},
"已授权"
),
]);
},
custom_tab_svn_anonymous: (h) => {
return h("div", [
h(
"span",
{
style: {
color: "#fa541c",
},
},
"未授权"
),
]);
},
/** /**
* 权限相关 * 权限相关
*/ */
@ -1282,8 +967,6 @@ export default {
modalRecommendHook: false, modalRecommendHook: false,
//UUID //UUID
modalSetUUID: false, modalSetUUID: false,
//
modalRepPathPri: false,
/** /**
* 排序数据 * 排序数据
@ -1685,298 +1368,6 @@ export default {
}, },
], ],
tableDataRepPathGroupPri: [], tableDataRepPathGroupPri: [],
//
tableDataRepPathPriInfo: [
{
type: 1,
name: "user1",
pri: "rw",
},
{
type: 2,
name: "group1",
pri: "rw",
action: "-",
},
{
type: 3,
name: "aliase1",
pri: "rw",
},
{
type: 4,
name: "*",
pri: "rw",
},
{
type: 5,
name: "$authenticated",
pri: "rw",
},
{
type: 6,
name: "$anonymous",
pri: "rw",
},
{
type: 1,
name: "user1",
pri: "rw",
},
{
type: 2,
name: "group1",
pri: "rw",
action: "-",
},
{
type: 3,
name: "aliase1",
pri: "rw",
},
{
type: 4,
name: "*",
pri: "rw",
},
{
type: 5,
name: "$authenticated",
pri: "rw",
},
{
type: 6,
name: "$anonymous",
pri: "rw",
},
],
tableColumnRepPathPriInfo: [
{
title: "授权类型",
slot: "type",
},
{
title: "对象名称",
key: "name",
tooltip: true,
width: 115,
},
{
title: "读写权限",
slot: "pri",
width: 200,
},
{
slot: "invert",
width: 100,
renderHeader(h, params) {
return h(
"tooltip",
{
props: {
transfer: true,
placement: "left",
"max-width": "400",
},
},
[
h("span", [
h("span", "权限反转"),
h("Icon", {
props: {
type: "ios-help-circle-outline",
size: "15",
},
class: { iconClass: true },
}),
]),
h(
"div",
{
slot: "content",
style: {
fontSize: "10px",
},
},
[
h(
"p",
{
style: {
color: "#479af1",
fontSize: "15px",
},
},
"不熟练的用户请慎用此功能!"
),
h("p", " "),
h("p", "从 Subversion 1.5 开始"),
h("p", "$authenticated 表示所有已认证的用户"),
h("p", "$anonymous 表示所有未认证的用户"),
h(
"p",
"~ 即权限反转表示排除某些用户 如在用户名、别名、用户组、认证类别前加上 ~ 表示将访问权限授予给与规则不匹配的用户"
),
h("p", " "),
h("p", "如:"),
h("p", "[calendar:/projects/calendar]"),
h("p", "$anonymous = r"),
h("p", "$authenticated = rw"),
h("p", " "),
h(
"p",
"虽然下面的配置容易让人产生困惑,,但它和上面的例子是等效的:"
),
h("p", " "),
h("p", "[calendar:/projects/calendar]"),
h("p", "~$authenticated = r"),
h("p", "~$anonymous = rw"),
h("p", " "),
h("p", "下面是一个更恰当的使用 ~ 的例子:"),
h("p", " "),
h("p", "[groups]"),
h("p", "# calc 项目的开发人员信息"),
h("p", "calc-developers = &harry, &sally, &joe"),
h("p", " "),
h("p", "# calc 项目的管理人员信息"),
h("p", "calc-owners = &hewlett, &packard"),
h("p", " "),
h("p", "# calc 项目的所有参与人信息"),
h("p", "calc = @calc-developers, @calc-owners"),
h("p", " "),
h("p", "# 所有的 calc 项目参与成员有该项目的读权限"),
h("p", "[calc:/projects/calc]"),
h("p", "@calc = rw"),
h("p", " "),
h("p", "# 只有项目管理员有 calc 项目的发行版标签操作权限"),
h("p", "[calc:/projects/calc/tags]"),
h("p", "~@calc-owners = r"),
]
),
]
);
},
},
{
title: "操作",
slot: "action",
},
],
//-SVN
tableColumnAllUsers: [
{
title: "用户名",
key: "userName",
tooltip: true,
},
{
title: "用户状态",
slot: "disabled",
},
{
title: "操作",
slot: "action",
width: 90,
},
],
tableDataAllUsers: [
{
userName: "xxxxxxx",
disabled: 1,
},
{
userName: "xx",
disabled: 0,
},
],
//-SVN
tableColumnAllGroups: [
{
title: "分组名",
key: "groupName",
tooltip: true,
},
{
title: "操作",
slot: "action",
},
],
tableDataAllGroups: [
{
groupName: "xxx",
},
{
groupName: "xxx",
},
],
//-SVN
tableColumnAllAliases: [
{
title: "别名",
key: "aliaseName",
tooltip: true,
},
{
title: "操作",
slot: "action",
},
],
tableDataAllAliases: [
{
aliaseName: "xxx",
},
{
aliaseName: "xxxx",
},
],
//-
tableColumnAll: [
{
title: "所有人",
key: "all",
},
{
title: "操作",
slot: "action",
},
],
tableDataAll: [
{
all: "*",
},
],
//-
tableColumnAuthenticated: [
{
title: "已授权",
key: "authenticated",
},
{
title: "操作",
slot: "action",
},
],
tableDataAuthenticated: [
{
authenticated: "$authenticated",
},
],
//-
tableColumnAnonymous: [
{
title: "未授权",
key: "anonymous",
},
{
title: "操作",
slot: "action",
},
],
tableDataAnonymous: [
{
anonymous: "$anonymous",
},
],
// uuid // uuid
tableColumnRepDetail: [ tableColumnRepDetail: [
{ {
@ -1985,7 +1376,6 @@ export default {
tooltip: true, tooltip: true,
fixed: "left", fixed: "left",
width: 170, width: 170,
// width:80
}, },
{ {
title: "信息", title: "信息",
@ -3440,101 +2830,9 @@ export default {
DelRep(rep_name) { DelRep(rep_name) {
var that = this; var that = this;
that.$Modal.confirm({ that.$Modal.confirm({
// title: " - " + rep_name, title: "删除仓库 - " + rep_name,
// content: content:
// "<br/><br/>", "确定要删除该仓库吗?<br/>该操作不可逆!<br/>如果该仓库有正在进行的网络传输,可能会删除失败,请注意提示信息!",
render: (h) => {
return h("div", [
h(
"div",
{
class: { "modal-title": true },
style: {
display: "flex",
height: "42px",
alignItems: "center",
},
},
[
h("Icon", {
props: {
type: "ios-help-circle",
},
style: {
width: "28px",
height: "28px",
fontSize: "28px",
color: "#f90",
},
}),
h(
"tooltip",
{
props: {
transfer: true,
placement: "bottom",
"max-width": "400",
},
},
[
h("span", {
style: {
marginLeft: "12px",
fontSize: "16px",
color: "#17233d",
fontWeight: 500,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
width: "285px",
display: "inline-block",
},
domProps: {
innerHTML: "删除仓库 - " + rep_name,
},
}),
h(
"div",
{
slot: "content",
style: {
fontSize: "10px",
},
},
[
h(
"p",
{
style: {
fontSize: "15px",
},
},
"删除仓库 - " + rep_name
),
]
),
]
),
]
),
h(
"div",
{
class: { "modal-content": true },
style: { paddingLeft: "40px" },
},
[
h("p", {
style: { marginBottom: "15px" },
domProps: {
innerHTML:
"确定要删除该仓库吗?<br/>该操作不可逆!<br/>如果该仓库有正在进行的网络传输,可能会删除失败,请注意提示信息!",
},
}),
]
),
]);
},
onOk: () => { onOk: () => {
var data = { var data = {
rep_name: rep_name, rep_name: rep_name,
@ -3557,13 +2855,6 @@ export default {
}, },
}); });
}, },
/**
* 显示路径授权对话框
*/
ModalRepPathPri() {
this.modalRepPathPri = true;
},
}, },
}; };
</script> </script>
@ -3574,9 +2865,6 @@ export default {
// padding: 0px 16px 0px 16px; // padding: 0px 16px 0px 16px;
// } // }
// } // }
// .custom-tabs-svn > .ivu-tabs-bar > .ivu-tabs-nav-container > .ivu-tabs-nav-wrap > .ivu-tabs-nav-scroll > .ivu-tabs-nav > .ivu-tabs-tab-active{
// background-color: red;
// }
.my-modal { .my-modal {
// //
.ivu-card-body { .ivu-card-body {

100
01.web/src/views/repositoryUser/index.vue

@ -106,9 +106,6 @@
v-model="formCreateUser.svn_user_pass" v-model="formCreateUser.svn_user_pass"
></Input> ></Input>
</FormItem> </FormItem>
<FormItem label="备注">
<Input v-model="formCreateUser.svn_user_note"></Input>
</FormItem>
<FormItem> <FormItem>
<Button <Button
type="primary" type="primary"
@ -233,7 +230,6 @@ export default {
formCreateUser: { formCreateUser: {
svn_user_name: "", svn_user_name: "",
svn_user_pass: "", svn_user_pass: "",
svn_user_note: "",
}, },
// //
formEditUser: { formEditUser: {
@ -455,7 +451,6 @@ export default {
var data = { var data = {
svn_user_name: that.formCreateUser.svn_user_name, svn_user_name: that.formCreateUser.svn_user_name,
svn_user_pass: that.formCreateUser.svn_user_pass, svn_user_pass: that.formCreateUser.svn_user_pass,
svn_user_note: that.formCreateUser.svn_user_note,
}; };
that.$axios that.$axios
.post("/api.php?c=Svnuser&a=CreateUser&t=web", data) .post("/api.php?c=Svnuser&a=CreateUser&t=web", data)
@ -554,98 +549,9 @@ export default {
DelUser(index, svn_user_name) { DelUser(index, svn_user_name) {
var that = this; var that = this;
that.$Modal.confirm({ that.$Modal.confirm({
render: (h) => { title: "删除SVN用户 - " + svn_user_name,
return h("div", [ content:
h( "确定要删除该用户吗?<br/>将会从所有仓库和分组下将该用户移除<br/>该操作不可逆!",
"div",
{
class: { "modal-title": true },
style: {
display: "flex",
height: "42px",
alignItems: "center",
},
},
[
h("Icon", {
props: {
type: "ios-help-circle",
},
style: {
width: "28px",
height: "28px",
fontSize: "28px",
color: "#f90",
},
}),
h(
"tooltip",
{
props: {
transfer: true,
placement: "bottom",
"max-width": "400",
},
},
[
h("span", {
style: {
marginLeft: "12px",
fontSize: "16px",
color: "#17233d",
fontWeight: 500,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
width: "285px",
display: "inline-block",
},
domProps: {
innerHTML: "删除SVN用户 - " + svn_user_name,
},
}),
h(
"div",
{
slot: "content",
style: {
fontSize: "10px",
},
},
[
h(
"p",
{
style: {
fontSize: "15px",
},
},
"删除SVN用户 - " + svn_user_name
),
]
),
]
),
]
),
h(
"div",
{
class: { "modal-content": true },
style: { paddingLeft: "40px" },
},
[
h("p", {
style: { marginBottom: "15px" },
domProps: {
innerHTML:
"确定要删除该用户吗?<br/>将会从所有仓库和分组下将该用户移除!<br/>该操作不可逆!",
},
}),
]
),
]);
},
onOk: () => { onOk: () => {
var data = { var data = {
svn_user_name: svn_user_name, svn_user_name: svn_user_name,

2
01.web/webpack.dev.config.js

@ -46,7 +46,7 @@ module.exports = merge(webpackBaseConfig, {
disableHostCheck: true, disableHostCheck: true,
proxy: { proxy: {
'/api.php': { '/api.php': {
target: 'http://dev.witersen.com:8009/api.php', target: 'http://dev.witersen.com/api.php',
changeOrigin: true, changeOrigin: true,
// pathRewrite: { '^/api': '' } // pathRewrite: { '^/api': '' }
} }

2
02.php/app/service/Svngroup.php

@ -190,7 +190,7 @@ class Svngroup extends Base
'svn_group_name' => $this->payload['svn_group_name'], 'svn_group_name' => $this->payload['svn_group_name'],
'include_user_count' => 0, 'include_user_count' => 0,
'include_group_count' => 0, 'include_group_count' => 0,
'svn_group_note' => $this->payload['svn_group_note'], 'svn_group_note' => ''
]); ]);
//日志 //日志

2
02.php/app/service/Svnuser.php

@ -253,7 +253,7 @@ class Svnuser extends Base
'svn_user_name' => $this->payload['svn_user_name'], 'svn_user_name' => $this->payload['svn_user_name'],
'svn_user_pass' => $this->payload['svn_user_pass'], 'svn_user_pass' => $this->payload['svn_user_pass'],
'svn_user_status' => 1, 'svn_user_status' => 1,
'svn_user_note' => $this->payload['svn_user_note'] 'svn_user_note' => ''
]); ]);
//日志 //日志

2
02.php/app/util/SVNAdmin/Core.php

@ -163,7 +163,7 @@ class Core
* 等 * 等
* *
* %s => $repName * %s => $repName
* %s => $repPaht str_replace('/', '\/', $repPath) * %s => $repPaht str_replace(['^', '$', '+', '*', '{', '}', '.', '(', ')', '[', ']', '%', '/'], ['\^', '\$', '\+', '\*', '\{', '\}', '\.', '\(', '\)', '\[', '\]', '\%', '\/'], $repPath)
* *
* @var string * @var string
*/ */

2
02.php/config/version.php

@ -12,5 +12,5 @@
* 用户请不要自行修改 以免影响后续升级检测 * 用户请不要自行修改 以免影响后续升级检测
*/ */
return [ return [
'version' => '2.3.4' 'version' => '2.3.3'
]; ];

13
02.php/server/svnadmind.php

@ -95,15 +95,10 @@ class Daemon
//接收客户端发送的数据 //接收客户端发送的数据
$receive = socket_read($client, $this->config_daemon['SOCKET_READ_LENGTH']); $receive = socket_read($client, $this->config_daemon['SOCKET_READ_LENGTH']);
$type = 'detect'; $receive = unserialize($receive);
$content = '';
if (!empty($receive)) { $type = $receive['type'];
$receive = unserialize($receive); $content = $receive['content'];
$type = $receive['type'];
$content = $receive['content'];
}
//console模式 //console模式
if ($this->workMode == 'console') { if ($this->workMode == 'console') {
@ -273,7 +268,7 @@ class Daemon
echo '检出SVN仓库前请注意放行协议端口(默认3690)' . PHP_EOL; echo '检出SVN仓库前请注意放行协议端口(默认3690)' . PHP_EOL;
echo '已自动更改系统加密密钥,在线用户会退出登录' . PHP_EOL; echo '已自动更改系统加密密钥,在线用户会退出登录' . PHP_EOL;
echo '建议将本程序通过nohup启动或加入系统管理' . PHP_EOL; echo '建议将本程序通过nohup启动或加入系统管理' . PHP_EOL;
chdir('/'); chdir('/');
umask(0); umask(0);
if (defined('STDIN')) { if (defined('STDIN')) {

536
README.md

@ -1,47 +1,61 @@
# SVNAdmin - 开源SVN管理系统 # SVNAdmin - 开源SVN管理系统
- 基于web的Subversion(SVN)服务器端管理工具,支持docker部署 - 该系统为使用PHP开发的基于web的Subversion(SVN)服务器端管理工具
- 支持功能:SVN仓库管理、SVN用户管理、SVN分组管理、目录授权、目录浏览、Hooks管理、在线dump备份、在线备份恢复、SVN用户禁用、服务器状态管理、日志管理、消息通知、更新检测... - 支持功能:SVN仓库管理、SVN用户管理、SVN分组管理、目录授权、目录浏览、Hooks管理、在线dump备份、在线备份恢复、SVN用户禁用、服务器状态管理、日志管理、消息通知、更新检测...
- 演示地址:http://svnadmin.witersen.com (默认的用户名与密码都为 admin) - 演示地址:http://svnadmin.witersen.com (默认的用户名与密码都为 admin)
- 项目地址: - 项目地址:
- GitHub地址:https://github.com/witersen/SvnAdminV2.0 - GitHub地址:https://github.com/witersen/SvnAdminV2.0
- Gitee地址:https://gitee.com/witersen/SvnAdminV2.0 - Gitee地址:https://gitee.com/witersen/SvnAdminV2.0
- 发行包:
- GitHub:https://github.com/witersen/SvnAdminV2.0/releases/download/v2.3.3/v2.3.3.zip
- Gitee:https://gitee.com/witersen/SvnAdminV2.0/releases/download/v2.3.3/v2.3.3.zip
- 兼容性
- 本程序提供 docker 镜像,基于 centos7.9.2009 构建 - 发行包:
- GitHub:https://github.com/witersen/SvnAdminV2.0/releases/download/v2.3.1/v2.3.1.zip
- Gitee:https://gitee.com/witersen/SvnAdminV2.0/attach_files/1099697/download/v2.3.1.zip
- 操作系统(手动安装):CentOS7(推荐)、CentOS8、Rocky、Ubuntu(Windows及其它Linux发行版正在测试兼容中) - 兼容性
- 操作系统:CentOS7(推荐)、CentOS8、Rocky、Ubuntu(Windows及其它Linux发行版正在测试兼容中)
- PHP版本:5.5 <= PHP < 8.0 - PHP版本:5.5 <= PHP < 8.0
- 数据库:SQLite、MySQL - 数据库:SQLite、MySQL
- Subversion:1.8+ - Subversion:1.8+
- 问题协助或功能建议加Q群:633108141
## 一、手动安装 - 有问题可先看本文档底部的常见问题解答,可以加群提建议或分享问题: QQ群 633108141
## 一、安装示例
### 1、在CentOS7.6操作系统裸机安装示例 ### 1、在CentOS7.6操作系统裸机安装示例
- 安装PHP和相关扩展 - 安装PHP和相关扩展
``` ```
# 解压缩和网络获取工具 #解压缩和网络获取工具
yum install -y zip unzip wget vim yum install -y zip unzip wget vim
# 由于CentOS7默认源中提供的PHP版本为5.4,而我们需要 5.5+,因此使用remi源 #由于CentOS7默认源中提供的PHP版本为5.4,因此我们使用remi源安装更高的php版本
# 可将 remi-php55 切换为想安装的版本 yum install -y epel-release
yum install -y epel-release yum-utils wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh https://mirrors.aliyun.com/remi/enterprise/remi-release-7.rpm rpm -Uvh remi-release-7.rpm
yum-config-manager --enable remi-php55
#编辑 /etc/yum.repos.d/remi.repo 文件,将想安装的PHP版本下方的enable由0改为1
# 安装php及相关扩展 vim /etc/yum.repos.d/remi.repo
yum install -y php php-common php-cli php-fpm php-json php-mysqlnd php-mysql php-pdo php-process php-json php-gd php-bcmath
#开始安装php及相关扩展
yum install -y php
yum install -y php-common
yum install -y php-cli
yum install -y php-fpm
yum install -y php-json
yum install -y php-mysqlnd
yum install -y php-process
yum install -y php-json
yum install -y php-gd
yum install -y php-bcmath
``` ```
- 安装web服务器 - 安装web服务器
``` ```
# 以apache为例 #以apache为例
yum install -y httpd yum install -y httpd
systemctl start httpd systemctl start httpd
systemctl enable httpd systemctl enable httpd
@ -50,25 +64,25 @@ systemctl enable httpd
- 安装本程序 - 安装本程序
``` ```
# 将代码包下载到 /var/www/html/ 目录并解压 #将代码包下载到 /var/www/html/ 目录并解压
cd /var/www/html/ cd /var/www/html/
# 代码包从发行版获取 #代码包从发行版获取
wget https://gitee.com/witersen/SvnAdminV2.0/releases/download/v2.3.3/v2.3.3.zip wget https://gitee.com/witersen/SvnAdminV2.0/attach_files/1099697/download/v2.3.1.zip
# 解压 #解压
unzip v2.3.3.zip unzip v2.3.1
``` ```
- 安装Subversion(如果你安装过Subversion,本步骤可以略过) - 安装Subversion(如果你安装过Subversion,本步骤可以略过)
``` ```
# 由于CentOS7.6默认源中的Subversion版本为1.7 因此我们需要通过安装脚本安装高版本(>=1.8) #由于CentOS7.6默认源中的Subversion版本为1.7 因此我们需要通过安装脚本安装高版本(>=1.8)
# 切换目录 #切换目录
cd /var/www/html/server/ cd /var/www/html/server/
# install.php文件可以帮助我们安装Subversion #install.php文件可以帮助我们安装Subversion
php install.php php install.php
``` ```
@ -82,324 +96,127 @@ cd /var/www/html/server
php install.php php install.php
``` ```
- 将本程序加入系统管理和开机自启(系统管理)(推荐)(与下方启动方式二选一即可) - 或者将本程序加入系统管理和开机自启(系统管理)(推荐)(与下方启动方式二选一即可)
- ```
#新建文件 svnserve.service
vim /usr/lib/systemd/system/svnadmind.service
```
- ```
#写入以下内容
#注意 /var/www/html/server/svnadmind.php 要改为自己实际的文件路径
#文件名称为 svnadmind 则表示我们新建的服务名称为 svnadmind
[Unit]
Description=SVNAdmin
After=syslog.target network.target
[Service]
Type=simple
ExecStart=/usr/bin/php /var/www/html/server/svnadmind.php start
[Install]
WantedBy=multi-user.target
```
- ```
#启动
systemctl daemon-reload
systemctl start svnadmind
#查看状态
systemctl status svnadmind
#加入开机自启动
systemctl enable svnadmind
#取消开机自启动
systemctl diable svnadmind
```
- 启动本程序的后台进程(手动管理)(与上方启动方式二选一即可)
- ```
#正式启动(后台模式)
nohup php svnadmind.php start >/dev/null 2>&1 &
#停止
php svnandmin.php stop
#调试模式
php svnadmin.php console
```
### 2、在安装宝塔面板的操作系统安装示例
- 安装方式跟手动部署类似,只是宝塔系统了很多可视化操作很方便
- 参考视频:[SVNAdmin V2.2.1 系统部署与使用演示视频【针对宝塔面板】]( https://www.bilibili.com/video/BV1XR4y1H7p3?share_source=copy_web&vd_source=f4620db503611c42618f1afd9c8afecd)
### 3、在ubutntu18安装示例
- 注意以root用户执行 server/install.php 和 server/svnadmind.php 即可
### 4、在Rocky安装示例
- 无注意事项
## 二、docker安装
- 拉取镜像
- ```
#拉取镜像
docker pull witersencom/svnadmin:2.3.3
```
- 仅运行查看效果(不挂载数据)
- ```
docker run -d \
--name svnadmintemp \
-p 80:80 \
-p 3690:3690 \
--privileged \
witersencom/svnadmin:2.3.3
```
- 用于生产环境(挂载数据到容器中,容器销毁数据不会丢失)
- 新用户
- ```
#启动一个临时容器,并将配置文件复制出来
docker run -d \
--name svnadmintemp \
--privileged=true \
witersencom/svnadmin:2.3.3 \
/usr/sbin/init
#复制的数据目录为 /home/svnadmin/
cd /home/
docker cp svnadmintemp:/home/svnadmin ./
#停止并删除临时容器
dockeer stop svnadmintemp && docker rm svnadmintemp
#启动正式容器
docker run -d \
-p 80:80 \
-p 3690:3690 \
-v /home/svnadmin/:/home/svnadmin/ \
--privileged \
witersencom/svnadmin:2.3.3
```
- 老用户(2.3.1+)
- ```
#假设数据存储主目录在宿主机的位置为 /home/svnadmin/ 则直接按照下面方式启动即可 会自动将宿主机数据挂载到容器中
docker run -d \
-p 80:80 \
-p 3690:3690 \
-v /home/svnadmin/:/home/svnadmin/ \
--privileged \
svnadmin:2.3.3
```
## 三、手动升级
### 3.1、docker用户
- docker版本只需要停止原来的镜像然后拉取新镜像即可
- 注意将数据存在宿主机
### 3.2、非docker用户
- 程序升级本质就是用新代码替换旧代码,然后用户的数据存储目录无需改变,流程如下:
- 停止后台 php server/svnadmind.php stop
- 下载新版本代码,替换旧版本代码
- 执行适配程序 php server/install.php
- 执行脚本并选择使用第2个选项,选择不覆盖原来的 autzh 、passwd、svnadmin.db 等文件
- 重新启动后台
- 如果用户之前自己修改了配置文件,则需要升级后重新修改配置文件
## 四、FAQ
### 1、如何将已有的SVN仓库使用此系统管理 ?
- (1)安装本系统
- (2)执行 php server/install.php 使用内置的功能重新配置你的Subversion
- (3)将已有的一个或多个SVN仓库移动到 /home/svnadmin/rep/ 目录下
- (4)刷新管理系统的仓库管理页面即可识别SVN仓库
- (5)注意此方式并不会识别SVN仓库原有的用户以及权限配置,因为我们使用了统一的配置文件来进行用户和权限管理,因此迁移仓库后还需要在管理系统重新添加用户、用户组、配置权限!
### 2、如何将数据库切换为MySQL ?
- 创建数据库
- 将系统提供的 mysql 数据库文件导入到你的MySQL数据库 ```
#新建文件 svnserve.service
- 修改 config/database.php 将sqlite部分注释并配置你的MySQL即可 vim /usr/lib/systemd/system/svnadmind.service
- 注意:若php版本过低而MySQL版本>=8.0,则会提示:The server requested authentication method unknown to the client,只需要升级php版本或者修改MySQL数据库的配置信息即可
### 3、为什么只支持管理Subversion1.8+ ?
- 预计在 2.5.x 版本向下适配,支持管理 Subversion 1.5+
### 4、为什么目前只支持Linux操作系统 ? #写入以下内容
#注意 /var/www/html/server/svnadmind.php 要改为自己实际的文件路径
#文件名称为 svnadmind 则表示我们新建的服务名称为 svnadmind
[Unit]
Description=SVNAdmin
After=syslog.target network.target
- 正在使用新方案对Windows操作系统进行支持测试 [Service]
- 预计在 2.4.x 版本支持 Windows 部署 Type=simple
ExecStart=/usr/bin/php /var/www/html/server/svnadmind.php start
### 5、仓库初始化结构模板 ? [Install]
WantedBy=multi-user.target
- 我们可以在创建仓库的时候选择创建指定内容结构的仓库,如包含 "trunk" "branches" "tags" 文件夹的结构,这一结构是可选的并且可调整的,我们可以手动调整 /home/svnadmin/templete/initStruct/01/ 下的目录结构 #启动
systemctl daemon-reload
systemctl start svnadmind
### 6、常用钩子推荐 ? #查看状态
systemctl status svnadmind
- 我们可以在目录 /home/svnadmin/hooks/ 下增加自己常用的钩子 #加入开机自启动
- /home/svnadmin/hooks/ 下建立文件夹 xx,名称任意 systemctl enable svnadmind
- 在 xx 下新建文件 hookDescription 写入对此钩子的描述文本内容
- 在 xx 下新建文件 hookName 写入钩子类型,如post-commit等
- 在 xx 下新建文件 ,以钩子类型命名,如 post-commit ,然后写入具体钩子内容
- 感谢 【北方糙汉子-】提供的钩子脚本
### 7、关于Subversion 权限配置中的魔力符号 #取消开机自启动
systemctl diable svnadmind
```
- Subversion从1.5开始支持用户使用一些魔力符号如 $authenticated 、$anonymous - 启动本程序的后台进程(手动管理)(与上方启动方式二选一即可)
- 预计在 2.3.4 版本支持 Subversion 的全部权限配置特性
### 8、关于与LDAP对接 ```
#正式启动(后台模式)
nohup php svnadmind.php start >/dev/null 2>&1 &
- 预计在 2.4 版本重新规划系统权限分配,并支持 LDAP 等认证方式 #停止
php svnandmin.php stop
### 9、如何找回密码 #调试模式
php svnadmin.php console
- 使用默认的SQLite数据库
``` ```
#使用sqlite数据库
yum install -y sqlite-devel ### 2、在安装宝塔面板的操作系统安装示例
cd /home/svnadmin - 创建站点
- 将PHP的命令行版本更换为要求的php版本
- 关闭站点的 open_basedir 防跨站攻击选项
- 将站点的PHP版本更换为要求的PHP版本
- 在软件商店对应版本的php中删除禁用的函数
- pcntl_signal
- pcntl_fork
- pcntl_wait
- shell_exec
- passthru
- 安装和启动
- 进入server目录
- php install.php 进行安装和配置Subversion
- php svnadmind.php start 启动后台程序
sqlite3 svnadmin.db ### 3、在ubutntu18安装示例
.header on - 注意以root用户执行 server/install.php 和 server/svnadmind.php 即可
.mode column ### 4、在Rocky安装示例
select * from admin_users; - 无注意事项 同1
```
- 使用MySQL数据库 ## 二、docker安装
- 使用可视化工具登录到数据库查看 admin_users 数据表信息即可
### 10、关于大文件下载中断问题 - docker在下个版本v2.3.2支持
- 当下载1G以及以上的大文件会出现下载被中断的问题,是因为文件下载为了安全没有使用http文件直链,而是通过php校验后读取文件流下载,所以会存在一个php-fpm最大执行时间的问题,因此你可以通过 设置 php-fpm.conf 配置文件的 request_terminate_timeout 为0 来取消超时限制 ## 三、手动升级
### 11、容器重启后无法正常访问web服务(svn不受影响) 手动配置升级,具体操作步骤如下:
``` ```
【原因】 #假设你的代码部署在 /var/www/html/ 目录下
重启容器后,容器内的 httpd 由于一些原因没有成功重启 cd /var/www/html/
1、构建的 docker 镜像是以 CentOS7.9.2009 为基础进行的
由于 CentOS7.9.2009 基础镜像的权限问题:https://github.com/docker-library/docs/tree/master/centos#dockerfile-for-systemd-base-image
导致如果启动容器时不增加 --privileged 参数 和不以 /usr/sbin/init 作为首先执行的指令,将会导致容器内一些程序无法正常启动
2、另外不排除重启后再次启动 httpd 时由于上次的 httpd.pid 文件依然造成的识别未 httpd 运行中的误判
【解决方案】
如果重启容器后 web 管理系统无法访问
只需要进入容器并执行下面的命令重新启动 httpd 服务即可
/usr/sbin/httpd
或者
/usr/sbin/httpd -DFOREGROUND &
后面会考虑更换更方便的解决方案
``` ```
- 停止守护进程
### 12、如果配置了多个仓库模板,如何在创建仓库时指定使用某个仓库模板?
``` ```
例如: #停止旧版本的守护进程
在 /home/svnadmin/templete/initStruct/01 下面配置第一个仓库结构模板 php server/svnadmind.php stop
在 /home/svnadmin/templete/initStruct/02 下面配置第二个仓库结构模板
如果在web中创建时,如何选用默认的 /home/svnadmin/templete/initStruct/02 下面的仓库结构模板?
【解决方案】
由于时间问题,开发时并没有对此功能做更多的详细开发,因此只预留了配置文件层面的修改途径,后续会将仓库模板功能加入到web配置,无需手动命令行管理
可以通过修改 config/svn.php 中的 templete_init_struct_01 值来修改
``` ```
- 备份
### 13、docker版本要修改容器内 svn 的 3690 默认端口
```
【解释】
既然使用 docker 版本,则无需考虑容器内应用的端口,因为可通过容器启动时候做端口映射
docker版本因为处于容器中权限问题禁用了一些按钮的操作权限,如修改svn服务的端口和绑定主机等信息
假如启动容器时,映射关系为 3691:3690 表示宿主机3691映射到容器的3690,因此在容器中修改3690为3692,会导致宿主机的3691无法提供服务
后面会改进 docker 版本,尽量令使用体验跟原生机器一致
【修改端口方案】
法1
直接在容器启动时即指定宿主机的映射端口,如 3692:3690 这样在容器中的管理系统查看还是3690,但是宿主机通过 3692 提供svn服务
法2(通过提供的dockefile自己重构docker镜像)
修改所有文件中的3690端口为想要的端口如3692
之后通过 docker build . -t svnadmin:xxx-edit 即可得到标签为 svnadmin:xxx-edit 的自定义构建镜像
这样的做法好处为管理系统查看到的端口为3692,启动docker时候映射端口的写法也可为 3692:3692
``` ```
mkdir -p /var/www/html2
### 14、如何创建其它的管理员账户 ? cp -r /var/www/html /var/www/html2
rm -rf /var/www/html/*
``` ```
由于目前的管理系统版本没有考虑到多用户权限管理的问题 ,此问题将在后续版本加入多用户权限管理解决 - 部署新版本代码
如果需要多个不同的管理员账号可以通过向管理员表 admin_users 手动插入数据
使用sqlite:数据库文件位置 /home/svnadmin/svnadmind.db,如果不熟悉sqlite的命令行插入,可以下载该文件到本地,使用 navicat 系列数据库管理软件打开修改,之后覆盖到服务器
使用mysql:进入命令行手动修改
``` ```
cd /var/www/html/
### 15、配置了自定义仓库模板但是创建仓库时没有生效 wget https://gitee.com/witersen/SvnAdminV2.0/attach_files/1099697/download/v2.3.1.zip
unzip v2.3.1.zip
``` ```
注意配置自定义仓库模板的位置 - 升级Subversion版本(1.8+)(>=1.8则无需升级)
通常的位置在 /home/svnadmin/templete/initStruct/01 下面
而不是在项目代码相关的位置
``` ```
#执行脚本并选择使用第1个选项
### 16、数据长度超过8192 请向上调整参数:SOCKET_READ_LENGTH php server/install.php
``` ```
【出现问题原因】 - 执行适配程序
svn的用户量和权限配置数量增加,超过了默认值
【解决方案】
修改 config/daemon.php 文件中的 SOCKET_READ_LENGTH 和 SOCKET_WRITE_LENGTH
设置到133693415 字节也就是大约小于128M貌似都是可以的,再大没有测试过
修改后别忘记要重启守护进程,重启守护进程的方式根据安装方式的不同而不同(不重启会出问题)
【适用版本】
2.1.0+
``` ```
#执行脚本并选择使用第2个选项,选择不覆盖原来的 autzh 、passwd、svnadmin.db 等文件
php server/install.php
### 17、登录时二维码总是提示输入错误 #如果之前在配置文件 config/database.php 切换了MySQL数据库,升级后需要重新配置下,这个问题会在下个版本修复
``` ```
【出现问题原因】 - 启动后台程序
首次登录数据信息默认使用sqlite数据库 ```
由于部署问题或其它问题造成数据库文件 /home/svnadmin/svnadmin.db 没有权限 启动方式见步骤一
【解决方案】
为sqlite数据库文件和文件所在目录授权777
chmod 777 /home/svnadmin/svnadmin.db
chmod 777 -R /home/svnadmin
如果是容器部署,需要在容器中执行此操作而不是在宿主机执行
``` ```
## 四、功能介绍
### 18、本程序的工作模式
- 通过使 svnadmind.php 成为守护进程并监听指定端口来工作
- php-fpm与php-cli程序的使用TCP套接字通信
![](./00.static/03.daemon/work.png)
## 五、功能介绍
- 登录界面可分角色登录,配合后端实现的登录验证码更安全(验证码可后台手动关闭开启) - 登录界面可分角色登录,配合后端实现的登录验证码更安全(验证码可后台手动关闭开启)
@ -516,3 +333,114 @@ chmod 777 -R /home/svnadmin
- SVN用户可自己修改密码 无需联系管理人员了 - SVN用户可自己修改密码 无需联系管理人员了
![](./00.static/01.demo/29.jpg) ![](./00.static/01.demo/29.jpg)
## 五、待办事项
### 1、计划增加功能
- [ ] 支持常见文件在线浏览
- [ ] 支持文件和文件夹在线下载
- [x] 支持重设仓库UUID
- [ ] 删除仓库需要输入管理人员密码
- [x] 支持修改应用根目录
- [ ] 支持authz、passwd文件的在线识别导入和导出
- [ ] docker部署
- [ ] 邮件发送和仓库备份等使用异步任务
- [ ] 支持在线仓库版本过滤、仓库版本互传
- [ ] 在仓库列表以突出颜色标记不被支持管理的仓库,如低版本的仓库
- [ ] 支持webhook
- [ ] 支持配置OSS进行备份
- [ ] 支持修改封面背景图片
- [ ] 仓库目录树视图中,文件或目录被授权过会有红点提示
- [ ] 增加多种备份方式的支持:如 svnadmin hotcopy
- [ ] 安装svnadmin的机器之间可进行远程同步
- [ ] 支持使用svnauthz-validate检查authz配置信息的正确性作为高级功能
- [ ] 支持使用三种认证选项(Apache+mod_dav_svn、svnserve(用户文件和SASL)、svnserve+SSH)
- [ ] 开发微信小程序端开发(针对提交提醒)
### 2、计划改进部分
## 六、FAQ
### 1、如何将已有的SVN仓库使用此系统管理 ?
- (1)安装本系统
- (2)执行 php server/install.php 使用内置的功能重新配置你的Subversion
- (3)将已有的一个或多个SVN仓库移动到 /home/svnadmin/rep/ 目录下
- (4)刷新管理系统的仓库管理页面即可识别SVN仓库
- (5)注意此方式并不会识别SVN仓库原有的用户以及权限配置,因为我们使用了统一的配置文件来进行用户和权限管理,因此迁移仓库后还需要在管理系统重新添加用户、用户组、配置权限!
### 2、如何将数据库切换为MySQL ?
- 创建数据库
- 将系统提供的 mysql 数据库文件导入到你的MySQL数据库
- 修改 config/database.php 将sqlite部分注释并配置你的MySQL即可
- 注意:若php版本过低而MySQL版本>=8.0,则会提示:The server requested authentication method unknown to the client,只需要升级php版本或者修改MySQL数据库的配置信息即可
### 3、为什么只支持管理Subversion1.8+ ?
- 由于Subversion1.8 之前不支持将多个仓库配置为使用相同的权限配置文件
- 而我们一开始基于Subversion1.10进行开发,因此没有及时的对Subversion1.7等版本进行适配
### 4、为什么目前只支持Linux操作系统 ?
- 正在使用新方案对Windows操作系统进行支持测试
- 预期目标为可安装Subversion和PHP的机器都可使用本软件
### 5、仓库初始化结构模板 ?
- 我们可以在创建仓库的时候选择创建指定内容结构的仓库,如包含 "trunk" "branches" "tags" 文件夹的结构,这一结构是可选的并且可调整的,我们可以手动调整 /home/svnadmin/templete/initStruct/01/ 下的目录结构
### 6、常用钩子推荐 ?
- 我们可以在目录 /home/svnadmin/hooks/ 下增加自己常用的钩子
- /home/svnadmin/hooks/ 下建立文件夹 xx,名称任意
- 在 xx 下新建文件 hookDescription 写入对此钩子的描述文本内容
- 在 xx 下新建文件 hookName 写入钩子类型,如post-commit等
- 在 xx 下新建文件 ,以钩子类型命名,如 post-commit ,然后写入具体钩子内容
- 感谢 【北方糙汉子-】提供的钩子脚本
### 7、关于Subversion 权限配置中的魔力符号
- Subversion从1.5开始支持用户使用一些魔力符号如 $authenticated 、$anonymous
- 我们使用正则表达式对authz和passwd文件进行匹配和修改
- 由于时间原因,暂时不支持用户的authz文件中使用 Subversion 支持的魔力符号
### 8、关于与LDAP对接
- 与LDAP的对接将会等待一段时间,因为还需要时间使当前版本更稳定
### 9、如何找回密码
- 使用默认的SQLite数据库
```
#使用sqlite数据库
yum install -y sqlite-devel
cd /home/svnadmin
sqlite3 svnadmin.db
.header on
.mode column
select * from admin_users;
```
- 使用MySQL数据库
- 使用可视化工具登录到数据库查看 admin_users 数据表信息即可
### 10、关于大文件下载中断问题
- 当下载1G以及以上的大文件会出现下载被中断的问题,是因为文件下载为了安全没有使用http文件直链,而是通过php校验后读取文件流下载,所以会存在一个php-fpm最大执行时间的问题,因此你可以通过 设置 php-fpm.conf 配置文件的 request_terminate_timeout 为0 来取消超时限制
### 11、本软件的工作模式
- 通过使 svnadmind.php 成为守护进程并监听指定端口来工作
- php-fpm与php-cli程序的使用TCP套接字通信
![](./00.static/03.daemon/work.png)
Loading…
Cancel
Save