Compare commits

..
96 Commits
Author SHA1 Message Date
HFO4 7d5e8fb2a1 1.0.3 2018-03-11 11:42:38 +08:00
HFO4 956deac89f 数据库升级逻辑 2018-03-11 11:39:33 +08:00
HFO4 4964f53dac 视频预览支持弹幕 2018-03-09 21:01:40 +08:00
AaronLiuandGitHub 037e6ad0b3 Update README.md 2018-03-08 22:44:06 +08:00
AaronLiuandGitHub 9c7494256c Update README.md 2018-03-08 22:43:18 +08:00
HFO4 21518300b4 定义移动端导航栏主题色 2018-03-07 20:07:25 +08:00
HFO4 99759b5a77 Fix #35 2018-03-05 19:20:12 +08:00
HFO4 d58b824d8b Fix #32 2018-03-05 19:09:19 +08:00
HFO4 33e56ca287 Merge branch 'master' of https://github.com/HFO4/Cloudreve 2018-03-05 19:03:37 +08:00
HFO4 c7901d55f0 修复 #25 2018-03-05 19:03:11 +08:00
AaronLiuandGitHub 53d01e5f6e Merge pull request #34 from Instrye/patch-1
修复 JS 获取 change 错误
2018-03-01 17:35:41 +08:00
InstryeandGitHub 4b58719e7c 修复 JS 获取 change 错误 2018-03-01 17:24:40 +08:00
AaronLiuandGitHub a82bee0216 Merge pull request #33 from Instrye/patch-1
修复 Admin删除分享文件的JS错误
2018-03-01 17:07:23 +08:00
InstryeandGitHub 0ea0902059 修复 Admi n删除分享文件的JS错误
修复 JQuery 获取 delete 对象错误
2018-03-01 17:05:05 +08:00
HFO4 a57dd79319 添加oss策略时加上http的提示 2018-02-19 17:55:16 +08:00
HFO4 228b898e9d 登录状态下访问首页跳转到文件页 2018-02-19 15:51:37 +08:00
HFO4 8f8b9df5a5 补齐.htaccess 2018-02-19 13:00:52 +08:00
HFO4 36925a63ef 删除锁文件 2018-02-18 21:51:00 +08:00
HFO4 df03461892 更新readme 2018-02-18 21:49:07 +08:00
HFO4 6361d4bd2e 修复二步验证二维码错误 2018-02-18 21:47:15 +08:00
AaronLiuandGitHub 937dfc77fd Merge pull request #18 from LinEvil/patch-1
Update TwoFactor.php
2018-02-18 21:34:43 +08:00
LinEvilandGitHub 31f1eb839f Update TwoFactor.php
安装的依赖endroid/qrcode已经弃用
请使用composer require endroid/qr-code
2018-02-18 21:32:18 +08:00
HFO4 12f7f691eb 修复因目录重名无法创建目录 2018-02-18 21:08:19 +08:00
HFO4 2d183acd0d 测试自动构建 2018-02-18 19:46:43 +08:00
HFO4 363da22bda 测试自动构建 2018-02-18 19:42:12 +08:00
HFO4 28d8d02508 测试自动构建 2018-02-18 19:39:50 +08:00
HFO4 662c3019d4 更新deploy.sh 2018-02-18 19:24:14 +08:00
HFO4 f5502b3666 添加自动打包 2018-02-18 19:20:06 +08:00
HFO4 4e550dcdb2 修复nginx无法使用sendfile 2018-02-16 11:59:09 +08:00
HFO4 59f8a9b58d 更新数据库版本 2018-02-16 10:46:07 +08:00
HFO4 b0898fcab4 支持通过sendfile下载文件 2018-02-16 10:31:53 +08:00
HFO4 8c8561dc31 拼写错误 2018-02-15 21:12:24 +08:00
HFO4 141de8ba54 修复部分情况加WebDAV无法使用 2018-02-15 21:08:26 +08:00
HFO4 159098decf 初步添加sendfile支持 2018-02-15 20:28:25 +08:00
HFO4 24789ca8a9 更新版本号 2018-02-14 18:11:57 +08:00
HFO4 544769bf04 Fix #12 2018-02-13 17:20:36 +08:00
HFO4 85119bc54d 新增发送安装反馈 2018-02-13 16:44:51 +08:00
HFO4 d3061f0526 README特性更新 2018-02-13 16:31:21 +08:00
HFO4 4492991bbb 修复一处url错误 2018-02-13 16:28:19 +08:00
HFO4 1e79428425 新增远程上传策略 2018-02-13 16:11:15 +08:00
HFO4 c28f08c210 自定远程服务端(未完成) 2018-02-10 14:14:40 +08:00
rainays 0e0f7d5258 添加登录按钮 2018-02-08 22:18:10 +08:00
HFO4 d2ca69b945 视频预览使用Dplayer 2018-02-07 14:40:46 +08:00
HFO4 9cb572f0da clear cache 2018-02-06 18:56:51 +08:00
HFO4 9994f12aa8 clear cache 2018-02-06 18:56:09 +08:00
HFO4 20b7d67adc 修复目录分享无法使用 2018-02-06 18:55:04 +08:00
HFO4 63cc404d74 修复目录分享无法使用 2018-02-06 18:54:08 +08:00
HFO4 47f334b6f4 修复部分服务器无法收到回调Authorization头 2018-02-06 17:34:49 +08:00
HFO4 1431f433d1 修复首页背景适应 2018-02-06 17:08:16 +08:00
HFO4 b6c1382e73 修复某些情况下验证码无效 2018-02-05 16:28:30 +08:00
HFO4 02ce111717 修复部分情况下安装报错 2018-02-05 13:59:19 +08:00
HFO4 02d00d9b19 更新安装说明 2018-02-05 13:27:51 +08:00
HFO4 25c86357da 权限设置 2018-02-05 12:23:31 +08:00
HFO4 bb49ff1b5f 拼写错误 2018-02-05 12:15:44 +08:00
HFO4 f33414c643 补全目录 2018-02-05 11:10:13 +08:00
HFO4 c1eebc7bf7 更新安装说明 2018-02-05 11:02:24 +08:00
HFO4 90a0b34b3e 安装程序执行发起 2018-02-05 10:52:09 +08:00
HFO4 60cd53895d 安装引导脚本 2018-02-05 10:48:11 +08:00
HFO4 a97df81a9e Merge branch 'master' of https://github.com/HFO4/Cloudreve 2018-02-05 08:41:37 +08:00
HFO4 3fdc327bb0 ready for merge 2018-02-05 08:41:30 +08:00
AaronLiuandGitHub d02899328d Update .htaccess 2018-02-05 07:33:04 +08:00
AaronLiuandGitHub 34767dd9b0 Merge pull request #4 from yrccondor/master
Change lang="en" to lang="zh_cn"
2018-02-04 20:16:12 +08:00
AxtonYaoandGitHub 85609ddbd8 fix 2018-02-04 20:12:10 +08:00
AxtonYaoandGitHub d6aa3ca86f Change lang="en" to lang="zh_cn" 2018-02-04 20:05:52 +08:00
AxtonYaoandGitHub 9e33129e7d Change lang="en" to lang="zh_cn" 2018-02-04 20:04:41 +08:00
HFO4 8c54632ccd Merge branch 'master' of https://github.com/HFO4/Cloudreve 2018-02-04 19:25:27 +08:00
HFO4 dda74f16ce Fix #2 2018-02-04 19:23:40 +08:00
AaronLiuandGitHub 69b540708e Update README.md 2018-02-04 18:29:59 +08:00
HFO4 f290658cd0 删除注释 2018-02-04 17:51:27 +08:00
HFO4 842f7bf052 修复找回密码表单判断 2018-02-04 17:45:53 +08:00
AaronLiuandGitHub 7998513e4e Update README.md 2018-02-04 17:22:05 +08:00
AaronLiuandGitHub dd3552fefd Update README.md 2018-02-04 17:20:58 +08:00
AaronLiuandGitHub f238dc14ca Delete database.php 2018-02-04 16:15:50 +08:00
AaronLiuandGitHub 865538f437 Update README.md 2018-02-04 16:09:34 +08:00
AaronLiuandGitHub c6fbca185d Update README.md 2018-02-04 15:53:23 +08:00
AaronLiuandGitHub 19fb84efa8 Update README.md 2018-02-04 15:44:11 +08:00
AaronLiuandGitHub 0be66f7897 Update README.md 2018-02-04 15:43:47 +08:00
AaronLiuandGitHub ebb99e9515 Update README.md 2018-02-04 15:33:12 +08:00
AaronLiuandGitHub 6f911908ed Update README.md 2018-02-04 15:32:37 +08:00
AaronLiuandGitHub d163808d45 更新Readme 2018-02-04 15:25:11 +08:00
HFO4 f46684495c 删除googleauthenticator 2018-02-04 14:55:03 +08:00
HFO4 884949dad4 语法错误 2018-02-04 14:40:51 +08:00
HFO4 3f30ec3c7e 取消dev要求 2018-02-04 14:33:02 +08:00
HFO4 93abecd2cb 更新README 2018-02-04 14:23:53 +08:00
AaronLiuandGitHub 9395228a66 Update composer.json 2018-02-04 14:08:42 +08:00
AaronLiuandGitHub 79c78a90f4 Update composer.json 2018-02-04 14:05:47 +08:00
AaronLiuandGitHub dcd392e70f Update composer.json 2018-02-04 13:56:50 +08:00
AaronLiuandGitHub 935f74fa52 Update composer.json 2018-02-04 13:37:10 +08:00
AaronLiuandGitHub 64f6cff7ce Update composer.json 2018-02-04 13:26:52 +08:00
AaronLiuandGitHub 76c5d9ad8a Update composer.json 2018-02-04 13:24:43 +08:00
AaronLiuandGitHub 3c90b83d11 Update composer.json 2018-02-04 13:24:13 +08:00
AaronLiuandGitHub 224c2a66c6 Update composer.json 2018-02-04 13:06:38 +08:00
AaronLiuandGitHub 7d6e026280 Update composer.json 2018-02-04 13:05:15 +08:00
AaronLiuandGitHub e9201d85f7 Update README.md 2018-02-04 13:02:21 +08:00
HFO4 3b9040028d Init 2018-02-04 12:58:07 +08:00
AaronLiuandGitHub a7691a1d1d Initial commit 2018-02-04 12:56:38 +08:00
810 changed files with 102987 additions and 55221 deletions
-1
View File
@@ -1 +0,0 @@
custom: ["https://cloudreve.org/buy.php"]
-38
View File
@@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
-61
View File
@@ -1,61 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 360
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- pinned
- security
- "[Status] Maybe Later"
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: true
# Label to use when marking as stale
staleLabel: wontfix
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
# closeComment: >
# Your comment here.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed
-55
View File
@@ -1,55 +0,0 @@
name: Build
on: workflow_dispatch
jobs:
build:
name: Build
runs-on: ubuntu-18.04
steps:
- name: Set up Go 1.18
uses: actions/setup-go@v2
with:
go-version: "1.18"
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
clean: false
submodules: "recursive"
- run: |
git fetch --prune --unshallow --tags
- name: Get dependencies and build
run: |
sudo apt-get update
sudo apt-get -y install gcc-mingw-w64-x86-64
sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
chmod +x ./build.sh
./build.sh -r b
- name: Upload binary files (windows_amd64)
uses: actions/upload-artifact@v2
with:
name: cloudreve_windows_amd64
path: release/cloudreve*windows_amd64.*
- name: Upload binary files (linux_amd64)
uses: actions/upload-artifact@v2
with:
name: cloudreve_linux_amd64
path: release/cloudreve*linux_amd64.*
- name: Upload binary files (linux_arm)
uses: actions/upload-artifact@v2
with:
name: cloudreve_linux_arm
path: release/cloudreve*linux_arm.*
- name: Upload binary files (linux_arm64)
uses: actions/upload-artifact@v2
with:
name: cloudreve_linux_arm64
path: release/cloudreve*linux_arm64.*
-57
View File
@@ -1,57 +0,0 @@
name: Build and push docker image
on:
push:
tags:
- 3.* # triggered on every push with tag 3.*
workflow_dispatch: # or just on button clicked
jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- run: git fetch --prune --unshallow
- name: Setup Environments
id: envs
run: |
CLOUDREVE_LATEST_TAG=$(git describe --tags --abbrev=0)
DOCKER_IMAGE="cloudreve/cloudreve"
echo "RELEASE_VERSION=${GITHUB_REF#refs}"
TAGS="${DOCKER_IMAGE}:latest,${DOCKER_IMAGE}:${CLOUDREVE_LATEST_TAG}"
echo "CLOUDREVE_LATEST_TAG:${CLOUDREVE_LATEST_TAG}"
echo ::set-output name=tags::${TAGS}
- name: Setup QEMU Emulator
uses: docker/setup-qemu-action@master
with:
platforms: all
- name: Setup Docker Buildx Command
id: buildx
uses: docker/setup-buildx-action@master
- name: Login to Dockerhub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build Docker Image and Push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: ${{ steps.envs.outputs.tags }}
- name: Update Docker Hub Description
uses: peter-evans/dockerhub-description@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
repository: cloudreve/cloudreve
short-description: ${{ github.event.repository.description }}
- name: Image Digest
run: echo ${{ steps.docker_build.outputs.digest }}
-35
View File
@@ -1,35 +0,0 @@
name: Test
on:
pull_request:
branches:
- master
push:
branches: [master]
jobs:
test:
name: Test
runs-on: ubuntu-18.04
steps:
- name: Set up Go 1.18
uses: actions/setup-go@v2
with:
go-version: "1.18"
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
submodules: "recursive"
- name: Build static files
run: |
mkdir assets/build
touch assets/build/test.html
- name: Test
run: go test -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v2
-31
View File
@@ -1,31 +0,0 @@
# Binaries for programs and plugins
cloudreve
*.exe
*.exe~
*.dll
*.so
*.dylib
*.db
*.bin
/release/
assets.zip
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Development enviroment
.idea/*
uploads/*
temp
# Version control
version.lock
# Config file
*.ini
conf/conf.ini
/statik/
.vscode/
-3
View File
@@ -1,3 +0,0 @@
[submodule "assets"]
path = assets
url = https://github.com/cloudreve/frontend.git
+9
View File
@@ -0,0 +1,9 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
</IfModule>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
+7 -29
View File
@@ -1,29 +1,7 @@
language: go
go:
- 1.18.x
node_js: "12.16.3"
git:
depth: 1
before_install:
- mkdir assets/build
- touch assets/build/test.html
script:
- go test -coverprofile=coverage.txt -covermode=atomic ./...
after_success:
- bash <(curl -s https://codecov.io/bash)
before_deploy:
- sudo apt-get update
- sudo apt-get -y install gcc-mingw-w64-x86-64
- sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
- sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- chmod +x ./build.sh
- ./build.sh -r b
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file: release/*
draft: true
skip_cleanup: true
on:
tags: true
language: php
php:
- 7.1
before_script:
- composer install
- chmod +x ./deploy.sh
script: ./deploy.sh
+114
View File
@@ -0,0 +1,114 @@
<?php
namespace CloudreveInstaller;
use Composer\Script\Event;
class Installer{
public static function startInstall(Event $event){
$version = json_decode(file_get_contents("application/version.json"),true)["version"];
$ioContext = $event->getIO();
$welcomMsg = "
___ _ _
/ __\ | ___ _ _ __| |_ __ _____ _____
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
Ver $version
================================================
";
$ioContext->write($welcomMsg);
$sqlInfo = self::getSqlInformation($event);
$ioContext->write("");
$siteUrl=$ioContext->ask("The full-url to access to your Cloudreve (e.g. https://pan.aoaoao.me/ , 'http' must be included in the front and '/' must be included at the end):");
$ioContext->write("");
if(!file_exists('mysql.sql')){
$ioContext->writeError("[Error] The file mysql.sql not exist.\nInstaller will exit.To retry, run 'composer install'");
exit();
}
$sqlSource = file_get_contents('mysql.sql');
$sqlSource = str_replace("https://cloudreve.org/", $siteUrl, $sqlSource);
$mysqli = @new \mysqli($sqlInfo["hostname"], $sqlInfo["username"], $sqlInfo["password"], $sqlInfo["database"], $sqlInfo["hostport"]);
$ioContext->write("=======================");
$ioContext->write("Starting import sql file...");
if ($mysqli->multi_query($sqlSource)) {
$ioContext->write("Writing complete.");
$ioContext->write("Writing database.php...");
if(file_exists('application/database.php')){
$ioContext->writeError("[Error] The file database.php already exist.\nInstaller will exit.To retry, run 'composer install'");
$ioContext->write("=======================");
exit();
}
self::writrConfig($event,$sqlInfo);
$ioContext->write("=======================");
}else{
$ioContext->writeError("[Error] Writing failed.Installer will exit. To retry, run 'composer install'");
$ioContext->write("=======================");
}
$ioContext->write("");
$ioContext->write("Congratulations! Cloudreve has been installed successfully.");
$ioContext->write("");
$ioContext->write("Here's some informatioin about yor Cloudreve:");
$ioContext->write("Homepage: $siteUrl");
$ioContext->write("Admin Panel: ".$siteUrl."Admin");
$ioContext->write("Default username: admin@cloudreve.org");
$ioContext->write("Default password: admin");
$ioContext->write("");
$ioContext->write("=======================");
$ioContext->write("IMPORTANT! You may still have to configure the URL Rewrite to set everthing to work.");
$ioContext->write("Refer to the install manual for more informatioin.");
$ioContext->write("=======================");
self::sendFeedBack($siteUrl);
}
public static function writrConfig(Event $event,$sqlInfo){
$ioContext = $event->getIO();
try {
$fileContent = file_get_contents("CloudreveInstaller/database_sample.php");
$replacement = array(
'{hostname}' => $sqlInfo["hostname"],
'{database}' => $sqlInfo["database"],
'{username}' => $sqlInfo["username"],
'{password}' => $sqlInfo["password"],
'{hostport}' => $sqlInfo["hostport"],
);
$fileContent = strtr($fileContent,$replacement);
file_put_contents('application/database.php',$fileContent);
}catch (Exception $e) {
$ioContext->writeError("[Error] Writing failed.Installer will exit. To retry, run 'composer install'");
}
$ioContext->write("Writing complete.");
}
public static function getSqlInformation(Event $event){
$ioContext = $event->getIO();
$hostname=$ioContext->ask("Input the hostname of your MySQL server (Default:127.0.0.1):","127.0.0.1");
$database=$ioContext->ask("The database name:","127.0.0.1");
$username=$ioContext->ask("The username of your MySQL server (Default:root):","root");
$password=$ioContext->ask("The password of your MySQL server:");
$hostport=$ioContext->ask("The hostport of your MySQL server (Default:3306):","3306");
$mysqli = @new \mysqli($hostname, $username, $password, $database, $hostport);
if ($mysqli->connect_error) {
$ioContext->writeError("[Error] Cannot connect to MySQL server, Message:".$mysqli->connect_error);
$ioContext->write("");
$ioContext->write("Please confirm your connection informatioin:");
@$mysqli->close();
return self::getSqlInformation($event);
}
return [
"hostname" => $hostname,
"database" => $database,
"username" => $username,
"password" => $password,
"hostport" => $hostport,
];
}
public static function sendFeedBack($url){
@file_get_contents("http://aoaoao.me/api/feedback.php?url=".urlencode($url));
}
}
?>
+53
View File
@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '{hostname}',
// 数据库名
'database' => '{database}',
// 用户名
'username' => '{username}',
// 密码
'password' => '{password}',
// 端口
'hostport' => '{hostport}',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'sd_',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 是否需要进行SQL性能分析
'sql_explain' => false,
];
-49
View File
@@ -1,49 +0,0 @@
# the frontend builder
# cloudreve need node.js 16* to build frontend,
# separate build step and custom image tag will resolve this
FROM node:16-alpine as cloudreve_frontend_builder
RUN apk update \
&& apk add --no-cache wget curl git yarn zip bash \
&& git clone --recurse-submodules https://github.com/cloudreve/Cloudreve.git /cloudreve_frontend
# build frontend assets using build script, make sure all the steps just follow the regular release
WORKDIR /cloudreve_frontend
ENV GENERATE_SOURCEMAP false
RUN chmod +x ./build.sh && ./build.sh -a
# the backend builder
# cloudreve backend needs golang 1.18* to build
FROM golang:1.18-alpine as cloudreve_backend_builder
# install dependencies and build tools
RUN apk update \
# install dependencies and build tools
&& apk add --no-cache wget curl git build-base gcc abuild binutils binutils-doc gcc-doc zip bash \
&& git clone --recurse-submodules https://github.com/cloudreve/Cloudreve.git /cloudreve_backend
WORKDIR /cloudreve_backend
COPY --from=cloudreve_frontend_builder /cloudreve_frontend/assets.zip ./
RUN chmod +x ./build.sh && ./build.sh -c
# TODO: merge the frontend build and backend build into a single one image
# the final published image
FROM alpine:latest
WORKDIR /cloudreve
COPY --from=cloudreve_backend_builder /cloudreve_backend/cloudreve ./cloudreve
RUN apk update \
&& apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& chmod +x ./cloudreve \
&& mkdir -p /data/aria2 \
&& chmod -R 766 /data/aria2
EXPOSE 5212
VOLUME ["/cloudreve/uploads", "/cloudreve/avatar", "/data"]
ENTRYPOINT ["./cloudreve"]
+1 -1
View File
@@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+82 -110
View File
@@ -1,131 +1,103 @@
<h1 align="center">
<br>
<a href="https://cloudreve.org/" alt="logo" ><img src="https://raw.githubusercontent.com/cloudreve/frontend/master/public/static/img/logo192.png" width="150"/></a>
<br>
Cloudreve
<br>
</h1>
![logo_white.png](https://raw.githubusercontent.com/HFO4/Cloudreve/master/static/img/logo_white.png)
<h4 align="center">支持多家云存储驱动的公有云文件系统.</h4>
Cloudreve - Make the cloud easy for everyone
=========================
[![Packagist](https://img.shields.io/packagist/v/HFO4/Cloudreve.svg)](https://packagist.org/packages/hfo4/cloudreve)
[![Latest Unstable Version](https://poser.pugx.org/hfo4/cloudreve/v/unstable)](https://packagist.org/packages/hfo4/cloudreve)
[![License](https://poser.pugx.org/hfo4/cloudreve/license)](https://packagist.org/packages/hfo4/cloudreve)
<p align="center">
<a href="https://github.com/cloudreve/Cloudreve/actions/workflows/test.yml">
<img src="https://img.shields.io/github/workflow/status/cloudreve/Cloudreve/Test?style=flat-square"
alt="GitHub Test Workflow">
</a>
<a href="https://codecov.io/gh/cloudreve/Cloudreve"><img src="https://img.shields.io/codecov/c/github/cloudreve/Cloudreve?style=flat-square"></a>
<a href="https://goreportcard.com/report/github.com/cloudreve/Cloudreve">
<img src="https://goreportcard.com/badge/github.com/cloudreve/Cloudreve?style=flat-square">
</a>
<a href="https://github.com/cloudreve/Cloudreve/releases">
<img src="https://img.shields.io/github/v/release/cloudreve/Cloudreve?include_prereleases&style=flat-square" />
</a>
<a href="https://hub.docker.com/r/cloudreve/cloudreve">
<img src="https://img.shields.io/docker/image-size/cloudreve/cloudreve?style=flat-square"/>
</a>
</p>
[主页](https://cloudreve.org) | [论坛](https://forum.cloudreve.org) | [演示站](https://pan.aoaoao.me) | |[Telegram群组](https://github.com/HFO4/Cloudreve)
<p align="center">
<a href="https://demo.cloudreve.org">演示站</a> •
<a href="https://forum.cloudreve.org/">讨论社区</a> •
<a href="https://docs.cloudreve.org/">文档</a> •
<a href="https://github.com/cloudreve/Cloudreve/releases">下载</a> •
<a href="https://t.me/cloudreve_official">Telegram 群组</a> •
<a href="#scroll-许可证">许可证</a>
</p>
基于ThinkPHP构建的网盘系统,能够助您以较低成本快速搭建起公私兼备的网盘。
![Screenshot](https://raw.githubusercontent.com/cloudreve/docs/master/images/homepage.png)
![homepage.png](https://download.aoaoao.me/homepage.png)
## :sparkles: 特性
目前已经实现的特性:
* :cloud: 支持本机、从机、七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive (包括世纪互联版) 作为存储
* :outbox_tray: 上传/下载 支持客户端直传,支持下载限速
* 💾 可对接 Aria2 离线下载,可使用多个从机节点分担下载任务
* 📚 在线 压缩/解压缩、多文件打包下载
* 💻 覆盖全部存储策略的 WebDAV 协议支持
* :zap: 拖拽上传、目录上传、流式上传处理
* :card_file_box: 文件拖拽管理
* :family_woman_girl_boy: 多用户、用户组
* :link: 创建文件、目录的分享链接,可设定自动过期
* :eye_speech_bubble: 视频、图像、音频、文本、Office 文档在线预览
* :art: 自定义配色、黑暗模式、PWA 应用、全站单页应用
* :rocket: All-In-One 打包,开箱即用
* 🌈 ... ...
* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、自建远程服务器,当然,还有本地存储
* 可限制单文件最大大小、MIMEType、文件后缀、用户可用容量
* 图片、音频、视频、文本、Markdown、Ofiice文档 在线预览
* 移动端全站响应式布局
* 文件、目录分享系统,可创建私有分享或公开分享链接
* 用户个人主页,可查看用户所有分享
* 多用户系统、用户组支持
* 初步完善的后台,方便管理
* 拖拽上传、分片上传、断点续传、下载限速(*实验性功能)
* 多上传策略,可为不同用户组分配不同策略
* 用户组基础权限设置、二步验证
* WebDAV协议支持
## :hammer_and_wrench: 部署
安装需求
------------
* LNMP/AMP With PHP5.6+
* curl、fileinfo、gd扩展
* Composer
下载适用于您目标机器操作系统、CPU架构的主程序,直接运行即可。
简要安装说明
------------
```shell
# 解压程序包
tar -zxvf cloudreve_VERSION_OS_ARCH.tar.gz
# 赋予执行权限
chmod +x ./cloudreve
# 启动 Cloudreve
./cloudreve
#### 1.使用Composer安装主程序
```
#安装开发版
$ composer create-project hfo4/cloudreve:dev-master
```
以上为最简单的部署示例,您可以参考 [文档 - 起步](https://docs.cloudreve.org/) 进行更为完善的部署。
## :gear: 构建
自行构建前需要拥有 `Go >= 1.18``node.js``yarn``zip` 等必要依赖。
#### 克隆代码
```shell
git clone --recurse-submodules https://github.com/cloudreve/Cloudreve.git
```
#等待安装依赖库后,会自动执行安装脚本,按照提示输入数据库账户信息
___ _ _
/ __\ | ___ _ _ __| |_ __ _____ _____
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
Ver XX
================================================
#按提示输入信息
......
```
#### 构建静态资源
```
#出现如下提示表示安装完成
Congratulations! Cloudreve has been installed successfully.
```shell
# 进入前端子模块
cd assets
# 安装依赖
yarn install
# 开始构建
yarn run build
# 构建完成后删除映射文件
cd build
find . -name "*.map" -type f -delete
# 返回项目主目录打包静态资源
cd ../../
zip -r - assets/build >assets.zip
Here's some informatioin about yor Cloudreve:
Homepage: https://pan.aoaoao.me/
Admin Panel: https://pan.aoaoao.me/Admin
Default username: admin@cloudreve.org
Default password: admin
```
#### 编译项目
#### 2.目录权限
`runtime`目录需要写入权限,如果你使用本地存储,`public` 目录也需要有写入权限
```shell
# 获得当前版本号、Commit
export COMMIT_SHA=$(git rev-parse --short HEAD)
export VERSION=$(git describe --tags)
# 开始编译
go build -a -o cloudreve -ldflags "-s -w -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=$VERSION' -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=$COMMIT_SHA'"
#### 3.URL重写
对于Apache服务器,项目目录下的`.htaccess`已经配置好重写规则,如有需求酌情修改.
对于Nginx服务器,以下是一个可供参考的配置:
```
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
break;
}
}
```
你也可以使用项目根目录下的 `build.sh` 快速开始构建:
#### 4.完成
后台地址:`http://您的域名/Admin` 初始用户名:`admin@cloudreve.org` 初始密码:`admin`
#### 后续操作
以下操作不是必须的,但仍推荐你完成这些操作:
* 修改初始账户密码
* 到 设置-基础设置 中更改站点URL,如果不更改,程序无法正常接受回调请求
* 添加Crontab定时任务 :你的域名/Cron
* 如果你打算使用本地上传策略并且不准备开启外链功能,请将·public/uploads·目录设置为禁止外部访问
* 如需启用二步验证功能,请依次执行`composer require phpgangsta/googleauthenticator:dev-master` `composer require endroid/qr-code`安装二步验证支持库
* 给本项目一个Star~
```shell
./build.sh [-a] [-c] [-b] [-r]
a - 构建静态资源
c - 编译二进制文件
b - 构建前端 + 编译二进制文件
r - 交叉编译,构建用于release的版本
```
文档
------------
* [完整安装说明](https://github.com/HFO4/Cloudreve/wiki/%E5%AE%89%E8%A3%85%E8%AF%B4%E6%98%8E)
* [安装及初次使用FAQ](https://github.com/HFO4/Cloudreve/wiki/%E5%AE%89%E8%A3%85%E5%8F%8A%E5%88%9D%E6%AC%A1%E4%BD%BF%E7%94%A8FAQ)
## :alembic: 技术栈
* [Go](https://golang.org/) + [Gin](https://github.com/gin-gonic/gin)
* [React](https://github.com/facebook/react) + [Redux](https://github.com/reduxjs/redux) + [Material-UI](https://github.com/mui-org/material-ui)
## :scroll: 许可证
GPL V3
---
> GitHub [@HFO4](https://github.com/HFO4) &nbsp;&middot;&nbsp;
> Twitter [@abslant00](https://twitter.com/abslant00)
许可证
------------
GPLV3
+1
View File
@@ -0,0 +1 @@
database.php
+1
View File
@@ -0,0 +1 @@
deny from all
+12
View File
@@ -0,0 +1,12 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
return [];
+41
View File
@@ -0,0 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用公共文件
function array_column_fix($array,$key){
if(count($array) == count($array,1)){
return array(0 =>$array[$key]);
}else{
return array_column($array,$key);
}
}
function getAllowedExt($ext){
$returnValue = "";
foreach (json_decode($ext,true) as $key => $value) {
$returnValue .= $value["ext"].",";
}
return rtrim($returnValue, ",");
}
function getDirName($name){
$explode = explode("/", $name);
return end($explode);
}
function getSize($bit,$array=false){
$type = array('Bytes','KB','MB','GB','TB');
$box = array('1','1024','1048576','1073741824','TB');
for($i = 0; $bit >= 1024; $i++) {
$bit/=1024;
}
if($array){
return [(floor($bit*100)/100),$box[$i]];
}
return (floor($bit*100)/100).$type[$i];
}
+270
View File
@@ -0,0 +1,270 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
//密码加盐
'salt' => 'sdshare',
// 应用命名空间
'app_namespace' => 'app',
// 应用调试模式
'app_debug' => false,
// 应用Trace
'app_trace' => false,
// 应用模式状态
'app_status' => '',
// 是否支持多模块
'app_multi_module' => true,
// 入口自动绑定模块
'auto_bind_module' => false,
// 注册的根命名空间
'root_namespace' => [],
// 扩展函数文件
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
// 默认输出类型
'default_return_type' => 'html',
// 默认AJAX 数据返回格式,可选json xml ...
'default_ajax_return' => 'json',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
// 默认时区
'default_timezone' => 'PRC',
// 是否开启多语言
'lang_switch_on' => false,
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 默认语言
'default_lang' => 'zh-cn',
// 应用类库后缀
'class_suffix' => false,
// 控制器类后缀
'controller_suffix' => false,
// +----------------------------------------------------------------------
// | 模块设置
// +----------------------------------------------------------------------
// 默认模块名
'default_module' => 'index',
// 禁止访问模块
'deny_module_list' => ['common'],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 默认验证器
'default_validate' => '',
// 默认的空控制器名
'empty_controller' => 'Error',
// 操作方法后缀
'action_suffix' => '',
// 自动搜索控制器
'controller_auto_search' => false,
// +----------------------------------------------------------------------
// | URL设置
// +----------------------------------------------------------------------
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
'url_convert' => false,
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => '',
// URL普通方式参数 用于自动生成
'url_common_param' => false,
// URL参数方式 0 按名称成对解析 1 按顺序解析
'url_param_type' => 0,
// 是否开启路由
'url_route_on' => true,
// 路由使用完整匹配
'route_complete_match' => false,
// 路由配置文件(支持配置多个)
'route_config_file' => ['route'],
// 是否强制使用路由
'url_route_must' => false,
// 域名部署
'url_domain_deploy' => false,
// 域名根,如thinkphp.cn
'url_domain_root' => '',
// 是否自动转换URL中的控制器和操作名
'url_convert' => false,
// 默认的访问控制器层
'url_controller_layer' => 'controller',
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '_ajax',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DS,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
],
// 视图输出字符串内容替换
'view_replace_str' => [],
// 默认跳转页面对应的模板文件
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
'dispatch_error_tmpl' => "application/index/view/error.html",
// +----------------------------------------------------------------------
// | 异常及错误设置
// +----------------------------------------------------------------------
// 异常页面的模板文件
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => false,
// 异常处理handle类 留空使用 \think\exception\Handle
'exception_handle' => '',
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
'log' => [
// 日志记录方式,内置 file socket 支持扩展
'type' => 'File',
// 日志保存目录
'path' => LOG_PATH,
// 日志记录级别
'level' => ["error"],
],
// +----------------------------------------------------------------------
// | Trace设置 开启 app_trace 后 有效
// +----------------------------------------------------------------------
'trace' => [
// 内置Html Console 支持扩展
'type' => 'Html',
],
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
'cache' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => CACHE_PATH,
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
],
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
'session' => [
'id' => '',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// SESSION 前缀
'prefix' => 'sd',
// 驱动方式 支持redis memcache memcached
'type' => '',
// 是否自动开启 SESSION
'auto_start' => true,
],
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
'cookie' => [
// cookie 名称前缀
'prefix' => '',
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => '',
// 是否使用 setcookie
'setcookie' => true,
],
//分页配置
'paginate' => [
'type' => 'bootstrap',
'var_page' => 'page',
'list_rows' => 15,
],
// +----------------------------------------------------------------------
// | 验证码设置
// +----------------------------------------------------------------------
'captcha'=>[
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
// 验证码字符集合
'expire' => 1800,
// 验证码过期时间(s
'useZh' => false,
// 使用背景图片
'fontSize' => 25,
// 验证码字体大小(px)
'useCurve' => true,
// 是否画混淆曲线
'useNoise' => true,
// 是否添加杂点
'imageH' => 0,
// 验证码图片高度
'imageW' => 0,
// 验证码图片宽度
'length' => 4,
// 验证码位数
'fontttf' => '',
// 验证码字体,不设置随机获取
'bg' => [243, 251, 254],
// 背景颜色
'reset' => true],
];
+53
View File
@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'tp',
// 用户名
'username' => 'root',
// 密码
'password' => 'root',
// 端口
'hostport' => '3306',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'sd_',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 是否需要进行SQL性能分析
'sql_explain' => false,
];
+14
View File
@@ -0,0 +1,14 @@
<?php
function classLoader($class)
{
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
$file = __DIR__ . '/src/' . $path . '.php';
if (file_exists($file)) {
require_once $file;
}
}
spl_autoload_register('classLoader');
require_once __DIR__ . '/src/Qiniu/functions.php';
+25
View File
@@ -0,0 +1,25 @@
<?php
function countSize($bit,$array=false){
$type = array('Bytes','KB','MB','GB','TB');
$box = array('1','1024','1048576','1073741824','TB');
for($i = 0; $bit >= 1024; $i++) {
$bit/=1024;
}
if($array){
return [(floor($bit*100)/100),$box[$i]];
}
return (floor($bit*100)/100).$type[$i];
}
function isPreview($fileName){
$allowedSuffix=["jpg","jpeg","gif","bmp","png","svg","mp4","mp3","ogg"];
$suffix = explode(".",$fileName);
if(in_array(end($suffix),$allowedSuffix)){
return "yes";
}
return "no";
}
function getDay($sec){
return floor($sec/86400);
}
?>
+486
View File
@@ -0,0 +1,486 @@
<?php
namespace app\index\controller;
use think\Controller;
use app\index\model\User;
use think\Cookie;
use think\Db;
use \app\index\model\Option;
use \app\index\model\AdminHandler;
use \app\index\model\FileManage;
class Admin extends Controller{
public $userObj;
public $siteOptions;
public $adminObj;
public function _initialize(){
$this->siteOptions = Option::getValues(["basic","admin"]);
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
if(!$this->userObj->loginStatus){
$this->redirect(url('/Login','',''));
exit();
}
if($this->userObj->groupData["id"] != 1){
$this->error('你无权访问此页面',403,$this->siteOptions);
}
$this->adminObj = new AdminHandler($this->siteOptions);
}
public function index(){
if($this->adminObj->checkDbVersion()){
$this->redirect(url('/Admin/UpdateDb','',''));
exit();
}
return view('admin_index', [
'options' => $this->siteOptions,
'statics' => $this->adminObj->getStatics(),
]);
}
public function UpdateDb(){
if(!$this->adminObj->checkDbVersion()){
$this->redirect(url('/Admin','',''));
exit();
}
echo "<meta charset='utf-8'>";
echo "准备升级数据库,当前数据库版本:".$this->adminObj->dbVerInfo["now"];
echo ", 目标数据库版本:".$this->adminObj->dbVerInfo["require"].";<br>";
$updatePath = ROOT_PATH . "update_".$this->adminObj->dbVerInfo["now"]."to".$this->adminObj->dbVerInfo["require"].".sql";
if(!file_exists($updatePath)){
die("数据库更新文件(".$updatePath.")不存在,升级中止.");
}
echo "获取升级SQL文件(".$updatePath.")<br>";
$updateContent = file_get_contents($updatePath);
echo "将执行以下指令:<br>";
echo "<code>".htmlspecialchars($updateContent)."</code><br>";
$sqlSingle = explode(";", $updateContent);
foreach ($sqlSingle as $key => $value){
if(empty($value)){
continue;
}
if(!Db::execute($value)){
echo "<strong>执行$value 时出现错误</strong><br>";
}
}
echo "<strong>升级完成,<a href='/Admin'>返回管理面板</a></strong>";
}
public function Setting(){
return view('basic_setting', [
'options' => $this->siteOptions,
]);
}
public function Config(){
$configType=input("?param.type") ? input("param.type") : "common";
$configFile = $this->adminObj->getConfigFile($configType);
return view('config_file', [
'options' => $this->siteOptions,
'type' => $configType,
'content' => $configFile[0],
'path' => $configFile[1],
]);
}
public function SaveConfigFile(){
return $this->adminObj->saveConfigFile(input('post.'));
}
public function SettingReg(){
return view('reg_setting', [
'options' => $this->siteOptions,
'optionsForSet' => Option::getValues(["login","register"]),
'groups' => $this->adminObj->getAvaliableGroup(),
]);
}
public function Theme(){
$fileName=input("?param.name") ? input("param.name") : "error";
$dir = ROOT_PATH."application/index/view/";
if(!function_exists("scandir")){
return "scandir被禁用";
}
$fileList=[];
$fileList=$fileList+scandir($dir);
$pathList=["/"=>$fileList];
foreach (["admin","explore","file","home","index","member","profile","share"] as $key => $value) {
$childPath = scandir($dir.$value."/");
$fileList=array_merge($fileList,$childPath);
$pathList = array_merge($pathList,[$value => $childPath]);
}
foreach ($fileList as $key => $value) {
if(substr_compare($value, ".html", -strlen(".html")) != 0){
unset($fileList[$key]);
}
}
foreach($pathList as $key=>$val){
if(in_array($fileName.".html",$val)){
$parentPath = $key;
break;
}
}
$fileContent = file_get_contents($dir.rtrim($parentPath,"/")."/".$fileName.".html");
return view('theme', [
'options' => $this->siteOptions,
'list' => $fileList,
'content' => $fileContent,
'path' => $parentPath,
'name' => $fileName,
]);
}
public function SaveThemeFile(){
return $this->adminObj->saveThemeFile(input('post.'));
}
public function SettingMail(){
return view('mail_setting', [
'options' => $this->siteOptions,
'optionsForSet' => Option::getValues(["mail_template","mail"]),
]);
}
public function SettingPay(){
return view('pay_setting', [
'options' => $this->siteOptions,
'optionsForSet' => Option::getValues(["payment"]),
]);
}
public function SettingOther(){
return view('other_setting', [
'options' => $this->siteOptions,
'optionsForSet' => Option::getValues(["file_edit","share","avatar","admin","storage_policy","download"]),
]);
}
public function Files(){
$this->adminObj->listFile();
return view('file_list', [
'options' => $this->siteOptions,
'groups' => $this->adminObj->getAvaliableGroup(),
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
'policy' => $this->adminObj->getAvaliablePolicy(),
]);
}
Public function Users(){
$this->adminObj->listUser();
$group = $this->adminObj->getAvaliableGroup();
return view('user_list', [
'options' => $this->siteOptions,
'group' => $group,
'groups' => $group,
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
'policy' => $this->adminObj->getAvaliablePolicy(),
]);
}
public function Shares(){
$this->adminObj->listShare();
return view('share_list', [
'options' => $this->siteOptions,
'groups' => $this->adminObj->getAvaliableGroup(),
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
]);
}
public function PolicyList(){
$this->adminObj->listPolicy();
return view('policy_list', [
'options' => $this->siteOptions,
'groups' => $this->adminObj->getAvaliableGroup(),
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
]);
}
public function GroupList(){
$this->adminObj->listGroup();
return view('group_list', [
'options' => $this->siteOptions,
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
]);
}
public function OrderList(){
$this->adminObj->listOrder();
return view('order_list', [
'options' => $this->siteOptions,
'list' => $this->adminObj->pageData,
'originList' => $this->adminObj->listData,
'pageNow' => $this->adminObj->pageNow,
'pageTotal' => $this->adminObj->pageTotal,
'dataTotal' => $this->adminObj->dataTotal,
]);
}
public function SaveBasicSetting(){
return $this->adminObj->saveBasicSetting(input('post.'));
}
public function SaveRegSetting(){
return $this->adminObj->saveRegSetting(input('post.'));
}
public function SaveMailSetting(){
return $this->adminObj->saveMailSetting(input('post.'));
}
public function SendTestMail(){
return $this->adminObj->sendTestMail(input('post.'));
}
public function SaveMailTemplate(){
return $this->adminObj->saveMailTemplate(input('post.'));
}
public function GetFileInfo(){
return $this->adminObj->getFileInfo(input('post.id'));
}
public function GetUserInfo(){
return $this->adminObj->getUserInfo(input('post.id'));
}
public function savePolicy(){
return $this->adminObj->addPolicy(input('post.'));
}
public function SaveEditPolicy(){
return $this->adminObj->editPolicy(input('post.'));
}
public function SaveGroup(){
return $this->adminObj->saveGroup(input('post.'));
}
public function AddPack(){
return $this->adminObj->addPack(input('post.'));
}
public function AddGroupPurchase(){
return $this->adminObj->addGroupPurchase(input('post.'));
}
public function SaveCron(){
$this->adminObj->saveCron(input('post.'));
$this->redirect("/Admin/Cron",302);
}
public function SaveUser(){
return $this->adminObj->saveUser(input('post.'));
}
public function BanUser(){
return $this->adminObj->banUser(input('post.id'),$this->userObj->uid);
}
public function AddUser(){
return $this->adminObj->addUser(input('post.'));
}
public function Preview(){
$fileId = input('param.id');
$fileRecord = Db::name("files")->where("id",$fileId)->find();
$fileObj = new FileManage(rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"],$fileRecord["upload_user"]);
$previewHandler = $fileObj->PreviewHandler(true);
if($previewHandler[0]){
$this->redirect($previewHandler[1],302);
}
}
public function Download(){
$fileId = input('param.id');
$fileRecord = Db::name("files")->where("id",$fileId)->find();
$fileObj = new FileManage(rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"],$fileRecord["upload_user"]);
$FileHandler = $fileObj->Download(true);
if($FileHandler[0]){
$this->redirect($FileHandler[1],302);
}
}
public function Delete(){
return $this->adminObj->deleteSingle(input('post.id'));
}
public function DeleteShare(){
return $this->adminObj->deleteShare([0=>input('post.id')]);
}
public function DeleteShareMultiple(){
return $this->adminObj->deleteShare(json_decode(input('post.id'),true));
}
public function DeleteMultiple(){
return $this->adminObj->deleteMultiple(input('post.id'));
}
public function DeletePolicy(){
return $this->adminObj->deletePolicy(input('post.id'));
}
public function DeleteGroup(){
return $this->adminObj->deleteGroup(input('post.id'));
}
public function DeleteOrder(){
return $this->adminObj->deleteOrder(input('post.id'));
}
public function ChangeShareType(){
return $this->adminObj->changeShareType(input('post.id'));
}
public function DeletePack(){
return $this->adminObj->deletePack(input('post.id'));
}
public function DeleteGroupPurchase(){
return $this->adminObj->deleteGroupPurchase(input('post.id'));
}
public function DeleteUser(){
return $this->adminObj->deleteUser(input('post.id'),$this->userObj->uid);
}
public function DeleteUsers(){
$uidGroup = json_decode(input('post.id'),true);
foreach ($uidGroup as $key => $value) {
$this->adminObj->deleteUser($value,$this->userObj->uid);
}
return ["error"=>false,"msg"=>"删除成功"];
}
public function SwitchColor(){
$colorNow = Option::getValues(["admin"]);
if($colorNow["admin_color_body"] == "fixed-nav sticky-footer bg-light"){
$colorNew = [
"admin_color_body" => "fixed-nav sticky-footer bg-dark",
"admin_color_nav" => "navbar navbar-expand-lg fixed-top navbar-dark bg-dark",
];
}else{
$colorNew = [
"admin_color_body" => "fixed-nav sticky-footer bg-light",
"admin_color_nav" => "navbar navbar-expand-lg fixed-top navbar-light bg-light",
];
}
foreach ($colorNew as $key => $value) {
Db::name("options")->where("option_name",$key)->update(["option_value" => $value]);
}
}
public function EditPolicy(){
$policyId = input('param.id');
$policyRecord = Db::name("policy")->where("id",$policyId)->find();
return view('edit_policy', [
'options' => $this->siteOptions,
'policy' => $policyRecord,
]);
}
public function EditGroup(){
$groupId = input('param.id');
$groupRecord = Db::name("groups")->where("id",$groupId)->find();
return view('edit_group', [
'options' => $this->siteOptions,
'group' => $groupRecord,
'policy' => $this->adminObj->getAvaliablePolicy(),
]);
}
public function AddGroup(){
return $this->adminObj->addGroup(input('post.'));
}
public function PolicyAdd(){
return view('add_policy', [
'options' => $this->siteOptions,
]);
}
public function Cron(){
$cronData = Db::name("corn")->select();
$neverExcute = true;
foreach ($cronData as $key => $value) {
if($value["last_excute"] !=0){
$neverExcute = false;
}
}
return view('cron_list', [
'options' => $this->siteOptions,
'cron' => $cronData,
'neverExcute' => $neverExcute,
]);
}
public function PolicyAddS3(){
return view('add_policy_s3', [
'options' => $this->siteOptions,
]);
}
public function PolicyAddRemote(){
return view('add_policy_remote', [
'options' => $this->siteOptions,
]);
}
public function About(){
$verison = json_decode(file_get_contents(ROOT_PATH . "application/version.json"),true);
return view('about', [
'options' => $this->siteOptions,
'programVersion' => $verison,
"dbsVersion" => Option::getValue("database_version"),
]);
}
public function Purchase(){
$packData = json_decode(Option::getValue("pack_data"),true);
return view('purchase', [
'options' => $this->siteOptions,
'pack' => $packData,
]);
}
public function PurchaseGroup(){
$groupData = json_decode(Option::getValue("group_sell_data"),true);
foreach ($groupData as $key => $value) {
$groupData[$key]["group"] = Db::name("groups")->where("id",$value["goup_id"])->find();
}
return view('purchase_group', [
'options' => $this->siteOptions,
'group' => $groupData,
'group_list' => $this->adminObj->getAvaliableGroup(),
]);
}
public function GroupAdd(){
return view('add_group', [
'options' => $this->siteOptions,
'policy' => $this->adminObj->getAvaliablePolicy(),
]);
}
}
+91
View File
@@ -0,0 +1,91 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\Request;
use \app\index\model\CallbackHandler;
use \app\index\model\User;
use \app\index\model\Option;
use \app\index\model\FileManage;
use think\Session;
class Callback extends Controller{
public function index(){
return "";
}
public function Qiniu(){
ob_end_clean();
header('Content-Type: application/json');
$handllerObj = new CallbackHandler(file_get_contents("php://input"));
$handllerObj -> qiniuHandler(Request::instance()->header('Authorization'));
}
public function Oss(){
ob_end_clean();
header('Content-Type: application/json');
$handllerObj = new CallbackHandler(file_get_contents("php://input"));
$handllerObj -> ossHandler(Request::instance()->header('Authorization'),Request::instance()->header('x-oss-pub-key-url'));
}
public function TmpPreview(){
$basicOptions = Option::getValues(['basic']);
$params = explode(":",input("param.key"));
$fileData = Db::name("files")->where("id",$params[0])->find();
if (empty($fileData)){
abort(404);
}
$userData = Db::name("users")->where("id",$fileData["upload_user"])->find();
if(md5($userData["user_pass"].$fileData["id"].$params[1].config("salt")) != $params[2] || time()<$params[0]){
abort(403);
}
$fileObj = new FileManage(rtrim($fileData["dir"],"/")."/".$fileData["orign_name"],$userData["id"]);
$Redirect = $fileObj->PreviewHandler();
}
public function Upyun(){
$signToken = Request::instance()->header('Authorization');
$reqDate = Request::instance()->header('Date');
$contentMd5 = Request::instance()->header('Content-MD5');
ob_end_clean();
header('Content-Type: application/json');
$callbackData = [
"code" => input("post.code"),
"file_size" => input("post.file_size"),
"url" => input("post.url"),
"image-width" => input("post.image-width"),
"image-height" => input("post.image-height"),
"ext-param" => json_decode(input("post.ext-param"),true),
];
$handllerObj = new CallbackHandler($callbackData);
$handllerObj -> upyunHandler($signToken,$reqDate,$contentMd5);
}
public function S3(){
$request = Request::instance();
if($request->method() == "OPTIONS"){
ob_end_clean();
header("Access-Control-Allow-Origin: *");
exit();
}
ob_end_clean();
header("Access-Control-Allow-Origin: *");
$callbackKey = input("param.key");
$callbackData = [
"bucket" => input("get.bucket"),
"key" => input("get.key"),
];
$handllerObj = new CallbackHandler($callbackData);
$handllerObj -> s3Handler($callbackKey);
}
public function Remote(){
ob_end_clean();
header('Content-Type: application/json');
$handllerObj = new CallbackHandler(file_get_contents("php://input"));
$handllerObj -> remoteHandler(Request::instance()->header('Authorization'));
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\Request;
use \app\index\model\CronHandler;
use think\Session;
class Cron extends Controller{
public function index(){
$cornObj = new CronHandler();
$cornObj->Doit();
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace app\index\controller;
use think\Controller;
use app\index\model\User;
use think\Cookie;
use think\Db;
use \app\index\model\Option;
class Explore extends Controller{
public $visitorObj;
public $userObj;
public $siteOptions;
public function _initialize(){
$this->siteOptions = Option::getValues(["basic"]);
}
public function Search(){
$this->visitorObj = new User(cookie('user_id'),cookie('login_key'));
return view("search",[
"options" => $this->siteOptions,
'loginStatus' => $this->visitorObj->loginStatus,
'userData' => $this->visitorObj->userSQLData,
]);
}
public function S(){
$this->visitorObj = new User(cookie('user_id'),cookie('login_key'));
$keyWords=input("param.key");
if(empty($keyWords)){
$this->redirect('/Explore/Search',302);
}
$list = Db::name('shares')
->where('type',"public")
->where('origin_name',"like","%".$keyWords."%")
->order('id DESC')
->paginate(10);
$listData = $list->all();
foreach ($listData as $key => $value) {
if($value["source_type"]=="file"){
$listData[$key]["fileData"] = $value["origin_name"];
}else{
$pathDir = explode("/",$value["source_name"]);
$listData[$key]["fileData"] = end($pathDir);
}
}
return view("result",[
"options" => $this->siteOptions,
'loginStatus' => $this->visitorObj->loginStatus,
'userData' => $this->visitorObj->userSQLData,
'list' => $listData,
'listOrigin' => $list,
'keyWords' => $keyWords,
]);
}
}
+175
View File
@@ -0,0 +1,175 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\Request;
use \app\index\model\Option;
use \app\index\model\User;
use \app\index\model\FileManage;
use \app\index\model\ShareHandler;
use think\Session;
class File extends Controller{
public $userObj;
/**
* [_initialize description]
* @return [type] [description]
*/
public function _initialize(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
if(!$this->userObj->loginStatus){
echo "Bad request";
exit();
}
}
/**
* [index description]
* @Author Aaron
* @DateTime 2017-07-03
* @return [type] [description]
*/
public function index(){
return "";
}
/**
* [List description]
* @Author Aaron
* @DateTime 2017-07-03
*/
public function ListFile(){
$reqPath = stripslashes(json_decode(file_get_contents("php://input"),true)['path']);
return FileManage::ListFile($reqPath,$this->userObj->uid);
}
public function Delete(){
$reqPath = json_decode(file_get_contents("php://input"),true)['items'];
$dirPath = json_decode(file_get_contents("php://input"),true)['dirs'];
FileManage::DirDeleteHandler($dirPath,$this->userObj->uid);
return FileManage::DeleteHandler($reqPath,$this->userObj->uid);
}
public function Move(){
$reqPath = json_decode(file_get_contents("php://input"),true)['items'];
$dirPath = json_decode(file_get_contents("php://input"),true)['dirs'];
$newPath = json_decode(file_get_contents("php://input"),true)['newPath'];
return FileManage::MoveHandler($reqPath,$dirPath,$newPath,$this->userObj->uid);
}
public function Rename(){
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
$newPath = json_decode(file_get_contents("php://input"),true)['newItemPath'];
return FileManage::RenameHandler($reqPath,$newPath,$this->userObj->uid);
}
public function Preview(){
$reqPath = $_GET["path"];
$fileObj = new FileManage($reqPath,$this->userObj->uid);
$Redirect = $fileObj->PreviewHandler();
if($Redirect[0]){
$this->redirect($Redirect[1],302);
}
}
public function ListPic(){
$reqPath = $_GET["path"];
return FileManage::listPic($reqPath,$this->userObj->uid);
}
public function Download(){
$reqPath = $_GET["path"];
$fileObj = new FileManage($reqPath,$this->userObj->uid);
$FileHandler = $fileObj->Download();
if($FileHandler[0]){
$this->redirect($FileHandler[1],302);
}
}
public function Share(){
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
$shareType = json_decode(file_get_contents("php://input"),true)['shareType'];
ShareHandler::createShare($reqPath,$shareType,$this->userObj->getSQLData(),$this->userObj->getGroupData());
}
public function gerSource(){
$reqPath = $_POST["path"];
$fileObj = new FileManage($reqPath,$this->userObj->uid);
$FileHandler = $fileObj->Source();
}
public function Content(){
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
$fileObj = new FileManage($reqPath,$this->userObj->uid);
$FileHandler = $fileObj->getContent();
}
public function Edit(){
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
$fileContent = json_decode(file_get_contents("php://input"),true)['content'];
$fileObj = new FileManage($reqPath,$this->userObj->uid);
$FileHandler = $fileObj->saveContent($fileContent);
}
public function OssDownload(){
return view('oss_download', [
'url' => urldecode(input("get.url")),
'name' => urldecode(input("get.name")),
]);
}
public function DocPreview(){
$filePath = input("get.path");
$fileObj = new FileManage($filePath,$this->userObj->uid);
$tmpUrl = $fileObj->signTmpUrl();
$this->redirect("http://view.officeapps.live.com/op/view.aspx?src=".urlencode($tmpUrl),302);
}
public function Thumb(){
$filePath = input("get.path");
if(input("get.isImg") != "true"){
return "";
}
$fileObj = new FileManage($filePath,$this->userObj->uid);
$Redirect = $fileObj->getThumb();
if($Redirect[0]){
$this->redirect($Redirect[1],302);
}
}
public function GoogleDocPreview(){
$filePath = input("get.path");
$fileObj = new FileManage($filePath,$this->userObj->uid);
$tmpUrl = $fileObj->signTmpUrl();
$this->redirect("https://docs.google.com/viewer?url=".urlencode($tmpUrl),302);
}
/**
* [createFolder description]
* @Author Aaron
* @DateTime 2017-07-03
* @return [type] [description]
*/
public function createFolder(){
$reqPath = stripslashes(json_decode(file_get_contents("php://input"),true)['newPath']);
$pathSplit = explode("/",$reqPath);
$dirName = end($pathSplit);
$dirPosition="/";
foreach ($pathSplit as $key => $value) {
if (empty($value)){
}else if($key == (count($pathSplit)-2)){
$dirPosition = $dirPosition.$value;
}else if($key == (count($pathSplit)-1)){
}else{
$dirPosition = $dirPosition.$value."/";
}
}
return FileManage::createFolder($dirName,$dirPosition,$this->userObj->uid);
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use \app\index\model\Option;
use \app\index\model\User;
use think\Session;
class Home extends Controller{
public $userObj;
public function _initialize(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
if(!$this->userObj->loginStatus){
$this->redirect(url('/Login','',''));
exit();
}
}
public function index(){
$userInfo = $this->userObj->getInfo();
$policyData = $this->userObj->getPolicy();
$groupData = $this->userObj->getGroupData();
$extJson = json_decode($policyData["filetype"],true);
$extLimit="";
foreach ($extJson as $key => $value) {
$extLimit.='{ title : "'.$value["title"].'", extensions : "'.$value["ext"].'" },';
}
$policyData["max_size"] = $policyData["max_size"]/(1024*1024);
return view('home', [
'options' => Option::getValues(['basic','upload']),
'userInfo' => $userInfo,
'extLimit' => $extLimit,
'policyData' => $policyData,
'groupData' => $groupData,
]);
}
public function Album(){
$userInfo = $this->userObj->getInfo();
$list = Db::name("files")->where("upload_user",$this->userObj->uid)
->where(function ($query) {
$query->where('orign_name', "like","%jpg")
->whereor('orign_name', "like","%png")
->whereor('orign_name', "like","%gif")
->whereor('orign_name', "like","%bmp");
})
->order('id DESC')
->paginate(9);
$pageCount = ceil(Db::name("files")->where("upload_user",$this->userObj->uid)
->where(function ($query) {
$query->where('orign_name', "like","%jpg")
->whereor('orign_name', "like","%png")
->whereor('orign_name', "like","%gif")
->whereor('orign_name', "like","%bmp");
})
->order('id DESC')->count()/9);
$listData = $list->all();
$pageNow = input("?get.page")?input("get.page"):1;
if($pageNow>$pageCount){
$this->error('页面不存在',404,Option::getValues(['basic','group_sell']));
}
return view('album', [
'options' => Option::getValues(['basic','group_sell']),
'userInfo' => $userInfo,
'list' => $listData,
'listOrigin' => $list,
'pageCount' => $pageCount,
'page' => $pageNow,
]);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use \app\index\model\Option;
use \app\index\model\User;
class Index extends Controller{
public $userObj;
public function index(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
if($this->userObj->loginStatus){
$this->redirect(url('/Home','',''));
exit();
}
$userInfo = $this->userObj->getInfo();
return view('index', [
'options' => Option::getValues(['basic']),
'userInfo' => $userInfo,
]);
}
}
+300
View File
@@ -0,0 +1,300 @@
<?php
namespace app\index\controller;
use think\Controller;
use app\index\model\User;
use think\Cookie;
use think\Db;
use \app\index\model\Option;
use \app\index\model\Avatar;
use \PHPGangsta_GoogleAuthenticator;
use \app\index\model\TwoFactor;
class Member extends Controller{
public $userObj;
/**
* [index description]
* @return [type] [description]
*/
public function index(){
echo "hello";
}
/**
* [Register description]
*/
public function Register(){
if(input('?post.username-reg') && input('?post.password-reg')){
$regAction = User::register(input('post.username-reg'),input('post.password-reg'),input('post.captchaCode'));
if ($regAction[0]){
return json(['code' => '200','message' => $regAction[1]]);
}else{
return json(['code' => '1','message' => $regAction[1]]);
}
}else{
return json(['code' => '1','message' => "信息不完整"]);
}
}
public function ForgetPwd(){
if(input('?post.regEmail') && !empty(input('post.regEmail'))){
$findAction = User::findPwd(input('post.regEmail'),input('post.captchaCode'));
if ($findAction[0]){
return json(['code' => '200','message' => $findAction[1]]);
}else{
return json(['code' => '1','message' => $findAction[1]]);
}
}else{
return json(['code' => '1','message' => "信息不完整"]);
}
}
/**
* [Login description]
*/
public function Login(){
if(input('?post.userMail') && input('?post.userPass')){
$logAction = User::login(input('post.userMail'),input('post.userPass'),input('post.captchaCode'));
if ($logAction[0]){
return json(['code' => '200','message' => '登陆成功']);
}else{
return json(['code' => '1','message' => $logAction[1]]);
}
}else{
return json(['code' => '1','message' => "信息不完整"]);
}
}
/**
* [LogOut description]
*/
public function LogOut(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->userObj->clear();
$this->redirect("/Login",302);
}
public function Memory(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->userObj->getMemory();
}
public function LoginForm(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->isLoginStatusCheck();
return view('login', [
'options' => Option::getValues(['basic']),
'RegOptions' => Option::getValues(['register','login']),
'loginStatus' => $this->userObj->loginStatus,
]);
}
public function TwoStepCheck(){
$checkCode = input("post.code");
if(empty($checkCode)){
return json(['code' => '1','message' => "验证码不能为空"]);
}
$userId = session("user_id_tmp");
$userData = Db::name('users')->where('id',$userId)->find();
$ga = new PHPGangsta_GoogleAuthenticator();
$checkResult = $ga->verifyCode($userData["two_step"], $checkCode, 2);
if($checkResult) {
cookie('user_id',session("user_id_tmp"),604800);
cookie('login_status',session("login_status_tmp"),604800);
cookie('login_key',session("login_key_tmp"),604800);
return json(['code' => '200','message' => '登陆成功']);
}else{
return json(['code' => '1','message' => "验证失败"]);
}
}
public function TwoStep(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->isLoginStatusCheck();
return view('two_step', [
'options' => Option::getValues(['basic']),
'RegOptions' => Option::getValues(['register','login']),
'loginStatus' => $this->userObj->loginStatus,
]);
}
public function setWebdavPwd(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->loginStatusCheck();
Db::name("users")->where("id",$this->userObj->uid)
->update([
"webdav_key" => md5($this->userObj->userSQLData["user_email"].":CloudreveWebDav:".input("post.pwd")),
]);
return json(['error' => '200','msg' => '设置成功']);
}
public function emailActivate(){
$activationKey = input('param.key');
$basicOptions = Option::getValues(['basic']);
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->isLoginStatusCheck();
$activeAction = User::activicateUser($activationKey);
if($activeAction[0]){
return view('active_user', [
'options' => $basicOptions,
'loginStatus' => $this->userObj->loginStatus,
]);
}else{
$this->error($activeAction[1],403,$basicOptions);
}
}
public function resetPwd(){
$resetKey = input('param.key');
$userId = input('get.uid');
$basicOptions = Option::getValues(['basic']);
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->isLoginStatusCheck();
$resetAction = User::resetUser($resetKey,$userId);
if($resetAction[0]){
return view('reset_user', [
'options' => $basicOptions,
'loginStatus' => $this->userObj->loginStatus,
'key' => $resetKey."_".$userId,
]);
}else{
$this->error($resetAction[1],403,$basicOptions);
}
}
public function Reset(){
$newPwd = input('post.pwd');
$resetKey = input('post.key');
$resetAction = User::resetPwd($resetKey,$newPwd);
if($resetAction[0]){
return json(['code' => '200','message' => '重设成功,请前往登录页登录']);
}else{
return json(['code' => '1','message' => $resetAction[1]]);
}
}
public function Setting(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$userInfo = $this->userObj->getInfo();
$this->loginStatusCheck();
$policyList=[];
foreach (explode(",",$this->userObj->groupData["policy_list"]) as $key => $value) {
$policyList[$key] = $value;
}
$avaliablePolicy = Db::name("policy")->where("id","in",$policyList)->select();
$basicOptions = Option::getValues(['basic']);
return view('setting', [
'options' => $basicOptions,
'userInfo' => $userInfo,
'userSQL' => $this->userObj->userSQLData,
'groupData' => $this->userObj->groupData,
'loginStatus' => $this->userObj->loginStatus,
'avaliablePolicy' => $avaliablePolicy,
]);
}
public function SaveAvatar(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$file = request()->file("avatar");
$avatarObj = new Avatar(true,$file);
if(!$avatarObj->SaveAvatar()){
return json_encode($avatarObj->errorMsg);
}else{
$avatarObj->bindUser($this->userObj->uid);
return json_encode(["result" => "success"]);
}
}
public function Avatar(){
if(!input("get.cache")=="no"){
header("Cache-Control: max-age=10800");
}
$userId = input("param.uid");
$avatarObj = new Avatar(false,$userId);
$avatarImg = $avatarObj->Out(input("param.size"));
$this->redirect($avatarImg,302);
}
public function SetGravatar(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$avatarObj = new Avatar(false,$this->userObj->uid);
$avatarObj->setGravatar();
}
public function Nick(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$userInfo = $this->userObj->getInfo();
$this->loginStatusCheck();
$saveAction = $this->userObj->changeNick(input("post.nick"));
if($saveAction[0]){
return json(['error' => '200','msg' => '设置成功']);
}else{
return json(['error' => '1','msg' => $saveAction[1]]);
}
}
public function HomePage(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$userInfo = $this->userObj->getInfo();
$this->loginStatusCheck();
$saveAction = $this->userObj->homePageToggle(input("post.status"));
if($saveAction[0]){
return json(['error' => '200','msg' => '设置成功']);
}else{
return json(['error' => '1','msg' => $saveAction[1]]);
}
}
public function EnableTwoFactor(){
$twoFactor = new TwoFactor();
$twoFactor->qrcodeRender();
}
public function TwoFactorConfirm(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$userInfo = $this->userObj->getInfo();
$this->loginStatusCheck();
$twoFactor = new TwoFactor();
$confirmResult = $twoFactor->confirmCode(session("two_factor_enable"),input("post.code"));
if($confirmResult[0]){
$twoFactor->bindUser($this->userObj->uid);
return json(['error' => '200','msg' => '设置成功']);
}else{
return json(['error' => '1','msg' => $confirmResult[1]]);
}
}
public function ChangePwd(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$userInfo = $this->userObj->getInfo();
$this->loginStatusCheck();
$changeAction = $this->userObj->changePwd(input("post.origin"),input("post.new"));
if($changeAction[0]){
return json(['error' => '200','msg' => '设置成功']);
}else{
return json(['error' => '1','msg' => $changeAction[1]]);
}
}
private function loginStatusCheck($login=true){
if(!$this->userObj->loginStatus){
if($login){
$this->redirect(url('/Login','',''));
}else{
$this->redirect(url('/Home','',''));
}
exit();
}
}
private function isLoginStatusCheck(){
if($this->userObj->loginStatus){
$this->redirect(url('/Home','',''));
exit();
}
}
}
+80
View File
@@ -0,0 +1,80 @@
<?php
namespace app\index\controller;
use think\Controller;
use app\index\model\User;
use think\Cookie;
use think\Db;
use \app\index\model\Option;
class Profile extends Controller{
public $visitorObj;
public $userObj;
public $siteOptions;
public function _initialize(){
$this->siteOptions = Option::getValues(["basic"]);
}
public function index(){
$this->visitorObj = new User(cookie('user_id'),cookie('login_key'));
$userId = (string)input("param.uid");
$userData = Db::name("users")->where("id",$userId)->find();
if (empty($userId) || empty($userData) || $userData["profile"] == 0){
$this->error('用户主页不存或者用户关闭了个人主页',404,$this->siteOptions);
}
$groupData = Db::name("groups")->where("id",$userData["user_group"])->find();
$shareCount = Db::name('shares')
->where('owner',$userId)
->where('type',"public")
->count();
$regDays = (int)((time()-strtotime($userData["user_date"]))/86400);
switch (input("get.type")) {
case 'all':
$list = Db::name('shares')
->where('owner',$userId)
->where('type',"public")
->order('id DESC')
->paginate(10);
break;
case 'hot':
$num = Option::getValue("hot_share_num");
$list = Db::name('shares')
->where('owner',$userId)
->where('type',"public")
->paginate($num);
break;
default:
$list = Db::name('shares')
->where('owner',$userId)
->where('type',"public")
->order('id DESC')
->paginate(10);
break;
}
$listData = $list->all();
foreach ($listData as $key => $value) {
if($value["source_type"]=="file"){
$listData[$key]["fileData"] = Db::name('files')->where('id',$value["source_name"])->find()["orign_name"];
}else{
$pathDir = explode("/",$value["source_name"]);
$listData[$key]["fileData"] = end($pathDir);
}
}
return view("profile",[
"options" => $this->siteOptions,
'loginStatus' => $this->visitorObj->loginStatus,
'userInfo' => $userData,
'userData' => $this->visitorObj->userSQLData,
'groupData' => $groupData,
'list' => $listData,
'listOrigin' => $list,
'type' => input("get.type"),
'shareCount' => $shareCount,
'regDays' => $regDays,
]);
}
}
+185
View File
@@ -0,0 +1,185 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use \app\index\model\Option;
use \app\index\model\User;
use \app\index\model\ShareHandler;
use think\Session;
use think\Request;
class Share extends Controller{
public $userObj;
public $siteOptions;
public function _initialize(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
$this->siteOptions = Option::getValues(["basic"]);
}
public function index(){
$shareKey = input('param.key');
$shareObj = new ShareHandler($shareKey);
if(!$shareObj->querryStatus){
header('HTTP/1.1 404 Not Found');
$this->error('当前分享不存在或者已经失效',404,$this->siteOptions);
}
if(!$shareObj->lockStatus){
$shareObj->numIncrease("view_num");
if($shareObj->shareData["source_type"] == "dir"){
return view('share_dir', [
'options' => Option::getValues(['basic','share']),
'userInfo' => $shareObj->shareOwner->userSQLData,
'dirData' => $shareObj->dirData,
'shareData' => $shareObj->shareData,
'loginStatus' => $this->userObj->loginStatus,
'userData' => $this->userObj->userSQLData,
'groupData' => $shareObj->shareOwner->groupData,
'allowPreview' => Option::getValue("allowdVisitorDownload"),
]);
}else{
return view('share_single', [
'options' => Option::getValues(['basic','share']),
'userInfo' => $shareObj->shareOwner->userSQLData,
'fileData' => $shareObj->fileData,
'shareData' => $shareObj->shareData,
'loginStatus' => $this->userObj->loginStatus,
'userData' => $this->userObj->userSQLData,
'allowPreview' => Option::getValue("allowdVisitorDownload"),
]);
}
}else{
return view('share_lock', [
'options' => Option::getValues(['basic','share']),
'userInfo' => $shareObj->shareOwner->userSQLData,
'fileData' => $shareObj->fileData,
'shareData' => $shareObj->shareData,
'loginStatus' => $this->userObj->loginStatus,
'userData' => $this->userObj->userSQLData,
'pwd' => input("?get.pwd") ? input("get.pwd") : "",
]);
}
}
public function getDownloadUrl(){
$shareId = input('key');
$shareObj = new ShareHandler($shareId,false);
return $shareObj->getDownloadUrl($this->userObj);
}
public function Download(){
$shareId = input('param.key');
$filePath = input('get.path');
$shareObj = new ShareHandler($shareId,false);
if(empty($filePath)){
$DownloadHandler = $shareObj->Download($this->userObj);
}else{
$DownloadHandler = $shareObj->DownloadFolder($this->userObj,$filePath);
}
if($DownloadHandler[0]){
$this->redirect($DownloadHandler[1],302);
}else{
$this->error($DownloadHandler[1],404,$this->siteOptions);
}
}
public function chekPwd(){
$shareId = input('key');
$inputPwd = input('password');
$shareObj = new ShareHandler($shareId,false);
if(!$shareObj->querryStatus){
return array(
"error" => 1,
"msg" => "分享不存在"
);
}
return $shareObj->checkPwd($inputPwd);
}
public function Preview(){
$shareId = input('param.key');
$filePath = input('get.path');
$shareObj = new ShareHandler($shareId,false);
if(empty($filePath)){
$previewHandler = $shareObj->Preview($this->userObj);
}else{
if(!empty(input('get.folder'))){
$previewHandler = $shareObj->PreviewFolder($this->userObj,$filePath,true);
}else{
$previewHandler = $shareObj->PreviewFolder($this->userObj,$filePath);
}
}
if($previewHandler[0]){
$this->redirect($previewHandler[1],302);
}else{
$this->error($previewHandler[1],404,$this->siteOptions);
}
}
public function ListFile(){
$shareId = input('param.key');
$reqPathTo = stripslashes(json_decode(file_get_contents("php://input"),true)['path']);
$shareObj = new ShareHandler($shareId,false);
return $shareObj->ListFile($reqPathTo);
}
public function ListPic(){
$filePath = input('get.path');
$shareId = input('get.id');
$shareObj = new ShareHandler($shareId,false);
return $shareObj->listPic($shareId,$filePath);
}
public function Delete(){
$shareId = input('post.id');
$shareObj = new ShareHandler($shareId,false);
if(!$shareObj->querryStatus){
return array(
"error" => 1,
"msg" => "分享不存在"
);
}
return $shareObj->deleteShare($this->userObj->uid);
}
public function ChangePromission(){
$shareId = input('post.id');
$shareObj = new ShareHandler($shareId,false);
if(!$shareObj->querryStatus){
return array(
"error" => 1,
"msg" => "分享不存在"
);
}
return $shareObj->changePromission($this->userObj->uid);
}
public function My(){
if(!$this->userObj->loginStatus){
$this->redirect(url('/Login','',''));
exit();
}
$userInfo = $this->userObj->getInfo();
$groupData = $this->userObj->getGroupData();
$list = Db::name('shares')->where('owner',$this->userObj->uid)->paginate(10);
$listData = $list->all();
foreach ($listData as $key => $value) {
if($value["source_type"]=="file"){
$listData[$key]["fileData"] = Db::name('files')->where('id',$value["source_name"])->find()["orign_name"];
}else{
$listData[$key]["fileData"] = $value["source_name"];
}
}
return view('share_home', [
'options' => Option::getValues(['basic','share']),
'userInfo' => $userInfo,
'groupData' => $groupData,
'list' => $listData,
'listOrigin' => $list
]);
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\Request;
use \app\index\model\Option;
use \app\index\model\User;
use \app\index\model\UploadHandler;
use think\Session;
class Upload extends Controller{
public $userObj;
public function _initialize(){
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
if(!$this->userObj->loginStatus){
echo "Bad request";
exit();
}
}
public function index(){
ob_end_clean();
$file = request()->file('file');
$fileInfo = Request::instance()->request();
$UploadHandler = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
return $UploadHandler->fileReceive($file,$fileInfo);
}
public function Token(){
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
$upToken = $uploadObj->getToken();
if(!empty($uploadObj->upyunPolicy)){
return json([
"token" => $upToken,
"policy" => $uploadObj->upyunPolicy,
]);
}
if(!empty($uploadObj->s3Policy)){
return json([
"policy" => $uploadObj->s3Policy,
"sign" => $uploadObj->s3Sign,
"key" => $uploadObj->dirName,
"credential" => $uploadObj->s3Credential,
"x_amz_date" => $uploadObj->x_amz_date,
"siteUrl"=>$uploadObj->siteUrl,
"callBackKey" => $uploadObj->callBackKey,
]);
}
if(!$uploadObj->getToken()){
return json([
"uptoken" => $uploadObj->ossToken,
"sign" => $uploadObj->ossSign,
"id" => $uploadObj->ossAccessId,
"key" => $uploadObj->ossFileName,
"callback" => $uploadObj->ossCallBack,
]);
}
return json(["uptoken" => $uploadObj->getToken()]);
}
public function chunk(){
$file = file_get_contents('php://input');
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
$uploadObj->setChunk(input('param.chunk'),input('param.chunks'),$file);
}
public function mkFile(){
$ctx = file_get_contents('php://input');
$originName = UploadHandler::b64Decode(input('param.fname'));
$filePath = UploadHandler::b64Decode(input('param.path'));
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
$uploadObj->generateFile($ctx,$originName,$filePath);
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use \app\index\model\Option;
use \app\index\model\User;
use \app\index\model\Directory;
use \app\index\model\Objects;
use \app\index\model\DavAuth;
use \app\index\model\BasicCallBack;
use Sabre\DAV;
use Sabre\DAV\Auth;
class WebDav extends Controller{
public $userObj;
public $uid;
public function index(){
}
public function Api(){
$this->uid = input("param.uid");
$publicDir = new Directory($this->uid."/");
$server = new DAV\Server($publicDir);
$server->setBaseUri('/WebDav/Api/uid/'.$this->uid);
$lockBackend = new DAV\Locks\Backend\File(ROOT_PATH.'public/locks');
$lockPlugin = new DAV\Locks\Plugin($lockBackend);
$server->addPlugin($lockPlugin);
$check = new DavAuth($this->uid);
$callBack = new BasicCallBack($check);
$authPlugin = new Auth\Plugin($callBack);
$server->addPlugin($authPlugin);
$server->addPlugin(new DAV\Browser\Plugin());
$server->addPlugin(new \Sabre\DAV\Browser\GuessContentType());
ob_end_clean();
$server->exec();
}
}
+668
View File
@@ -0,0 +1,668 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \app\index\model\Mail;
use \app\index\model\FileManage;
class AdminHandler extends Model{
public $siteOptions;
public $pageData;
public $listData;
public $pageNow;
public $pageTotal;
public $dataTotal;
public $dbVerInfo;
public function __construct($options){
$this->siteOptions = $options;
}
public function checkDbVersion(){
$versionInfo = json_decode(@file_get_contents(ROOT_PATH. "application/version.json"),true);
$dbVerNow = Option::getValue("database_version");
if(!isset($versionInfo["db_version"]) || $dbVerNow < (int)$versionInfo["db_version"]){
$this->dbVerInfo = array('now' => $dbVerNow, 'require' => $versionInfo["db_version"]);
return true;
}
return false;
}
public function getStatics(){
$statics["fileNum"] = Db::name('files')->count();
$statics["privateShareNum"] = Db::name('shares')->where("type","private")->count();
$statics["publicShareNum"] = Db::name('shares')->where("type","public")->count();
$statics["userNum"] = Db::name('users')->where("user_status",0)->count();
if($statics["fileNum"]==0){
$statics["imgRate"] = 0;
$statics["audioRate"] = 0;
$statics["videoRate"] = 0;
$statics['otherRate'] = 0;
}else{
$statics["imgRate"] =floor(Db::name('files')
->where('pic_info',"<>"," ")
->where('pic_info',"<>","0,0")
->where('pic_info',"<>","null,null")
->count()/$statics["fileNum"]*10000)/100;
$statics["audioRate"] =floor(Db::name('files')
->where(function ($query) {
$query->where('orign_name', "like","%mp3")
->whereor('orign_name', "like","%flac")
->whereor('orign_name', "like","%wma")
->whereor('orign_name', "like","%aac")
->whereor('orign_name', "like","%wav")
->whereor('orign_name', "like","%ogg");
})
->count()/$statics["fileNum"]*10000)/100;
$statics["videoRate"] =floor(Db::name('files')
->where(function ($query) {
$query->where('orign_name', "like","%mp4")
->whereor('orign_name', "like","%avi")
->whereor('orign_name', "like","%rmvb")
->whereor('orign_name', "like","%aac")
->whereor('orign_name', "like","%wav")
->whereor('orign_name', "like","%mkv");
})
->count()/$statics["fileNum"]*10000)/100;
$statics['otherRate'] = 100-($statics["videoRate"]+$statics["audioRate"]+$statics["imgRate"]);
}
$timeNow=time();
$statics["trendFile"]="";
$statics["trendUser"]="";
$statics["trendDate"]="";
for ($i=0; $i < 13; $i++) {
$statics["trendFile"].= Db::name('files')->where('upload_date','between time',[date("Y-m-d",$timeNow-(12-$i)*3600*24),date("Y-m-d",$timeNow-(11-$i)*3600*24)])->count().",";
}
for ($i=0; $i < 13; $i++) {
$statics["trendUser"].= Db::name('users')->where('user_date','between time',[date("Y-m-d",$timeNow-(12-$i)*3600*24),date("Y-m-d",$timeNow-(11-$i)*3600*24)])->count().",";
}
for ($i=0; $i < 13; $i++) {
$statics["trendDate"].='"'.date("m月d日",$timeNow-(12-$i)*3600*24).'",';
}
$statics["trendFile"] = rtrim($statics["trendFile"],",");
$statics["trendDate"] = rtrim($statics["trendDate"],",");
$statics["trendUser"] = rtrim($statics["trendUser"],",");
return $statics;
}
public function saveBasicSetting($options){
$siteUrl = rtrim($options["siteURL"],"/")."/";
$options["siteURL"]=$siteUrl;
return $this->saveOptions($options);
}
public function saveRegSetting($options){
foreach(["email_active","login_captcha","reg_captcha","forget_captcha"] as $key){
$options[$key] = array_key_exists($key,$options) ? $options[$key] : 0;
}
return $this->saveOptions($options);
}
public function saveMailSetting($options){
return $this->saveOptions($options);
}
public function saveMailTemplate($options){
return $this->saveOptions($options);
}
public function AddGroup($options){
$options["max_storage"] = $options["max_storage"]*$options["sizeTimes"];
unset($options["sizeTimes"]);
$options["grade_policy"] = 0;
$options["policy_list"] = $options["policy_name"];
try {
Db::name("groups")->insert($options);
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function addPolicy($options){
$options["max_size"] = $options["max_size"]*$options["sizeTimes"];
unset($options["sizeTimes"]);
$options["server"] = isset($options["server"]) ? $options["server"] : "/Upload";
foreach (["bucketname","bucket_private","bucketname","ak","sk","op_name","op_pwd","mimetype","namerule"] as $key => $value) {
$options[$value] = isset($options[$value]) ? $options[$value] : "0";
}
if(empty($options["filetype"])){
$options["filetype"]="[]";
}else{
$options["filetype"] = json_encode([0=>["ext"=>$options["filetype"],"title"=>"default"]]);
}
if($options["policy_type"] == "upyun"){
$options["server"] = "https://v0.api.upyun.com/".$options["bucketname"];
}
try {
Db::name("policy")->insert($options);
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function editPolicy($options){
$policyId = $options["id"];
$options["max_size"] = $options["max_size"]*$options["sizeTimes"];
unset($options["sizeTimes"]);
unset($options["id"]);
if(empty($options["filetype"])){
$options["filetype"]="[]";
}else{
$options["filetype"] = json_encode([0=>["ext"=>$options["filetype"],"title"=>"default"]]);
}
try {
Db::name("policy")->where("id",$policyId)->update($options);
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function saveGroup($options){
$groupId = $options["id"];
unset($options["id"]);
$options["max_storage"] = $options["max_storage"]*$options["sizeTimes"];
unset($options["sizeTimes"]);
try {
Db::name("groups")->where("id",$groupId)->update($options);
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function saveOptions($options){
try {
foreach ($options as $key => $value) {
Db::name("options")->where("option_name",$key)->update(["option_value"=>$value]);
}
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function getAvaliableGroup(){
$groupData = Db::name("groups")->where("id","neq",2)->select();
return $groupData;
}
public function saveCron($options){
$cronId = $options["id"];
unset($options["id"]);
Db::name("corn")->where("id",$cronId)->update($options);
}
public function getAvaliablePolicy(){
$policyData = Db::name("policy")->select();
return $policyData;
}
public function sendTestMail($options){
$mailObj = new Mail();
if(empty($options["receiveMail"])){
return ["error"=>1,"msg"=>"接收邮箱不能为空"];
}
$sendResult = $mailObj->Send($options["receiveMail"],"发信测试",$options["subject"],$options["content"]);
if($sendResult){
return ["error"=>200,"msg"=>"发送成功"];
}else{
return ["error"=>1,"msg"=>$mailObj->errorMsg];
}
}
public function deleteSingle($id){
$fileRecord = Db::name("files")->where("id",$id)->find();
return FileManage::DeleteHandler([0 => rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"]],$fileRecord["upload_user"]);
}
public function deletePolicy($id){
$groupData = Db::name("groups")->where("policy_name",$id)->select();
if(!empty($groupData)){
return ["error"=>true,"msg"=>"此上传策略正在被以下用户组使用:".join(",",array_column($groupData, "group_name"))];
}
Db::name("policy")->where("id",$id)->delete();
return ["error"=>false,"msg"=>"已删除"];
}
public function deleteGroup($id){
$userData = Db::name("users")->where("user_group",$id)->find();
if(!empty($userData)){
return ["error"=>true,"msg"=>"此用户组下仍有用户,请先删除这些用户"];
}
if($id == 1 || $id == 2){
return ["error"=>true,"msg"=>"系统保留用户组,无法删除"];
}
Db::name("groups")->where("id",$id)->delete();
return ["error"=>false,"msg"=>"已删除"];
}
public function getConfigFile($type){
switch ($type) {
case 'common':
$configPath = ROOT_PATH ."application/config.php";
$basicPath = "application/config.php";
break;
case 'database':
if(file_exists( ROOT_PATH ."application/database.lock")){
return ["出于安全考虑,默认禁止直接编辑数据库配置文件。如果需要开启编辑,请手动删除 application/database.lock 文件。","application/database.php"];
}
$configPath = ROOT_PATH ."application/database.php";
$basicPath = "application/database.php";
break;
case 'route':
$configPath = ROOT_PATH ."application/route.php";
$basicPath = "application/route.php";
break;
case 'tags':
$configPath = ROOT_PATH ."application/tags.php";
$basicPath = "application/tags.php";
break;
default:
die("");
break;
}
return [file_get_contents($configPath),$basicPath];
}
public function saveConfigFile($options){
switch ($options["type"]) {
case 'common':
file_put_contents(ROOT_PATH ."application/config.php",$options["content"]);
break;
case 'route':
file_put_contents(ROOT_PATH ."application/route.php",$options["content"]);
break;
case 'tags':
file_put_contents(ROOT_PATH ."application/tags.php",$options["content"]);
break;
case 'database':
if(file_exists( ROOT_PATH ."application/database.lock")){
return ["error"=>true,"msg"=>"出于安全考虑,默认禁止直接编辑数据库配置文件。如果需要开启编辑,请手动删除 application/database.lock 文件。"];
}
file_put_contents(ROOT_PATH ."application/database.php",$options["content"]);
break;
default:
# code...
break;
}
return ["error"=>false,"msg"=>""];
}
public function deleteMultiple($id){
$fileInfo = json_decode($id,true);
$pathGroup = [];
foreach ($fileInfo as $key => $value) {
$pathGroup[$value["uid"]] = isset($pathGroup[$value["uid"]]) ? $pathGroup[$value["uid"]] : [];
array_push($pathGroup[$value["uid"]], $value["path"]);
}
foreach ($pathGroup as $key => $value) {
FileManage::DeleteHandler($value,$key);
}
return ["error"=>200,"msg"=>"删除成功"];
}
public function deleteShare($ids){
Db::name("shares")->where("id","in",$ids)->delete();
return ["error"=>false,"msg"=>"删除成功"];
}
public function deleteOrder($id){
Db::name("order")->where("id",$id)->delete();
return ["error"=>false,"msg"=>"删除成功"];
}
public function deleteUser($id,$userNow){
if($userNow == $id){
return ["error"=>true,"msg"=>"我的老伙计,你可不能删除你自己"];
}
//删除用户所有文件及目录
FileManage::DirDeleteHandler([0 => "/"],$id);
//删除此用户所有分享
Db::name("shares")->where("owner",$id)->delete();
//删除此用户
Db::name("users")->where("id",$id)->delete();
return ["error"=>false,"msg"=>"删除成功"];
}
public function changeShareType($id){
$shareId = $id;
$shareObj = new ShareHandler($shareId,false);
if(!$shareObj->querryStatus){
return array(
"error" => 1,
"msg" => "分享不存在"
);
}
return $shareObj->changePromission(0,true);
}
public function getUserInfo($id){
$userData = Db::name("users")->where("id",$id)->find();
$userData["used_storage"] =getSize($userData["used_storage"]);
return $userData;
}
public function listFile(){
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
$orderType = empty(cookie('orderMethodFile')) ? "id DESC" : cookie('orderMethodFile');
$this->pageData = Db::name("files")
->where(function ($query) {
if(!empty(cookie('fileSearch'))){
$query->where('orign_name', "like","%".cookie('fileSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('filePolicy'))){
$query->where('policy_id', cookie('filePolicy'));
}
})
->where(function ($query) {
if(!empty(cookie('searchValue'))){
$query->where(cookie('searchCol'),"like", cookie('searchValue'));
}
})
->order($orderType)
->paginate($pageSize);
$this->dataTotal = Db::name("files")
->where(function ($query) {
if(!empty(cookie('fileSearch'))){
$query->where('orign_name', "like","%".cookie('fileSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('filePolicy'))){
$query->where('policy_id', cookie('filePolicy'));
}
})
->where(function ($query) {
if(!empty(cookie('searchValue'))){
$query->where(cookie('searchCol'),"like", cookie('searchValue'));
}
})
->order($orderType)
->count();
$this->pageTotal = ceil($this->dataTotal/$pageSize);
$this->listData = $this->pageData->all();
$userCache=[];
$userCacheList=[];
foreach ($this->listData as $key => $value) {
if(in_array($value["upload_user"], $userCacheList)){
$this->listData[$key]["user"] = $userCache[$value["upload_user"]];
}else{
$this->listData[$key]["user"] = Db::name("users")->where("id",$value["upload_user"])->find();
array_push($userCacheList,$value["upload_user"]);
$userCache[$value["upload_user"]] = $this->listData[$key]["user"];
}
}
$this->pageNow = input("?get.page")?input("get.page"):1;
}
public function listUser(){
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
$orderType = empty(cookie('orderMethodUser')) ? "id DESC" : cookie('orderMethodUser');
$this->pageData = Db::name("users")
->where(function ($query) {
if(!empty(cookie('userStatus'))){
$query->where('user_status', cookie('userStatus')-1);
}
})
->where(function ($query) {
if(!empty(cookie('userSearch'))){
$query->where('user_nick', "like","%".cookie('userSearch')."%")
->whereOr("id",cookie('userSearch'))
->whereOr("user_email","like","%".cookie('userSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('userGroup'))){
$query->where('user_group', cookie('userGroup'));
}
})
->where(function ($query) {
if(!empty(cookie('searchValueUser'))){
$query->where(cookie('searchColUser'),"like", cookie('searchValueUser'));
}
})
->order($orderType)
->paginate($pageSize);
$this->dataTotal = Db::name("users")
->where(function ($query) {
if(!empty(cookie('userStatus'))){
$query->where('user_status', cookie('userStatus')-1);
}
})
->where(function ($query) {
if(!empty(cookie('userSearch'))){
$query->where('user_nick', "like","%".cookie('userSearch')."%")
->whereOr("id",cookie('userSearch'))
->whereOr("user_email","like","%".cookie('userSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('userGroup'))){
$query->where('user_group', cookie('userGroup'));
}
})
->where(function ($query) {
if(!empty(cookie('searchValueUser'))){
$query->where(cookie('searchColUser'),"like", cookie('searchValueUser'));
}
})
->order($orderType)
->count();
$this->pageTotal = ceil($this->dataTotal/$pageSize);
$this->listData = $this->pageData->all();
$groupCache=[];
$groupCacheList=[];
foreach ($this->listData as $key => $value) {
if(in_array($value["user_group"], $groupCacheList)){
$this->listData[$key]["group"] = $groupCache[$value["user_group"]];
}else{
$this->listData[$key]["group"] = Db::name("groups")->where("id",$value["user_group"])->find();
array_push($groupCacheList,$value["user_group"]);
$groupCache[$value["user_group"]] = $this->listData[$key]["group"];
}
}
$this->pageNow = input("?get.page")?input("get.page"):1;
}
public function listShare(){
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
$orderType = empty(cookie('orderMethodShare')) ? "id DESC" : cookie('orderMethodShare');
$this->pageData = Db::name("shares")
->where(function ($query) {
if(!empty(cookie('shareSearch'))){
$query->where('source_name', "like","%".cookie('shareSearch')."%")->whereOr('origin_name', "like","%".cookie('shareSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('shareType'))){
$query->where('type', cookie('shareType'));
}
})
->order($orderType)
->paginate($pageSize);
$this->dataTotal = Db::name("shares")
->where(function ($query) {
if(!empty(cookie('shareSearch'))){
$query->where('source_name', "like","%".cookie('shareSearch')."%")->whereOr('origin_name', "like","%".cookie('shareSearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('shareType'))){
$query->where('type', cookie('shareType'));
}
})
->order($orderType)
->count();
$this->pageTotal = ceil($this->dataTotal/$pageSize);
$this->listData = $this->pageData->all();
$userCache=[];
$userCacheList=[];
foreach ($this->listData as $key => $value) {
if(in_array($value["owner"], $userCacheList)){
$this->listData[$key]["user"] = $userCache[$value["owner"]];
}else{
$this->listData[$key]["user"] = Db::name("users")->where("id",$value["owner"])->find();
array_push($userCacheList,$value["owner"]);
$userCache[$value["owner"]] = $this->listData[$key]["user"];
}
}
$this->pageNow = input("?get.page")?input("get.page"):1;
}
public function listPolicy(){
$pageSize =!cookie('?pageSize') ? 10 : cookie('pageSize');
$this->pageData = Db::name("policy")
->where(function ($query) {
if(!empty(cookie('policySearch'))){
$query->where('policy_name', "like","%".cookie('policySearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('policyType'))){
$query->where('policy_type', cookie('policyType'));
}
})
->order("id DESC")
->paginate($pageSize);
$this->dataTotal = Db::name("policy")
->where(function ($query) {
if(!empty(cookie('policySearch'))){
$query->where('policy_name', "like","%".cookie('policySearch')."%");
}
})
->where(function ($query) {
if(!empty(cookie('policyType'))){
$query->where('policy_type', cookie('policyType'));
}
})
->order("id DESC")
->count();
$this->pageTotal = ceil($this->dataTotal/$pageSize);
$this->listData = $this->pageData->all();
$this->pageNow = input("?get.page")?input("get.page"):1;
foreach ($this->listData as $key => $value) {
$this->listData[$key]["file_num"] = Db::name("files")->where("policy_id",$value["id"])->count();
$this->listData[$key]["file_size"] = Db::name("files")->where("policy_id",$value["id"])->sum("size");
}
}
public function getFileInfo($id){
$fileRecord = Db::name("files")->where("id",$id)->find();
$policyRecord = Db::name("policy")->where("id",$fileRecord["policy_id"])->find();
$fileRecord["policy"] = $policyRecord;
return $fileRecord;
}
public function saveThemeFile($options){
$fileName=$options["name"];
$dir = ROOT_PATH."application/index/view/";
$fileList=[];
$fileList=$fileList+scandir($dir);
$pathList=["/"=>$fileList];
foreach (["admin","explore","file","home","index","member","profile","share"] as $key => $value) {
$childPath = scandir($dir.$value."/");
$fileList=array_merge($fileList,$childPath);
$pathList = array_merge($pathList,[$value => $childPath]);
}
foreach ($fileList as $key => $value) {
if(substr_compare($value, ".html", -strlen(".html")) != 0){
unset($fileList[$key]);
}
}
foreach($pathList as $key=>$val){
if(in_array($fileName.".html",$val)){
$parentPath = $key;
break;
}
}
file_put_contents($dir.rtrim($parentPath,"/")."/".$fileName.".html",$options["content"]);
return ["error"=>false,"msg"=>"成功"];
}
public function saveUser($options){
if(empty($options["user_pass"])){
unset($options["user_pass"]);
}else{
$options["user_pass"] = md5(config('salt').$options["user_pass"]);
}
$userId = $options["uid"];
unset($options["uid"]);
try {
Db::name("users")->where("id",$userId)->update($options);
} catch (Exception $e) {
return ["error"=>1,"msg"=>$e->getMessage()];
}
return ["error"=>200,"msg"=>"设置已保存"];
}
public function banUser($id,$uid){
if($id == $uid){
return ["error"=>1,"msg"=>"我的老伙计,你怎么能封禁你自己?"];
}
$userData = Db::name("users")->where("id",$id)->find();
$statusNew = $userData["user_status"] == 1 ? 0 : 1;
Db::name("users")->where("id",$id)->update(["user_status" => $statusNew]);
return ["error"=>200,"msg"=>"设置已保存"];
}
public function listGroup(){
$pageSize = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
$this->pageData = Db::name("groups")
->order("id DESC")
->paginate($pageSize);
$this->dataTotal = Db::name("groups")
->order("id DESC")
->count();
$this->pageTotal = ceil($this->dataTotal/$pageSize);
$this->listData = $this->pageData->all();
$this->pageNow = input("?get.page")?input("get.page"):1;
foreach ($this->listData as $key => $value) {
$this->listData[$key]["policy"] = Db::name("policy")->where("id",$value["policy_name"])->find();
$this->listData[$key]["user_num"] = Db::name("users")->where("user_group",$value["id"])->count();
}
}
public function addUser($options){
$options["user_pass"] = md5(config('salt').$options["user_pass"]);
if(Db::name('users')->where('user_email',$options["user_email"])->find() !=null){
return ["error" => true,"msg"=>"该邮箱已被注册"];
}
$sqlData = [
'user_email' => $options["user_email"],
'user_pass' => $options["user_pass"],
'user_status' => $options["user_status"],
'user_group' => $options["user_group"],
'group_primary' => $options["user_group"],
'user_date' => date("Y-m-d H:i:s"),
'user_nick' => $options["user_nick"],
'user_activation_key' => "n",
'used_storage' => 0,
'two_step'=>"0",
'webdav_key' =>$options["user_pass"],
'delay_time' =>0,
'avatar' => "default",
'profile' => true,
];
if(Db::name('users')->insert($sqlData)){
$userId = Db::name('users')->getLastInsID();
Db::name('folders')->insert( [
'folder_name' => '根目录',
'parent_folder' => 0,
'position' => '.',
'owner' => $userId,
'date' => date("Y-m-d H:i:s"),
'position_absolute' => '/',
]);
}
return ["error"=>0,"msg"=>"设置已保存"];
}
}
?>
+146
View File
@@ -0,0 +1,146 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \app\index\model\Option;
use \app\index\model\FileManage;
class Avatar extends Model{
public $avatarObj;
public $errorMsg;
public $fileName;
public $avatarKey;
public $userData;
public $avatarType;
public function __construct($new=false,$obj){
$this->avatarObj = $obj;
if(!$new){
$userData = Db::name("users")->where('id',$obj)->find();
$this->userData = $userData;
if($userData["avatar"] == "default"){
$this->avatarType = "default";
}else{
$avatarPrarm = explode(".",$userData["avatar"]);
$this->avatarType = $avatarPrarm[0];
$this->fileName = ltrim(ltrim($userData["avatar"],"g."),"f.");
}
}
}
public function SaveAvatar(){
$info = $this->avatarObj->validate(['size'=>2097152,'ext'=>'jpg,png,gif.bmp'])->rule('uniqid')->move(ROOT_PATH . 'public' . DS . 'avatars');
if($info){
$_path = ROOT_PATH.'public/avatars/'.$info->getSaveName();
$_img = new Image($_path);
$_img->thumb(200, 200);
$_img->output();
$_img = new Image($_path);
$_img->thumb(130, 130);
$_img->output("_130");
$_img = new Image($_path);
$_img->thumb(50, 50);
$_img->output("_50");
$this->fileName = $info->getSaveName();
return true;
}else{
$this->errorMsg=["result"=>"error","msg"=>$this->avatarObj->getError()];
return false;
}
}
public function bindUser($uid){
$this->avatarKey = "f.".$this->fileName;
Db::name("users")->where('id',$uid)->update(["avatar" => $this->avatarKey]);
}
public function Out($size){
switch ($this->avatarType) {
case 'f':
$this->outPutFile($size);
exit();
break;
case 'default':
$this->defaultAvatar($size);
exit();
break;
case 'g':
return $this->outGravatar($size);
break;
default:
# code...
break;
}
}
public function outPutFile($size){
switch ($size) {
case 's':
$siezSuffix = "_50";
break;
case 'm':
$siezSuffix = "_130";
break;
default:
$siezSuffix = "";
break;
}
$filePath = ROOT_PATH . 'public/avatars/' . $this->fileName.$siezSuffix;
if(file_exists($filePath)){
ob_end_clean();
header('Content-Type: '.FileManage::getMimetype($filePath));
$fileObj = fopen($filePath,"r");
while(!feof($fileObj)){
echo fread($fileObj,2097152);
}
}else{
$this->defaultAvatar($siezSuffix);
}
}
public function outGravatar($size){
switch ($size) {
case 's':
$siezSuffix = "50";
break;
case 'm':
$siezSuffix = "130";
break;
default:
$siezSuffix = "200";
break;
}
ob_end_clean();
$gravatarServer = Option::getValue("gravatar_server");
return $gravatarServer.$this->fileName."?d=mm&s=".$siezSuffix;
}
public function defaultAvatar($size){
switch ($size) {
case 's':
$siezSuffix = "_50";
break;
case 'm':
$siezSuffix = "_130";
break;
default:
$siezSuffix = "";
break;
}
ob_end_clean();
$filePath = ROOT_PATH . 'static/img/default.png' .$siezSuffix;
header('Content-Type: '.FileManage::getMimetype($filePath));
$fileObj = fopen($filePath,"r");
while(!feof($fileObj)){
echo fread($fileObj,2097152);
}
}
public function setGravatar(){
$this->avatarKey="g.".md5($this->userData["user_email"]);
Db::name("users")->where('id',$this->userData["id"])->update(["avatar" => $this->avatarKey]);
}
}
+72
View File
@@ -0,0 +1,72 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \app\index\model\Option;
class B2 extends Model{
public $policy;
private $ak;
public function __construct($policy){
$this->policy = $policy;
$akInfo = explode(":",$this->policy["ak"]);
$this->ak = $akInfo[0];
if(time()-$akInfo[1]>=86000){
$this->updateAuth();
}
}
private function updateAuth(){
$credentials = base64_encode($this->ak . ":" . $this->policy["sk"]);
$url = "https://api.backblazeb2.com/b2api/v1/b2_authorize_account";
$session = curl_init($url);
$headers = array();
$headers[] = "Accept: application/json";
$headers[] = "Authorization: Basic " . $credentials;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_HTTPGET, true);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
$server_output = curl_exec($session);
curl_close ($session);
$authInfo = json_decode($server_output,true);
Db::name("policy")->where("id",$this->policy["id"])
->update([
"ak" => $this->ak . ":" . time(),
"op_name" => $authInfo["apiUrl"],
"url" => $authInfo["downloadUrl"],
"op_pwd" => $authInfo["authorizationToken"],
]);
$this->policy = Db::name("policy")->where("id",$this->policy["id"])->find();
$this->updateUploadAuth();
}
private function updateUploadAuth(){
$session = curl_init($this->policy["op_name"] . "/b2api/v1/b2_get_upload_url");
$data = array("bucketId" => $this->policy["bucketname"]);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
$headers = array();
$headers[] = "Authorization: " . $this->policy["op_pwd"];
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
curl_setopt($session, CURLOPT_POST, true);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($session);
curl_close ($session);
$authInfo = json_decode($server_output,true);
Db::name("policy")->where("id",$this->policy["id"])
->update([
"server" => $authInfo["uploadUrl"] . "|" . $authInfo["authorizationToken"],
]);
$this->policy = Db::name("policy")->where("id",$this->policy["id"])->find();
die("");
}
}
?>
+39
View File
@@ -0,0 +1,39 @@
<?php
namespace app\index\model;
use think\Model;
use Sabre\DAV;
use Sabre\DAV\Auth\Backend;
class BasicCallBack extends \Sabre\DAV\Auth\Backend\AbstractDigest {
/**
* Callback
*
* @var callable
*/
protected $callBack;
/**
* Creates the backend.
*
* A callback must be provided to handle checking the username and
* password.
*
* @param callable $callBack
* @return void
*/
function __construct(callable $callBack) {
$this->callBack = $callBack;
$this->realm = 'CloudreveWebDav';
}
public function getDigestHash($realm, $username){
$cb = $this->callBack;
return $cb($realm,$username);
}
}
+233
View File
@@ -0,0 +1,233 @@
<?php
namespace app\index\model;
require_once 'extend/Qiniu/functions.php';
use think\Model;
use think\Db;
use Qiniu\Auth;
use \app\index\model\Option;
use \app\index\model\FileManage;
use \app\index\model\UploadHandler;
class CallbackHandler extends Model{
public $CallbackData;
public $policyData;
public $userData;
public function __construct($data){
$this->CallbackData = $data;
}
public function remoteHandler($header){
$jsonData = json_decode(base64_decode($this->CallbackData),true);
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
if(!$this->IsRemoteCallback($header)){
$this->setError("Undelegated Request");
}
if($this->policyData == null){
$this->setError("CallbackKey Not Exist.");
}
if(!FileManage::sotrageCheck($CallbackSqlData["uid"],$jsonData["fsize"])){
$this->setError("空间容量不足",true);
}
$picInfo = $jsonData["picinfo"];
$addAction = FileManage::addFile($jsonData,$this->policyData,$CallbackSqlData["uid"],$picInfo);
if(!$addAction[0]){
$this->setError($addAction[1],true);
}
FileManage::storageCheckOut($CallbackSqlData["uid"],$jsonData["fsize"]);
$this->setSuccess($jsonData['fname']);
}
public function qiniuHandler($header){
$jsonData = json_decode($this->CallbackData,true);
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
if(!$this->IsQiniuCallback($header)){
$this->setError("Undelegated Request");
}
if($this->policyData == null){
$this->setError("CallbackKey Not Exist.");
}
if(!FileManage::sotrageCheck($CallbackSqlData["uid"],$jsonData["fsize"])){
$this->setError("空间容量不足",true);
}
$picInfo = $jsonData["picinfo"];
$addAction = FileManage::addFile($jsonData,$this->policyData,$CallbackSqlData["uid"],$picInfo);
if(!$addAction[0]){
$this->setError($addAction[1],true);
}
FileManage::storageCheckOut($CallbackSqlData["uid"],$jsonData["fsize"]);
$this->setSuccess($jsonData['fname']);
}
public function ossHandler($auth,$pubKey){
if(!$this->IsOssCallback($auth,$pubKey)){
$this->setError("Undelegated Request");
}
$jsonData = json_decode($this->CallbackData,true);
$jsonData["fname"] = urldecode($jsonData["fname"]);
$jsonData["objname"] = urldecode($jsonData["objname"]);
$jsonData["path"] = urldecode($jsonData["path"]);
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
if($this->policyData == null){
$this->setError("CallbackKey Not Exist.");
}
if(!FileManage::sotrageCheck($CallbackSqlData["uid"],$jsonData["fsize"])){
$this->setError("空间容量不足",true);
}
$picInfo = $jsonData["picinfo"];
$addAction = FileManage::addFile($jsonData,$this->policyData,$CallbackSqlData["uid"],$picInfo);
if(!$addAction[0]){
$this->setError($addAction[1],true);
}
FileManage::storageCheckOut($CallbackSqlData["uid"],$jsonData["fsize"]);
$this->setSuccess($jsonData['fname']);
}
public function upyunHandler($token,$date,$md5){
$this->policyData = Db::name("policy")->where("id",$this->CallbackData["ext-param"]["pid"])->find();
if(!$this->IsUpyunCallback($token,$date,$md5)){
$this->setError("Undelegated Request",false,true);
}
if(!FileManage::sotrageCheck($this->CallbackData["ext-param"]["uid"],$this->CallbackData["file_size"])){
FileManage::deleteFile($this->CallbackData["url"],$this->policyData);
$this->setError("空间容量不足",false,true);
}
$picInfo = empty($this->CallbackData["image-width"]) ? "" :$this->CallbackData["image-width"].",".$this->CallbackData["image-height"];
$fileNameExplode = explode("CLSUFF",$this->CallbackData["url"]);
$jsonData["fname"] = end($fileNameExplode);
$jsonData["objname"] = $this->CallbackData["url"];
$jsonData["path"] = $this->CallbackData["ext-param"]["path"];
$jsonData["fsize"] = $this->CallbackData["file_size"];
$addAction = FileManage::addFile($jsonData,$this->policyData,$this->CallbackData["ext-param"]["uid"],$picInfo);
if(!$addAction[0]){
FileManage::deleteFile($this->CallbackData["url"],$this->policyData);
$this->setError($addAction[1],false,true);
}
FileManage::storageCheckOut($this->CallbackData["ext-param"]["uid"],$jsonData["fsize"]);
$this->setSuccess($jsonData['fname']);
}
public function s3Handler($key){
$CallbackSqlData = Db::name('callback')->where('callback_key',$key)->find();
//删除callback记录
if(empty($CallbackSqlData)){
$this->setError("Undelegated Request",false,true);
}
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
$this->userData = Db::name('users')->where('id',$CallbackSqlData['uid'])->find();
$paths = explode("/",$this->CallbackData["key"]);
$jsonData["fname"] = end($paths);
$jsonData["objname"] = $this->CallbackData["key"];
$jsonData["path"] ="";
foreach ($paths as $key => $value) {
if($key == 0 || $key == count($paths)-1) continue;
$jsonData["path"].=$value.",";
}
$jsonData["path"] = rtrim($jsonData["path"],",");
$jsonData["fsize"] = $this->getS3FileInfo();
if(!$jsonData["fsize"]){
$this->setError("File not exist",false,true);
}
$jsonData["fsize"] = $jsonData["fsize"]["size"];
$picInfo = "";
$addAction = FileManage::addFile($jsonData,$this->policyData,$this->userData["id"],"");
if(!$addAction[0]){
FileManage::deleteFile($this->CallbackData["key"],$this->policyData);
$this->setError($addAction[1],false,true);
}
FileManage::storageCheckOut($this->userData["id"],$jsonData["fsize"]);
$this->setSuccess($jsonData['fname']);
}
private function getS3FileInfo(){
$s3 = new \S3\S3($this->policyData["ak"], $this->policyData["sk"],false,$this->policyData["op_pwd"]);
$s3->setSignatureVersion('v4');
try {
$returnVal = $s3->getObjectInfo($this->policyData["bucketname"],$this->CallbackData["key"]);
} catch (Exception $e) {
return false;
}
return $returnVal;
}
public function setSuccess($fname){
die(json_encode(["key"=> $fname]));
}
public function setError($text,$delete = false,$ignore=false){
header("HTTP/1.1 401 Unauthorized");
if(!$ignore){
$deletedFile = json_decode($this->CallbackData,true);
$fileNmae = $deletedFile['objname'];
if($delete){
FileManage::deleteFile($fileNmae,$this->policyData);
}
}
die(json_encode(["error"=> $text]));
}
private function isUpyunCallback($token,$date,$md5){
if(UploadHandler::upyunSign($this->policyData["op_name"],md5($this->policyData["op_pwd"]),"POST","/Callback/Upyun",$date,$md5) != $token){
return false;
}
return true;
}
public function IsQiniuCallback($httpHeader){
$auth = new Auth($this->policyData['ak'], $this->policyData['sk']);
$callbackBody = $this->CallbackData;
$contentType = 'application/json';
$authorization = $httpHeader;
$url = Option::getValue("siteUrl")."Callback/Qiniu";
$isQiniuCallback = $auth->verifyCallback($contentType, $authorization, $url,$callbackBody);
if ($isQiniuCallback) {
return true;
} else {
return false;
}
}
private function IsRemoteCallback($header){
$signKey = hash_hmac("sha256",$this->CallbackData,$this->policyData["sk"]);
return ($signKey == $header);
}
public function IsOssCallback($auth,$pubKey){
if (empty($auth) || empty($pubKey)){
header("http/1.1 403 Forbidden");
exit();
}
$authorization = base64_decode($auth);
$pubKeyUrl = base64_decode($pubKey);
$pubOssKey = file_get_contents($pubKeyUrl);
if ($pubOssKey == ""){
return false;
}
$body = file_get_contents('php://input');
$authStr = '';
$path = $_SERVER['REQUEST_URI'];
$pos = strpos($path, '?');
if ($pos === false){
$authStr = urldecode($path)."\n".$body;
}else{
$authStr = urldecode(substr($path, 0, $pos)).substr($path, $pos, strlen($path) - $pos)."\n".$body;
}
$ok = openssl_verify($authStr, $authorization, $pubOssKey, OPENSSL_ALGO_MD5);
if ($ok == 1){
return true;
}else{
return false;
}
}
}
?>
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \think\Session;
use \app\index\model\FileManage;
use \app\index\model\Option;
use \app\index\model\Mail;
class CronHandler extends Model{
public $cornTasks;
public $timeNow;
public $notifiedUid = [];
public function __construct(){
$this->cornTasks = Db::name('corn')->where('enable',1)->order('rank desc')->select();
$this->timeNow = time();
}
public function checkInterval($interval,$last){
return ($last+$interval)<= $this->timeNow ? true : false;
}
public function setComplete($name){
Db::name('corn')->where('name', $name)->update(['last_excute' => $this->timeNow]);
}
public function Doit(){
foreach ($this->cornTasks as $key => $value) {
switch ($value["name"]) {
case 'delete_unseful_chunks':
if($this->checkInterval($value["interval_s"],$value["last_excute"])){
$this->deleteUnsefulChunks($value["interval_s"]);
}
break;
case 'delete_callback_data':
if($this->checkInterval($value["interval_s"],$value["last_excute"])){
$this->deleteCallbackData($value["interval_s"]);
}
break;
default:
# code...
break;
}
}
}
private function deleteUnsefulChunks($interval){
echo("deleteUnsefulChunks...");
$chunkInfo = Db::name('chunks')->whereTime('time', '<', date('Y-m-d', time()-86400))->select();
$deleteList=[];
foreach ($chunkInfo as $key => $value) {
$fileSize = @filesize(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
@unlink(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
FileManage::storageGiveBack($value["user"],$fileSize?$fileSize:0);
$deleteList["$key"] = $value["id"];
}
Db::name('chunks')->where(['id' => ["in",$deleteList],])->delete();
$this->setComplete("delete_unseful_chunks");
echo("Complete<br>");
}
private function deleteCallbackData($interval){
echo("deleteCallbackData...");
Db::name("callback")->delete(true);
echo("Complete<br>");
$this->setComplete("delete_callback_data");
}
}
?>
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use app\index\model\User;
class DavAuth extends Model{
public $uid;
function __construct($id) {
$this->uid = $id;
}
public function __invoke($realm,$um){
$userData = Db::name("users")->where("id",$this->uid)->find();
if(empty($userData) || $userData["user_email"] != $um){
return null;
}
$userGroup = Db::name("groups")->where("id",$userData["user_group"])->find();
if(!$userGroup["webdav"]){
return null;
}
return $userData["webdav_key"];
}
}
?>
+186
View File
@@ -0,0 +1,186 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use Sabre\DAV;
use \app\index\model\FileManage;
use \app\index\model\User;
use \app\index\model\UploadHandler;
class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{
private $myPath;
public $uid;
public $userObj;
function __construct($path) {
$ex = explode("/",$path);
$this->uid = $ex[0];
if(empty($this->uid)){
return false;
}
$t = strpos($path,$this->uid);
if($t == 0){
$this->myPath = substr($path,$t+strlen($this->uid));
}else{
$this->myPath = $path;
}
$this->myPath = empty($this->myPath) ? "/" : $this->myPath;
}
function createFile($name, $data = NULL){
$userData = Db::name("users")->where("id",$this->uid)->find();
$groupData = Db::name("groups")->where("id",$userData["user_group"])->find();
$policyData = Db::name("policy")->where("id",$groupData["policy_name"])->find();
$uploadHandle = new UploadHandler($groupData["policy_name"],$this->uid);
$allowedExt = UploadHandler::getAllowedExt(json_decode($policyData["filetype"],true));
if(!empty($allowedExt)){
$ex = explode(".",$name);
$fileSuffix = end($ex);
if(!in_array($fileSuffix, explode(",",$allowedExt))){
throw new DAV\Exception\InvalidResourceType('File type not allowed');
}
}
if($policyData["policy_type"] !="local"){
throw new DAV\Exception\Forbidden('Poliyc not supported yet');
}
$fileSize = fstat($data)["size"];
if(empty($fileSize)){
$fileSize = 0;
}
if($fileSize>$policyData["max_size"]){
throw new DAV\Exception\InsufficientStorage('File is to large');
}
if(!FileManage::sotrageCheck($this->uid,$fileSize)){
throw new DAV\Exception\InsufficientStorage('Quota is not enough');
}
if($policyData['autoname']){
$fileName = $uploadHandle->getObjName($policyData['namerule'],"local",$name);
}else{
$fileName = $name;
}
$generatePath = $uploadHandle->getDirName($policyData['dirrule']);
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
if(!file_exists($savePath)){
mkdir($savePath,0777,true);
}
file_put_contents($savePath."/".$fileName, $data);
$jsonData = array(
"path" => str_replace("/",",",ltrim($this->myPath,"/")),
"fname" => $name,
"objname" => $generatePath."/".$fileName,
"fsize" => $fileSize,
);
@list($width, $height, $type, $attr) = getimagesize(rtrim($savePath, DS).DS.$fileName);
$picInfo = empty($width)?" ":$width.",".$height;
$addAction = FileManage::addFile($jsonData,$policyData,$this->uid,$picInfo);
if(!$addAction[0]){
unlink($savePath."/".$fileName);
throw new DAV\Exception\Conflict($addAction[1]);
}
FileManage::storageCheckOut($this->uid,$jsonData["fsize"]);
//echo json_encode(array("key" => $info["name"]));
}
function getQuotaInfo() {
$this->userObj = new User($this->uid,"",true);
$quotaInfo = json_decode($this->userObj->getMemory(true),true);
return [
$quotaInfo["used"],
$quotaInfo["total"]
];
}
function setName($name){
$reqPath = $this->myPath;
$ex = explode("/",$reqPath);
$newPath = rtrim(dirname($reqPath) == "\\" ?"/":dirname($reqPath),"/")."/".$name;
$renameAction = json_decode(FileManage::RenameHandler($reqPath,$newPath,$this->uid,true),true);
if(!$renameAction["result"]["success"]){
throw new DAV\Exception\InvalidResourceType($renameAction["result"]["error"]);
}
}
function getChildren() {
$children = array();
$fileList = Db::name('files')->where('upload_user',$this->uid)->where('dir',$this->myPath)->select();
$dirList = Db::name('folders')->where('owner',$this->uid)->where('position',$this->myPath)->select();
foreach($fileList as $node) {
// Ignoring files staring with .
$children[] = $this->getChildFile($node,false);
}
foreach($dirList as $node) {
// Ignoring files staring with .
$children[] = $this->getChildDir($node,true);
}
return $children;
}
function getChildFile($name){
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name["orign_name"];
return new Objects($path);
}
function getChildDir($name){
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name["folder_name"];
return new Directory($path);
}
function delete(){
foreach ($this->getChildren() as $child) $child->delete();
FileManage::DirDeleteHandler([0=>$this->myPath],$this->uid);
}
function getChild($name) {
if(!$this->childExists($name)){
throw new DAV\Exception\NotFound('File with name ' . $name . ' could not be located');
}
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name;
if($this->findDir(rtrim($this->myPath,"/") . '/' . $name)){
$returnObj = new Directory($path);
return $returnObj;
}else{
return new Objects($path);
}
}
function childExists($name) {
$fileObj = new Objects($this->uid.rtrim($this->myPath,"/") . '/' . $name);
if($this->findDir(rtrim($this->myPath,"/") . '/' . $name) || $fileObj->isExist){
return true;
}
return false;
}
public function findDir($path){
if($path == "/"){
return true;
}
$explode = explode("/",$path);
$dirName = end($explode);
$rootPath = rtrim($path,"/".$dirName);
$rootPath = empty($rootPath) ? "/" : $rootPath;
$dirData = Db::name('folders')->where('owner',$this->uid)->where('position',dirname($path) == "\\" ?"/":dirname($path))->where("folder_name",basename($path))->find();
if(empty($dirData)){
return false;
}
return true;
}
function getName() {
$explode = explode("/", $this->myPath);
return end($explode);
}
function createDirectory($name) {
$createAction = FileManage::createFolder($name,$this->myPath,$this->uid);
if(!$createAction["result"]["success"]){
die($this->myPath);
throw new DAV\Exception\InvalidResourceType($createAction["result"]["error"]);
}
}
}
?>
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
<?php
namespace app\index\model;
use think\Model;
class Image extends Model{
private $file; //图片地址
private $width; //图片长度
private $height; //图片长度
private $itype; //图片类型
private $img; //原图的资源句柄
private $new; //新图的资源句柄
//构造方法,初始化
public function __construct($_file) {
$this->file = $_file;
list($this->width, $this->height, $this->itype) = getimagesize($this->file);
$this->img = $this->getFromImg($this->file, $this->itype);
}
//缩略图(固定长高容器,图像等比例,扩容填充,裁剪)[固定了大小,不失真,不变形]
public function thumb($new_width = 0,$new_height = 0) {
if (empty($new_width) && empty($new_height)) {
$new_width = $this->width;
$new_height = $this->height;
}
if (!is_numeric($new_width) || !is_numeric($new_height)) {
$new_width = $this->width;
$new_height = $this->height;
}
//创建一个容器
$_n_w = $new_width;
$_n_h = $new_height;
//创建裁剪点
$_cut_width = 0;
$_cut_height = 0;
if ($this->width < $this->height) {
$new_width = ($new_height / $this->height) * $this->width;
} else {
$new_height = ($new_width / $this->width) * $this->height;
}
if ($new_width < $_n_w) { //如果新高度小于新容器高度
$r = $_n_w / $new_width; //按长度求出等比例因子
$new_width *= $r; //扩展填充后的长度
$new_height *= $r; //扩展填充后的高度
$_cut_height = ($new_height - $_n_h) / 2; //求出裁剪点的高度
}
if ($new_height < $_n_h) { //如果新高度小于容器高度
$r = $_n_h / $new_height; //按高度求出等比例因子
$new_width *= $r; //扩展填充后的长度
$new_height *= $r; //扩展填充后的高度
$_cut_width = ($new_width - $_n_w) / 2; //求出裁剪点的长度
}
$this->new = imagecreatetruecolor($_n_w,$_n_h);
imagecopyresampled($this->new,$this->img,0,0,$_cut_width,$_cut_height,$new_width,$new_height,$this->width,$this->height);
}
//加载图片,各种类型,返回图片的资源句柄
public function getFromImg($_file, $_type) {
switch ($_type) {
case 1 :
$img = imagecreatefromgif($_file);
break;
case 2 :
$img = imagecreatefromjpeg($_file);
break;
case 3 :
$img = imagecreatefrompng($_file);
break;
default:
$img = '';
}
return $img;
}
//图像输出
public function output($name = "") {
imagepng($this->new,$this->file.$name);//第二个参数为新生成的图片名
imagedestroy($this->img);
imagedestroy($this->new);
}
}
?>
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \app\index\model\Option;
use \PHPMailer\PHPMailer\PHPMailer;
use \PHPMailer\PHPMailer\Exception;
class Mail extends Model{
public $fromName;
public $fromAdress;
public $smtpHost;
public $smtpPort;
public $replyTo;
public $smtpUser;
public $smtpPass;
public $encriptionType;
public $errorMsg;
public function __construct(){
$mailOptions = Option::getValues(["mail"]);
$this->fromName = $mailOptions["fromName"];
$this->fromAdress = $mailOptions["fromAdress"];
$this->smtpHost = $mailOptions["smtpHost"];
$this->smtpPort = $mailOptions["smtpPort"];
$this->replyTo = $mailOptions["replyTo"];
$this->smtpUser = $mailOptions["smtpUser"];
$this->smtpPass = $mailOptions["smtpPass"];
$this->encriptionType = $mailOptions["encriptionType"];
}
public function Send($to,$name,$title,$content){
$mail = new PHPMailer();
$mail->isSMTP();
$mail->SMTPAuth=true;
$mail->Host = $this->smtpHost;
if(!empty($this->encriptionType) && $this->encriptionType != "no"){
$mail->SMTPSecure = $this->encriptionType;
}
$mail->Port = $this->smtpPort;
$mail->CharSet = 'UTF-8';
$mail->FromName = $this->fromName;
$mail->Username =$this->smtpUser;
$mail->Password = $this->smtpPass;
$mail->From = $this->fromAdress;
$mail->isHTML(true);
$mail->addAddress($to,$name);
$mail->Subject = $title;
$mail->Body = $content;
$status = $mail->send();
if(!$status){
$this->errorMsg = $mail->ErrorInfo;
return false;
}
return true;
}
}
?>
+95
View File
@@ -0,0 +1,95 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use Sabre\DAV;
use \app\index\model\FileManage;
class Objects extends DAV\File{
private $myPath;
public $id;
public $fileData;
public $uid;
public $fileName;
public $dir;
public $actualPath;
public $isExist;
function __construct($path) {
$ex = explode("/",$path);
$this->uid = $ex[0];
$t = strpos($path,$this->uid);
if($t == 0){
$this->myPath = substr($path,$t+strlen($this->uid));
}else{
$this->myPath = $path;
}
$this->fileName = end($ex);
$this->dir = dirname($this->myPath) == "\\" ? "/" :dirname($this->myPath);
$this->fileData = Db::name('files')->where('upload_user',$this->uid)->where('dir',$this->dir)->where('orign_name',$this->fileName)->find();
if(empty($this->fileData)){
$this->isExist = false;
}else{
$this->isExist = true;
}
$this->actualPath = ROOT_PATH . 'public/uploads/'.$this->fileData["pre_name"];
}
function getName() {
return $this->fileName;
}
function get() {
return fopen($this->actualPath, 'r');
}
function getSize() {
return $this->fileData["size"];
}
function setName($name){
$reqPath = $this->myPath;
$ex = explode("/",$reqPath);
$newPath = rtrim($reqPath,end($ex)).$name;
$renameAction = json_decode(FileManage::RenameHandler($reqPath,$newPath,$this->uid,true),true);
if(!$renameAction["result"]["success"]){
throw new DAV\Exception\Forbidden($renameAction["result"]["error"]);
}
}
function getContentType() {
return null;
}
function put($data){
$fileSize = (int)$_SERVER['CONTENT_LENGTH'];
if(!FileManage::sotrageCheck($this->uid,$fileSize)){
throw new DAV\Exception\InsufficientStorage("Quota is not enough");
}
$filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"];
file_put_contents($filePath, "");
file_put_contents($filePath, $data);
FileManage::storageGiveBack($this->uid,$this->fileData["size"]);
FileManage::storageCheckOut($this->uid,$fileSize);
@list($width, $height, $type, $attr) = getimagesize($filePath);
$picInfo = empty($width)?" ":$width.",".$height;
Db::name('files')->where('id', $this->fileData["id"])->update(['size' => $fileSize,'pic_info' => $picInfo]);
}
function delete(){
FileManage::DeleteHandler([0=>$this->myPath],$this->uid);
}
function getETag() {
return '"' . sha1(
fileinode($this->actualPath) .
filesize($this->actualPath) .
filemtime($this->actualPath)
) . '"';
}
}
?>
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
class Option extends Model{
static function getValues($groups = ['basic']){
$t = Db::name('options')->where('option_type','in',$groups)->column('option_value','option_name');
return $t;
}
static function getValue($optionName){
return Db::name('options')->where('option_name',$optionName)->value('option_value');
}
}
?>
+73
View File
@@ -0,0 +1,73 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \app\index\model\Option;
class Remote extends Model{
public $sk;
private $policy;
private $serverOutput;
private $httpCode;
public function __construct($policy){
$this->policy = $policy;
}
public function remove($fileList){
$signKey = $this->sign($fileList,"DELETE");
$this->send("manager.php",$signKey,"DELETE",base64_encode(json_encode($fileList)));
}
public function preview($fname){
return $this->signUrl($this->policy["url"]."object.php?action=preview&name=".urlencode($fname)."&expires=".(time()+(int)Option::getValue("timeout")));
}
public function clean(){
return $this->signUrl($this->policy["url"]."object.php?action=clean&expires=".(time()+(int)Option::getValue("timeout")));
}
public function download($fname,$attnanme){
return $this->signUrl($this->policy["url"]."object.php?action=download&name=".urlencode($fname)."&attaname=".urlencode($attnanme)."&expires=".(time()+(int)Option::getValue("timeout")));
}
public function thumb($fname,$picInfo){
return $this->signUrl($this->policy["url"]."object.php?action=thumb&name=".urlencode($fname)."&expires=".(time()+(int)Option::getValue("timeout"))."&w=".$picInfo[0]."&h=".$picInfo[1]);
}
public function signUrl($url){
$signKey = hash_hmac("sha256",$url,"GET".$this->policy["sk"]);
return $url."&auth=".$signKey;
}
public function updateContent($fname,$content){
$object = ["fname"=>$fname,"content"=>$content];
$signKey = $this->sign($object,"UPDATE");
$this->send("manager.php",$signKey,"UPDATE",base64_encode(json_encode($object)));
}
public function send($target,$auth,$action,$object){
$session = curl_init($this->policy["server"].$target);
$postData = array(
"action" => $action,
"auth" => $auth,
"object" => $object,
);
curl_setopt($session, CURLOPT_POST, 1);
curl_setopt($session, CURLOPT_POSTFIELDS, $postData);
curl_setopt($session, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false);
$this->serverOutput = curl_exec($session);
$this->httpCode = curl_getinfo($session,CURLINFO_HTTP_CODE);
echo $this->serverOutput;
}
public function sign($content,$method = null){
return hash_hmac("sha256",base64_encode(json_encode($content)),$method.$this->policy["sk"]);
}
}
?>
+308
View File
@@ -0,0 +1,308 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \think\Session;
use \app\index\model\FileManage;
use \app\index\model\Option;
use \app\index\model\User;
class ShareHandler extends Model{
public $shareData;
public $querryStatus = true;
public $shareOwner;
public $fileData;
public $dirData;
public $lockStatus = false;
public function __construct($key,$notExist=true){
$this->shareData = Db::name('shares')->where('share_key',$key)->find();
if(empty($this->shareData)){
$this->querryStatus = false;
}else{
if($notExist){
if($this->shareData["source_type"] == "file"){
$this->fileShareHandler();
}else{
$this->dirShareHandler();
}
}
}
if($this->shareData["type"] == "private"){
$this->lockStatus = Session::has("share".$this->shareData["id"])?false:true;
}
}
public function deleteShare($uid){
if($this->shareData["owner"] != $uid){
return array(
"error" => 1,
"msg" => "无权操作"
);
}
Db::name('shares')->where('share_key',$this->shareData["share_key"])->delete();
return array(
"error" => 0,
"msg" => "分享取消成功"
);
}
public function changePromission($uid,$ignore=false){
if($this->shareData["owner"] != $uid && $ignore == false){
return array(
"error" => 1,
"msg" => "无权操作"
);
}
Db::name('shares')->where('share_key',$this->shareData["share_key"])->update([
'type' => $this->shareData["type"] == "public"?"private":"public",
'share_pwd' => self::getRandomKey(6)
]);
return array(
"error" =>0,
"msg" => "更改成功"
);
}
public function checkPwd($pwd){
if($pwd == $this->shareData["share_pwd"]){
Session::set("share".$this->shareData["id"],"1");
return array(
"error" =>0,
);
}else{
return array(
"error" =>1,
"msg" => "密码错误"
);
}
}
public function checkSession($user){
if($this->lockStatus){
return [false,"会话过期,请刷新页面"];
}
if(Option::getValue("allowdVisitorDownload") == "false" && !$user->loginStatus){
return [false,"未登录用户禁止下载,请先登录"];
}
if(!$this->querryStatus){
return [false,"分享不存在,请检查链接是否正确"];
}
return[true,null];
}
public function Download($user){
$checkStatus = $this->checkSession($user);
if(!$checkStatus[0]){
return [$checkStatus[0],$checkStatus[1]];
}
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
if($reqPath["dir"] == "/"){
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
}else{
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
}
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
$FileHandler = $fileObj->Download();
return $FileHandler;
}
public function DownloadFolder($user,$path){
$checkStatus = $this->checkSession($user);
if(!$checkStatus[0]){
return [$checkStatus[0],$checkStatus[1]];
}
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
$path = $path == "/"?"":$path;
$fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]);
$this->numIncrease("download_num");
$FileHandler = $fileObj->Download();
return $FileHandler;
}
public function ListFile($path){
if($this->lockStatus){
die('{ "result": { "success": false, "error": "会话过期,请重新登陆" } }');
}
if(!$this->querryStatus){
return [false,"分享不存在,请检查链接是否正确"];
}
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
$path = $path == "/"?"":$path;
return FileManage::ListFile($this->shareData["source_name"].$path,$this->shareData["owner"]);
}
public function Preview($user){
$checkStatus = $this->checkSession($user);
if(!$checkStatus[0]){
return [$checkStatus[0],$checkStatus[1]];
}
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
if($reqPath["dir"] == "/"){
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
}else{
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
}
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
return $fileObj->PreviewHandler();
}
public function PreviewFolder($user,$path,$folder=false){
$checkStatus = $this->checkSession($user);
if(!$checkStatus[0]){
return [$checkStatus[0],$checkStatus[1]];
}
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
if($folder){
$fileObj = new FileManage($path,$this->shareData["owner"]);
}else{
$fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]);
}
return $fileObj->PreviewHandler();
}
public function listPic($id,$path){
if($this->lockStatus){
die('{ "result": { "success": false, "error": "会话过期,请重新登陆" } }');
}
if(!$this->querryStatus){
return [false,"分享不存在,请检查链接是否正确"];
}
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
$path = $path == "/"?"":$path;
return FileManage::listPic($this->shareData["source_name"].$path,$this->shareData["owner"],"/Share/Preview/".$this->shareData["share_key"]."?folder=true");
}
public function numIncrease($name){
Db::name('shares')->where('share_key',$this->shareData["share_key"])->setInc($name);
}
public function getDownloadUrl($user){
if(Option::getValue("allowdVisitorDownload") == "false" && !$user->loginStatus){
return array(
"error" => 1,
"msg" => "未登录用户禁止下载,请先登录",
);
}else{
$this->numIncrease("download_num");
return array(
"error" => 0,
"result" => "/Share/Download/".$this->shareData["share_key"],
);
}
}
public function fileShareHandler(){
$this->shareOwner = new User($this->shareData["owner"],null,true);
$this->fileData = Db::name('files')
->where('upload_user',$this->shareData["owner"])
->where('id',(int)$this->shareData["source_name"])
->find();
if(!$this->shareOwner->loginStatus || empty($this->fileData)){
$this->querryStatus = false;
}else{
$this->querryStatus = true;
}
}
public function dirShareHandler(){
$this->shareOwner = new User($this->shareData["owner"],null,true);
$this->dirData = Db::name('folders')
->where('owner',$this->shareData["owner"])
->where('position_absolute',$this->shareData["source_name"])
->find();
if(!$this->shareOwner->loginStatus || empty($this->dirData)){
$this->querryStatus = false;
}else{
$this->querryStatus = true;
}
}
static function createShare($fname,$type,$user,$group){
if(!$group["allow_share"]){
self::setError("您当前的用户组无权分享文件");
}
$path = FileManage::getFileName($fname)[1];
$fnameTmp = FileManage::getFileName($fname)[0];
$fileRecord = Db::name('files')->where('upload_user',$user["id"])->where('orign_name',$fnameTmp)->where('dir',$path)->find();
if(empty($fileRecord)){
self::createDirShare($fname,$type,$user,$group);
}else{
self::createFileShare($fileRecord,$type,$user,$group);
}
}
static function setError($text){
die('{ "result": { "success": false, "error": "'.$text.'" } }');
}
static function setSuccess($text){
die('{ "result": "'.$text.'" }');
}
static function createDirShare($fname,$type,$user,$group){
$dirRecord = Db::name('folders')->where('owner',$user["id"])->where('position_absolute',$fname)->find();
if(empty($dirRecord)){
self::setError("目录不存在");
}
$shareKey = self::getRandomKey(8);
$sharePwd = $type=="public" ? "0" : self::getRandomKey(6);
$SQLData = [
'type' => $type=="public" ? "public" : "private",
'share_time' => date("Y-m-d H:i:s"),
'owner' => $user["id"],
'source_name' => $fname,
'origin_name' => $fname,
'download_num' => 0,
'view_num' => 0,
'source_type' => "dir",
'share_key' => $shareKey,
'share_pwd' => $sharePwd,
];
if(Db::name('shares')->insert($SQLData)){
if($sharePwd == "0"){
self::setSuccess(Option::getValue("siteURL")."s/".$shareKey);
}else{
self::setSuccess("链接:".Option::getValue("siteURL")."s/".$shareKey." 密码:".$sharePwd);
}
}
}
static function createFileShare($file,$type,$user,$group){
$shareKey = self::getRandomKey(8);
$sharePwd = $type=="public" ? "0" : self::getRandomKey(6);
$SQLData = [
'type' => $type=="public" ? "public" : "private",
'share_time' => date("Y-m-d H:i:s"),
'owner' => $user["id"],
'source_name' => $file["id"],
'origin_name' => $file["orign_name"],
'download_num' => 0,
'view_num' => 0,
'source_type' => "file",
'share_key' => $shareKey,
'share_pwd' => $sharePwd,
];
if(Db::name('shares')->insert($SQLData)){
if($sharePwd == "0"){
self::setSuccess(Option::getValue("siteURL")."s/".$shareKey);
}else{
self::setSuccess("链接:".Option::getValue("siteURL")."s/".$shareKey." 密码:".$sharePwd);
}
}
}
static function getRandomKey($length = 16){
$charTable = 'abcdefghijklmnopqrstuvwxyz0123456789';
$result = "";
for ( $i = 0; $i < $length; $i++ ){
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
}
return $result;
}
}
?>
+91
View File
@@ -0,0 +1,91 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
class Thumb extends Model{
private $file; //图片地址
private $width; //图片长度
private $height; //图片长度
private $img_type; //图片类型
private $img; //原图的资源句柄
private $new; //新图的资源句柄
//构造方法,初始化
public function __construct($_file) {
$this->file = $_file;
list($this->width, $this->height, $this->img_type) = getimagesize($this->file);
$this->img = $this->getFromImg($this->file, $this->img_type);
}
//缩略图(固定长高容器,图像等比例,扩容填充,裁剪)[固定了大小,不失真,不变形]
public function thumb($new_width = 0,$new_height = 0) {
if (empty($new_width) && empty($new_height)) {
$new_width = $this->width;
$new_height = $this->height;
}
if (!is_numeric($new_width) || !is_numeric($new_height)) {
$new_width = $this->width;
$new_height = $this->height;
}
//创建一个容器
$_n_w = $new_width;
$_n_h = $new_height;
//创建裁剪点
$_cut_width = 0;
$_cut_height = 0;
if ($this->width < $this->height) {
$new_width = ($new_height / $this->height) * $this->width;
} else {
$new_height = ($new_width / $this->width) * $this->height;
}
if ($new_width < $_n_w) { //如果新高度小于新容器高度
$r = $_n_w / $new_width; //按长度求出等比例因子
$new_width *= $r; //扩展填充后的长度
$new_height *= $r; //扩展填充后的高度
$_cut_height = ($new_height - $_n_h) / 2; //求出裁剪点的高度
}
if ($new_height < $_n_h) { //如果新高度小于容器高度
$r = $_n_h / $new_height; //按高度求出等比例因子
$new_width *= $r; //扩展填充后的长度
$new_height *= $r; //扩展填充后的高度
$_cut_width = ($new_width - $_n_w) / 2; //求出裁剪点的长度
}
$this->new = imagecreatetruecolor($_n_w,$_n_h);
imagecopyresampled($this->new,$this->img,0,0,$_cut_width,$_cut_height,$new_width,$new_height,$this->width,$this->height);
}
//加载图片,各种类型,返回图片的资源句柄
private function getFromImg($_file, $_type) {
switch ($_type) {
case 1 :
$img = imagecreatefromgif($_file);
break;
case 2 :
$img = imagecreatefromjpeg($_file);
break;
case 3 :
$img = imagecreatefrompng($_file);
break;
default:
$img = '';
}
return $img;
}
//图像输出
public function out($name) {
imagepng($this->new,$name);//第二个参数为新生成的图片名
imagedestroy($this->img);
imagedestroy($this->new);
}
}
?>
+54
View File
@@ -0,0 +1,54 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \think\Session;
use \PHPGangsta_GoogleAuthenticator;
use \Endroid\QrCode\QrCode;
use \app\index\model\Option;
class TwoFactor extends Model{
public $ga;
public $secretKey;
public $checkResult;
public function __construct(){
$this->ga = new PHPGangsta_GoogleAuthenticator();
}
public function qrcodeRender(){
ob_end_clean();
$this->secretKey = $this->ga->createSecret();
session("two_factor_enable",$this->secretKey);
$qrCode = new QrCode(urldecode(str_replace("https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=","",$this->ga->getQRCodeGoogleUrl(Option::getValue("siteName"), $this->secretKey))));
$qrCode->setSize(165);
$qrCode->setMargin(0);
header('Content-Type: '.$qrCode->getContentType());
echo $qrCode->writeString();
}
public function confirmCode($key,$code){
$this->secretKey = $key;
if(empty($code)){
return [0,"验证码不能为空"];
}
if(empty($key)){
return [0,"二维码过期,请刷新页面后重新扫描"];
}
$this->checkResult = $this->ga->verifyCode($key, $code, 2);
if($this->checkResult){
return [1,"验证成功"];
}else{
return [0,"验证码错误"];
}
}
public function bindUser($uid){
Db::name("users")->where("id",$uid)->update(["two_step" => $this->secretKey]);
}
}
?>
+484
View File
@@ -0,0 +1,484 @@
<?php
namespace app\index\model;
require_once 'extend/Qiniu/functions.php';
use think\Model;
use think\Db;
use Qiniu\Auth;
use \app\index\model\Option;
use \app\index\model\FileManage;
class UploadHandler extends Model{
public $policyId;
public $policyContent;
public $userId;
public $chunkData;
public $fileSizeTmp;
public $ossToken;
public $ossSign;
public $ossCallback;
public $ossAccessId;
public $ossFileName;
public $ossCallBack;
public $upyunPolicy;
public $s3Policy;
public $s3Sign;
public $dirName;
public $s3Credential;
public $siteUrl;
public $callBackKey;
public function __construct($id,$uid){
$this->policyId = $id;
$this->userId = $uid;
$this->policyContent = Db::name('policy')->where('id',$id)->find();
}
public function setChunk($chunkId,$chunkSum,$file){
$sqlData = [
'user' => $this->userId,
'ctx' => self::getRandomKey(),
'obj_name' => self::getRandomKey(8),
'time' => date("Y-m-d H:i:s"),
'chunk_id' => $chunkId,
'sum' => $chunkSum,
];
$this->chunkData = $sqlData;
Db::name('chunks')->insert($sqlData);
$this->saveChunk($file);
$this->chunkInfo();
}
public function saveChunk($file){
$chunkSize = strlen($file);
if(!FileManage::sotrageCheck($this->userId,$chunkSize)){
$this->setError("空间容量不足",false);
}
FileManage::storageCheckOut($this->userId,$chunkSize);
if($chunkSize >=4195304){
$this->setError("分片错误",false);
}
$chunkObj=fopen (ROOT_PATH . 'public/uploads/chunks/'.$this->chunkData["obj_name"].".chunk","w+");
$chunkObjWrite = fwrite ($chunkObj,$file);
if(!$chunkObj || !$chunkObjWrite){
$this->setError("分片创建错误",false);
}
}
public function chunkInfo(){
$returnJson = array(
"ctx" => $this->chunkData["ctx"],
);
echo json_encode($returnJson);
return 0;
}
public function generateFile($ctx,$fname,$path){
$ctxTmp = explode(",",$ctx);
$chunks = Db::name('chunks')->where([
'ctx' => ["in",$ctxTmp],
])->order('id asc')->select();
$file = $this->combineChunks($chunks);
$this->filterCheck($file,$fname);
$suffixTmp = explode('.', $fname);
$fileSuffix = array_pop($suffixTmp);
if($this->policyContent['autoname']){
$fileName = $this->getObjName($this->policyContent['namerule'],"local",$fname).".".$fileSuffix;
}else{
$fileName = $fname;
}
$generatePath = $this->getDirName($this->policyContent['dirrule']);
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
is_dir($savePath)? :mkdir($savePath,0777,true);
if(file_exists($savePath.DS.$fileName)){
$this->setError("文件重名",true,$file,ROOT_PATH . 'public/uploads/chunks/');
}
if(!@rename(ROOT_PATH . 'public/uploads/chunks/'.$file,$savePath.DS.$fileName)){
$this->setError("文件创建失败",true,$file,ROOT_PATH . 'public/uploads/chunks/');
}else{
if($path == "ROOTDIR"){
$path = "";
}
$jsonData = array(
"path" => $path,
"fname" => $fname,
"objname" => $generatePath."/".$fileName,
"fsize" => $this->fileSizeTmp,
);
$addAction = FileManage::addFile($jsonData,$this->policyContent,$this->userId);
if(!$addAction[0]){
$this->setError($addAction[1],true,$fileName,$savePath);
}
echo json_encode(array("key" => $fname));
}
}
public function filterCheck($file,$fname){
$fileSize = filesize(ROOT_PATH . 'public/uploads/chunks/'.$file);
$suffixTmp = explode('.', $fname);
$fileSuffix = array_pop($suffixTmp);
$allowedSuffix = explode(',', self::getAllowedExt(json_decode($this->policyContent["filetype"],true)));
$sufficCheck = !in_array($fileSuffix,$allowedSuffix);
if(empty(self::getAllowedExt(json_decode($this->policyContent["filetype"],true)))){
$sufficCheck = false;
}
if(($fileSize >= (int)$this->policyContent["max_size"]) || $sufficCheck){
FileManage::storageGiveBack($this->userId,$fileSize);
$this->setError("文件效验失败",true,$file,ROOT_PATH . 'public/uploads/chunks/');
}
$this->fileSizeTmp = $fileSize;
}
public function combineChunks($fname){
$fileName = "file_".self::getRandomKey(8);
$fileObj=fopen (ROOT_PATH . 'public/uploads/chunks/'.$fileName,"a+");
$deleteList=[];
foreach ($fname as $key => $value) {
$chunkObj = fopen(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk", "rb");
if(!$fileObj || !$chunkObj){
$this->setError("文件创建失败",false);
}
$content = fread($chunkObj, 4195304);
fwrite($fileObj, $content, 4195304);
unset($content);
fclose($chunkObj);
unlink(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
array_push($deleteList, $value["id"]);
}
$chunks = Db::name('chunks')->where([
'id' => ["in",$deleteList],
])->delete();
return $fileName;
}
public function fileReceive($file,$info){
$allowedExt = self::getAllowedExt(json_decode($this->policyContent["filetype"],true));
$filter = array('size'=>(int)$this->policyContent["max_size"]);
if(!empty($allowedExt)){
$filter = array_merge($filter,array("ext" => $allowedExt));
}
if(!FileManage::sotrageCheck($this->userId,$file->getInfo('size'))){
$this->setError("空间容量不足",false);
}
if($this->policyContent['autoname']){
$fileName = $this->getObjName($this->policyContent['namerule'],"local",$file->getInfo('name'));
}else{
$fileName = $file->getInfo('name');
}
$generatePath = $this->getDirName($this->policyContent['dirrule']);
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
$Uploadinfo = $file
->validate($filter)
->move($savePath,$fileName,false);
if($Uploadinfo){
$jsonData = array(
"path" => $info["path"],
"fname" => $info["name"],
"objname" => $generatePath."/".$Uploadinfo->getSaveName(),
"fsize" => $Uploadinfo->getSize(),
);
@list($width, $height, $type, $attr) = getimagesize(rtrim($savePath, DS).DS.$Uploadinfo->getSaveName());
$picInfo = empty($width)?" ":$width.",".$height;
$addAction = FileManage::addFile($jsonData,$this->policyContent,$this->userId,$picInfo);
if(!$addAction[0]){
$tmpFileName = $Uploadinfo->getSaveName();
unset($Uploadinfo);
$this->setError($addAction[1],true,$tmpFileName,$savePath);
}
FileManage::storageCheckOut($this->userId,$jsonData["fsize"],$Uploadinfo->getInfo('size'));
echo json_encode(array("key" => $info["name"]));
}else{
header("HTTP/1.1 401 Unauthorized");
echo json_encode(array("error" => $file->getError()));
}
}
public function setError($text,$delete = false,$fname="",$path=""){
header("HTTP/1.1 401 Unauthorized");
if($delete){
unlink(rtrim($path, DS).DS.$fname);
}
die(json_encode(["error"=> $text]));
}
static function getAllowedExt($ext){
$returnValue = "";
foreach ($ext as $key => $value) {
$returnValue .= $value["ext"].",";
}
return rtrim($returnValue, ",");
}
public function getToken(){
switch ($this->policyContent['policy_type']) {
case 'qiniu':
return $this->getQiniuToken();
break;
case 'local':
return $this->getLocalToken();
break;
case 'oss':
return $this->getOssToken();
break;
case 'upyun':
return $this->getUpyunToken();
break;
case 's3':
return $this->getS3Token();
break;
case 'remote':
return $this->getRemoteToken();
break;
default:
# code...
break;
}
}
public function getObjName($expression,$type = "qiniu",$origin = ""){
$policy = array(
'{date}' =>date("Ymd"),
'{datetime}' =>date("YmdHis"),
'{uid}' =>$this->userId,
'{timestamp}' =>time(),
'{randomkey16}' =>self::getRandomKey(16),
'{randomkey8}' =>self::getRandomKey(8),
);
if($type == "qiniu"){
$policy = array_merge($policy,array("{originname}" => "$(fname)"));
}else if($type == "local"){
$policy = array_merge($policy,array("{originname}" => $origin));
}else if ($type="oss"){
$policy = array_merge($policy,array("{originname}" => '${filename}'));
}else if ($type="upyun"){
$policy = array_merge($policy,array("{originname}" => '{filename}{.suffix}'));
}
return strtr($expression,$policy);
}
public function getDirName($expression){
$policy = array(
'{date}' =>date("Ymd"),
'{datetime}' =>date("YmdHis"),
'{uid}' =>$this->userId,
'{timestamp}' =>time(),
'{randomkey16}' =>self::getRandomKey(16),
'{randomkey8}' =>self::getRandomKey(8),
);
return trim(strtr($expression,$policy),"/");
}
public function getQiniuToken(){
$callbackKey = $this->getRandomKey();
$sqlData = [
'callback_key' => $callbackKey,
'pid' => $this->policyId,
'uid' => $this->userId
];
Db::name('callback')->insert($sqlData);
$auth = new Auth($this->policyContent['ak'], $this->policyContent['sk']);
$policy = array(
'callbackUrl' =>Option::getValue("siteURL").'Callback/Qiniu',
'callbackBody' => '{"fname":"$(fname)","objname":"$(key)","fsize":"$(fsize)","callbackkey":"'.$callbackKey.'","path":"$(x:path)","picinfo":"$(imageInfo.width),$(imageInfo.height)"}',
'callbackBodyType' => 'application/json',
'fsizeLimit' => (int)$this->policyContent['max_size'],
);
$dirName = $this->getObjName($this->policyContent['dirrule']);
if($this->policyContent["autoname"]){
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/").$this->getObjName($this->policyContent['namerule'])));
}else{
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/")."$(fname)"));
}
if(!empty($this->policyContent['mimetype'])){
$policy = array_merge($policy,array("mimeLimit" => $this->policyContent['mimetype']));
}
$token = $auth->uploadToken($this->policyContent['bucketname'], null, 3600, $policy);
return $token;
}
private function getRemoteToken(){
$callbackKey = $this->getRandomKey();
$sqlData = [
'callback_key' => $callbackKey,
'pid' => $this->policyId,
'uid' => $this->userId
];
Db::name('callback')->insert($sqlData);
$policy = array(
'callbackUrl' =>Option::getValue("siteURL").'Callback/Remote',
'callbackKey' => $callbackKey,
'callbackBodyType' => 'application/json',
'fsizeLimit' => (int)$this->policyContent['max_size'],
'uid' => $this->userId,
);
$dirName = $this->getObjName($this->policyContent['dirrule']);
if($this->policyContent["autoname"]){
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/").$this->getObjName($this->policyContent['namerule'])));
}else{
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/")."$(fname)"));
}
if(!empty($this->policyContent['mimetype'])){
$policy = array_merge($policy,array("mimeLimit" => $this->policyContent['mimetype']));
}
$signingKey = hash_hmac("sha256",json_encode($policy),"UPLOAD".$this->policyContent['sk']);
$token = $signingKey. ":" .base64_encode(json_encode($policy));
return $token;
}
static function upyunSign($key, $secret, $method, $uri, $date, $policy=null, $md5=null){
$elems = array();
foreach (array($method, $uri, $date, $policy, $md5) as $v){
if ($v){
$elems[] = $v;
}
}
$value = implode('&', $elems);
$sign = base64_encode(hash_hmac('sha1', $value, $secret, true));
return 'UPYUN ' . $key . ':' . $sign;
}
public function getUpyunToken(){
$callbackKey = $this->getRandomKey();
$sqlData = [
'callback_key' => $callbackKey,
'pid' => $this->policyId,
'uid' => $this->userId
];
Db::name('callback')->insert($sqlData);
$options = Option::getValues(["oss","basic"]);
$dateNow = gmdate('D, d M Y H:i:s \G\M\T');
$policy=[
"bucket" => $this->policyContent['bucketname'],
"expiration" => time()+$options["timeout"],
"notify-url" => $options["siteURL"]."Callback/Upyun",
"content-length-range" =>"0,".$this->policyContent['max_size'],
"date" => $dateNow,
"ext-param"=>json_encode([
"path"=>cookie("path"),
"uid" => $this->userId,
"pid" => $this->policyId,
]),
];
$allowedExt = self::getAllowedExt(json_decode($this->policyContent["filetype"],true));
if(!empty($allowedExt)){
$policy = array_merge($policy,array("allow-file-type" => $allowedExt));
}
$dirName = $this->getObjName($this->policyContent['dirrule']);
$policy = array_merge($policy,array("save-key" => $dirName.(empty($dirName)?"":"/").uniqid()."CLSUFF{filename}{.suffix}"));
$this->upyunPolicy = base64_encode(json_encode($policy));
return self::upyunSign($this->policyContent['op_name'], md5($this->policyContent['op_pwd']), "POST", "/".$this->policyContent['bucketname'],$dateNow,$this->upyunPolicy);
}
public function ossCallback(){
$callbackKey = $this->getRandomKey();
$sqlData = [
'callback_key' => $callbackKey,
'pid' => $this->policyId,
'uid' => $this->userId
];
Db::name('callback')->insert($sqlData);
$returnValue["callbackUrl"] = Option::getValue("siteUrl").'Callback/Oss';
$returnValue["callbackBody"] = '{"fname":"${x:fname}","objname":"${object}","fsize":"${size}","callbackkey":"'.$callbackKey.'","path":"${x:path}","picinfo":"${imageInfo.width},${imageInfo.height}"}';
$this->ossCallBack = base64_encode(json_encode($returnValue));
return base64_encode(json_encode($returnValue));
}
public function getS3Token(){
$dirName = $this->getDirName($this->policyContent['dirrule']);
$longDate = gmdate('Ymd\THis\Z');
$shortDate = gmdate('Ymd');
$credential = $this->policyContent['ak'] . '/' . $shortDate . '/' . $this->policyContent['op_name'] . '/s3/aws4_request';
$callbackKey = $this->getRandomKey();
$sqlData = [
'callback_key' => $callbackKey,
'pid' => $this->policyId,
'uid' => $this->userId
];
Db::name('callback')->insert($sqlData);
$this->siteUrl = Option::getValue("siteUrl");
$returnValue = [
"expiration" => date("Y-m-d",time()+1800)."T".date("H:i:s",time()+1800).".000Z",
"conditions" => [
0 => ["bucket" => $this->policyContent['bucketname']],
1 => ["starts-with",'$key', $dirName],
2 => ["starts-with",'$success_action_redirect' ,$this->siteUrl."Callback/S3/key/".$callbackKey],
3 => ["content-length-range",1,(int)$this->policyContent['max_size']],
4 => ['x-amz-algorithm' => 'AWS4-HMAC-SHA256'],
5 => ['x-amz-credential' => $credential],
6 => ['x-amz-date' => $longDate],
7 => ["starts-with", '$name', ""],
8 => ["starts-with", '$Content-Type', ""],
]
];
$this->s3Policy = base64_encode(json_encode($returnValue));
$signingKey = hash_hmac("sha256",$shortDate,"AWS4".$this->policyContent['sk'],true);
$signingKey = hash_hmac("sha256",$this->policyContent['op_name'],$signingKey,true);
$signingKey = hash_hmac("sha256","s3",$signingKey,true);
$signingKey = hash_hmac("sha256","aws4_request",$signingKey,true);
$signingKey = hash_hmac("sha256",$this->s3Policy,$signingKey);
$this->s3Sign = $signingKey;
$this->dirName = $dirName;
$this->s3Credential = $credential;
$this->x_amz_date = $longDate;
$this->callBackKey = $callbackKey;
}
public function getOssToken(){
$dirName = $this->getObjName($this->policyContent['dirrule']);
$returnValu["expiration"] = date("Y-m-d",time()+1800)."T".date("H:i:s",time()+1800).".000Z";
$returnValu["conditions"][0]["bucket"] = $this->policyContent['bucketname'];
$returnValu["conditions"][1][0]="starts-with";
$returnValu["conditions"][1][1]='$key';
if($this->policyContent["autoname"]){
$this->ossFileName = $dirName.(empty($dirName)?"":"/").$this->getObjName($this->policyContent['namerule'],"oss");;
}else{
$this->ossFileName = $dirName.(empty($dirName)?"":"/").'${filename}';
}
$returnValu["conditions"][1][2]=$dirName.(empty($dirName)?"":"/");
$returnValu["conditions"][2]=["content-length-range",1,(int)$this->policyContent['max_size']];
$returnValu["conditions"][3]["callback"] = $this->ossCallback();
$this->ossToken=base64_encode(json_encode($returnValu));
$this->ossSignToken();
$this->ossAccessId = $this->policyContent['ak'];
return false;
}
public function ossSignToken(){
$this->ossSign = base64_encode(hash_hmac("sha1", $this->ossToken, $this->policyContent['sk'],true));
}
public function getLocalToken(){
$auth = new Auth($this->policyContent['ak'], $this->policyContent['sk']);
$policy = array(
'callbackBody' => '{"path":"'.cookie('path').'"}',
'callbackBodyType' => 'application/json',
);
$token = $auth->uploadToken($this->policyContent['bucketname'], null, 3600, $policy);
return $token;
}
static function getRandomKey($length = 16){
$charTable = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$result = "";
for ( $i = 0; $i < $length; $i++ ){
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
}
return $result;
}
static function b64Decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
}
?>
+375
View File
@@ -0,0 +1,375 @@
<?php
namespace app\index\model;
use think\Model;
use think\Db;
use \think\Session;
use \think\Cookie;
use \app\index\model\Option;
use \app\index\model\Mail;
use think\Validate;
class User extends Model{
public $uid;
public $varifyKey;
public $groupId;
public $regDate;
public $loginStatus = false;
public $userNick;
public $userMail;
public $groupData;
public $userSQLData;
/**
* [__construct description]
* @param [type] $userId [description]
* @param [type] $userKey [description]
*/
public function __construct($userId,$userKey,$ignoreLogin = false){
$userData = Db::name('users')->where('id',$userId)->where('user_status',0)->find();
if(empty($userData)){
$this->loginStatus = false;
$this->setUser();
return false;
}
if(!$ignoreLogin){
if(md5($userData['user_email'].$userData['user_pass'].config('salt')) != $userKey){
$this->loginStatus = false;
$this->setUser();
return false;
}
}
$this->groupData = Db::name('groups')->where('id',$userData['user_group'])->find();
$this->loginStatus = true;
$this->uid = $userId;
$this->groupId = $userData['user_group'];
$this->regDate = $userData['user_date'];
$this->userNick = $userData['user_nick'];
$this->userMail = $userData['user_email'];
$this->varifyKey = $userKey;
$this->userSQLData = $userData;
}
public function setUser(){
$this->groupData = Db::name('groups')->where('id',2)->find();
$this->uid = -1;
}
static function resetPwd($key,$pwd){
$key = explode("_",$key);
$resetKey = $key[0]."_".$key[1];
$userId = $key[2];
$keyCheck = self::resetUser($resetKey,$userId);
if(!$keyCheck[0]){
return $keyCheck;
}else{
if ((mb_strlen($pwd,'UTF8')>64) || (mb_strlen($pwd,'UTF8')<4)){
return [false,"密码不符合规范"];
}
self::Reset($userId,$pwd);
return [true,"密码重设成功"];
}
}
static function Reset($uid,$pwd){
Db::name('users')->where('id',$uid)
->update([
'user_pass' => md5(config('salt').$pwd),
]);
}
/**
* [register description]
* @param [type] $userEmail [description]
* @param [type] $userPass [description]
* @return [type] [description]
*/
static function register($userEmail,$userPass,$captchaCode){
if(Option::getValue("reg_captcha")=="1"){
if(!self::checkCaptcha($captchaCode)){
return [false,"验证码错误"];
}
}
if (\app\index\model\Option::getValue("regStatus") == '1'){
return [false,"当前站点关闭注册"];
}
$userName = str_replace(" ", "", $userEmail);
$passWord = $userPass;
if ( !filter_var($userName,FILTER_VALIDATE_EMAIL) || (mb_strlen($userName,'UTF8')>22) || (mb_strlen($userName,'UTF8')<4) || (mb_strlen($passWord,'UTF8')>64) || (mb_strlen($passWord,'UTF8')<4)){
return [false,"邮箱或密码不符合规范"];
}
if(Db::name('users')->where('user_email',$userName)->find() !=null){
return [false,"该邮箱已被注册"];
}
$defaultGroup = (int)\app\index\model\Option::getValue("defaultGroup");
$regOptions = Option::getValues(["register"]);
if($regOptions["email_active"] == "1"){
$activationKey = md5(uniqid(rand(), TRUE));
$userStatus = 1;
}else{
$activationKey = "n";
$userStatus = 0;
}
$sqlData = [
'user_email' => $userName,
'user_pass' => md5(config('salt').$passWord),
'user_status' => $userStatus,
'user_group' => $defaultGroup,
'group_primary' => 0,
'user_date' => date("Y-m-d H:i:s"),
'user_nick' => explode("@",$userName)[0],
'user_activation_key' => $activationKey,
'used_storage' => 0,
'two_step'=>"0",
'webdav_key' =>md5(config('salt').$passWord),
'delay_time' =>0,
'avatar' => "default",
'profile' => true,
];
if(Db::name('users')->insert($sqlData)){
$userId = Db::name('users')->getLastInsID();
Db::name('folders')->insert( [
'folder_name' => '根目录',
'parent_folder' => 0,
'position' => '.',
'owner' => $userId,
'date' => date("Y-m-d H:i:s"),
'position_absolute' => '/',
]);
if($regOptions["email_active"] == "1"){
$options = Option::getValues(["basic","mail_template"]);
$replace = array(
'{siteTitle}' =>$options["siteName"],
'{userName}' =>explode("@",$userName)[0],
'{siteUrl}' =>$options["siteURL"],
'{siteSecTitle}' =>$options["siteTitle"],
'{activationUrl}' =>$options["siteURL"]."Member/emailActivate/".$activationKey,
);
$mailContent = strtr($options["mail_activation_template"],$replace);
$mailObj = new Mail();
$mailObj->Send($userName,explode("@",$userName)[0],"".$options["siteName"].""."注册激活",$mailContent);
return [true,"ec"];
}
return [true,"注册成功"];
}
}
static function activicateUser($key){
$userData = Db::name('users')
->where('user_activation_key','neq','n')
->where("user_activation_key",$key)->find();
if(empty($userData)){
return [0,"激活失败,用户在不存在"];
}else{
Db::name('users')->where("id",$userData["id"])->update([
"user_activation_key" => "n",
"user_status" => 0,
]);
return [1,1];
}
}
static function resetUser($key,$uid){
$timeNow = time();
if(empty($key)||empty($uid)){
return [0,"URL参数错误"];
}
$key = explode("_",$key);
$userData = Db::name('users')
->where('user_status',0)
->where("id",$uid)->find();
if(empty($userData)){
return [0,"用户不存在"];
}
if(md5($userData["user_pass"].$key[1]) != $key[0]){
return [0,"参数无效,请检查邮件链接"];
}
if(($timeNow - $key[1])>7200){
return [0,"重设链接过期,请重新提交"];
}
return [1,1];
}
static function findPwd($email,$captchaCode){
if(Option::getValue("forget_captcha")=="1"){
if(!self::checkCaptcha($captchaCode)){
return [false,"验证码错误"];
}
}
$userData = Db::name('users')->where('user_email',$email)->find();
if(empty($userData)){
return [1,1];
}
$timeNow = time();
$resetHash = md5($userData["user_pass"].$timeNow);
$resetKey = $resetHash."_".$timeNow;
$options = Option::getValues(["basic","mail_template"]);
$replace = array(
'{siteTitle}' =>$options["siteName"],
'{userName}' =>$userData["user_nick"],
'{siteUrl}' =>$options["siteURL"],
'{siteSecTitle}' =>$options["siteTitle"],
'{resetUrl}' =>$options["siteURL"]."Member/resetPwd/".$resetKey."?uid=".$userData["id"],
);
$mailContent = strtr($options["mail_reset_pwd_template"],$replace);
$mailObj = new Mail();
$mailObj->Send($email,$userData["user_nick"],"".$options["siteName"].""."密码重置",$mailContent);
return [true,"ec"];
}
/**
* [login description]
* @param [type] $userEmail [description]
* @param [type] $userPass [description]
* @return [type] [description]
*/
static function login($userEmail,$userPass,$captchaCode){
$userEmail = str_replace(" ", "", $userEmail);
$userData =Db::name('users')->where('user_email',$userEmail)->find();
if(empty($userEmail) || empty($userPass)){
return [false,"表单不完整"];
}
if(Option::getValue("login_captcha")=="1"){
if(!self::checkCaptcha($captchaCode)){
return [false,"验证码错误"];
}
}
if(Db::name('users')->where('user_email',$userEmail)->value('user_pass') != md5(config('salt').$userPass)){
return [false,"用户名或密码错误"];
}
if(Db::name('users')->where('user_email',$userEmail)->value('user_status') != 0){
return [false,"账号被禁用或未激活"];
}
if($userData["two_step"] != "0"){
session("user_id_tmp",Db::name('users')->where('user_email',$userEmail)->value('id'));
session("login_status_tmp","ok");
session("login_key_tmp",md5($userEmail.md5(config('salt').$userPass).config('salt')));
return [false,"tsp"];
}
$loginKey = md5($userEmail.md5(config('salt').$userPass).config('salt'));
cookie('user_id',Db::name('users')->where('user_email',$userEmail)->value('id'),604800);
cookie('login_status','ok',604800);
cookie('login_key',$loginKey,604800);
return [true,"登录成功",$loginKey];
}
static function checkCaptcha($code){
if(!captcha_check($code)){
return false;
}
return true;
}
/**
* [clear description]
* @return [type] [description]
*/
public function clear(){
$this->loginStatus = false;
$this->uid = null;
$this->groupId = null;
$this->regDate = null;
$this->varifyKey = null;
cookie('user_id', null);
cookie('login_status', null);
cookie('login_key', null);
}
/**
* [getInfo description]
* @return [type] [description]
*/
public function getInfo(){
return [
'uid' => $this->uid,
'groupId' => $this->groupId,
'regDate' => $this->regDate,
'loginStatus' => $this->loginStatus,
'userNick' => $this->userNick,
'userMail' => $this->userMail,
'groupData' => $this->groupData,
'sqlData' => $this->userSQLData,
];
}
public function getSQLData(){
return $this->userSQLData;
}
public function getPolicy(){
return Db::name('policy')->where('id',$this->groupData["policy_name"])->find();
}
public function getGroupData(){
return $this->groupData;
}
public function getMemory($notEcho = false){
$usedMemory = $this->userSQLData["used_storage"];
$groupStorage = (int)$this->groupData["max_storage"];
$packetStorage = (int)Db::name('storage_pack')
->where('uid',$this->uid)
->where('dlay_time',">",time())
->sum('pack_size');
$returnData["used"] = self::countSize($usedMemory);
$returnData["total"] = self::countSize($groupStorage+$packetStorage);
$returnData["rate"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
$returnData["basic"] = self::countSize($groupStorage);
$returnData["pack"] = self::countSize($packetStorage);
if($usedMemory > $groupStorage){
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
$returnData["r2"] = 0;
$returnData["r3"] = 100-$returnData["r1"];
}else{
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
$returnData["r2"] = floor(($groupStorage-$usedMemory)/($groupStorage+$packetStorage)*100);;
$returnData["r3"] = 100-$returnData["r1"]-$returnData["r2"];
}
if($notEcho){
return json_encode($returnData);
}
echo json_encode($returnData);
}
static function countSize($bit) {
$type = array('Bytes','KB','MB','GB','TB');
for($i = 0; $bit >= 1024; $i++) {
$bit/=1024;
}
return (floor($bit*100)/100).$type[$i];
}
public function changeNick($nick){
$nick=["nick" => $nick];
$rules = [
'nick' => ['require','max'=>'25','chsDash'],
];
$validate = new Validate($rules);
if (!$validate->check($nick)) {
return [0,"昵称必须是1-25位字符,只能包含中英文等常见字符"];
}else{
Db::name("users")->where("id",$this->uid)->update(["user_nick" => $nick["nick"]]);
return [1,1];
}
}
public function changePwd($origin,$new){
if(md5(config('salt').$origin) != $this->userSQLData["user_pass"]){
return [0,"原密码错误"];
}
if ((mb_strlen($new,'UTF8')>64) || (mb_strlen($new,'UTF8')<4)){
return [false,"密码不符合规范"];
}
self::Reset($this->uid,$new);
return [true,"密码重设成功"];
}
public function homePageToggle($status){
Db::name("users")->where("id",$this->uid)->update(["profile" => $status=="true"?1:0]);
return [1,1];
}
}
?>
+72
View File
@@ -0,0 +1,72 @@
{extend name="header_admin" /}
{block name="title"}基础设置- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">其他</li>
<li class="breadcrumb-item active">关于</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>关于</h2>
<br>
<div class="row">
<div class="col">
<div class="card">
<div class="card-header" >
<i class="fa fa-eye fa-fw" aria-hidden="true"></i>
系统信息
</div>
<div class="card-body">
<ul>
<li>服务器信息:{:$_SERVER ['SERVER_SOFTWARE']}</li>
<li>服务端系统:{:PHP_OS}</li>
<li>最大上传限制:{:get_cfg_var ("upload_max_filesize")?get_cfg_var ("upload_max_filesize"):"不允许上传"}</li>
<li>脚本最大执行时间:{:get_cfg_var("max_execution_time")."s "}</li>
<li>脚本最大内存:{:get_cfg_var ("memory_limit")?get_cfg_var("memory_limit"):"无"}</li>
<li>PHP扩展:curl{eq name=":extension_loaded('curl')" value="true"}√{else/}×{/eq} openssl{eq name=":extension_loaded('openssl')" value="true"}√{else/}×{/eq} GD{eq name=":extension_loaded('gd')" value="true"}√{else/}×{/eq} fileinfo{eq name=":extension_loaded('fileinfo')" value="true"}√{else/}×{/eq}</li>
</ul>
</div>
</div>
</div>
<div class="col">
<div class="card" style="min-height: 269px;">
<div class="card-header">
<i class="fa fa-cloud fa-fw" aria-hidden="true"></i>
关于Cloudreve
</div>
<div class="card-body">
<h5 class="card-title">Cloudreve {$programVersion.type} {$programVersion.version}</h5>
<ul>
<li>主页:<a href="https://cloudreve.org" target="_blank">https://cloudreve.org</a></li>
<li>Github<a href="https://github.com/HFO4/Cloudreve" target="_blank">https://github.com/HFO4/Cloudreve</a></li>
<li>许可证:<a href="https://github.com/HFO4/Cloudreve/LICENSE" target="_blank">GPL V3</a>(社区版)</li>
<li>其他链接:<a href="https://github.com/HFO4/Cloudreve/graphs/contributors" target="_blank">代码贡献者</a> <a href="https://cloudreve.org/joingroup" target="_blank">Telegram群组</a> <a href="https://forum.cloudreve.org" target="_blank">社区</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script type="text/javascript">
</script>
{/block}
+164
View File
@@ -0,0 +1,164 @@
{extend name="header_admin" /}
{block name="title"}注册访问- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">用户组</li>
<li class="breadcrumb-item active">添加用户组</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>添加用户组</h2>
<br>
<form id="addGroup">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组名</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="group_name" required></div>
<div class="col-md-4 option-des"> 用户组的名称</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">上传策略</label>
</div>
<div class="col-md-4">
<select name="policy_name" required class="form-control">
{volist name="policy" id="p"}
<option value="{$p.id}">{$p.policy_name}</option>
{/volist}
</select>
</div>
<div class="col-md-4 option-des"> 为该用户组绑定一个上传策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">初始容量</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_storage" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 该用户组初始最大可用容量</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">下载限速</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="speed" spellcheck="false" min="0" placeholder="留空表示不限速,0表示禁止下载">
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
Kb/s
</span>
</div>
</div>
<div class="col-md-4 option-des"> 限制该用户组下的用户上传的文件的下载速度,<strong>此设置仅对本地上传方案有效</strong></div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">断点续传及多线程下载</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="range_transfer" value="1" id="allow_range_1" checked>
<label class="" for="allow_range_1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="range_transfer" id="allow_range_0" value="0" >
<label class="" for="allow_range_0">禁止</label></div>
<div class="col-md-4 option-des"> 是否断点续传及多线程下载,关闭后预览视频不支持拖拽播放,<strong>此设置仅对本地上传方案有效</strong></div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">创建分享</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="allow_share" value="1" id="allow_share_1" checked>
<label class="" for="allow_share_1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="allow_share" id="allow_share_0" value="0" >
<label class="" for="allow_share_0">禁止</label></div>
<div class="col-md-4 option-des"> 是否允许创建文件分享链接</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">WebDAV支持</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="webdav" value="1" id="webdav1" checked>
<label class="" for="webdav1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="webdav" id="webdav0" value="0" >
<label class="" for="webdav0">禁止</label></div>
<div class="col-md-4 option-des"> 是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组标志色</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="color" value="default" id="default" checked>
<label class="" for="default" ><span class="badge badge-primary">蓝色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="primary" id="primary">
<label class="" for="primary" ><span class="badge badge-secondary">灰色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="success" id="success">
<label class="" for="success" ><span class="badge badge-success">绿色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="danger" id="danger">
<label class="" for="danger" ><span class="badge badge-danger">红色</span></label>
<br>
<input class="" type="radio" name="color" value="warning" id="warning">
<label class="" for="warning" ><span class="badge badge-warning">黄色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="info" id="info">
<label class="" for="info" ><span class="badge badge-info">浅蓝色</span></label>
&nbsp;&nbsp;&nbsp;
</div>
<div class="col-md-4 option-des"> 用户个人主页展示用户组时的徽章颜色</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveGroup">添加</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/add_group.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,825 @@
{extend name="header_admin" /}
{block name="title"}添加上传策略- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item">
<a href="/Admin/PolicyAdd">上传策略</a>
</li>
<li class="breadcrumb-item active">添加</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>添加上传策略</h2>
<br>
<div id="choose">
<div class="row">
<div class="col-md-3 md-2 mt-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/local.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">本地服务器</h5>
<p class="card-text">将文件存放在Cloudreve主程序的同一个服务器上</p>
<a href="javascript:void()" class="btn btn-primary" id="addLocal">添加</a>
</div>
</div>
</div>
<div class="col-md-3 md-2 mt-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/qiniu.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">七牛云存储</h5>
<p class="card-text">使用<a href="https://www.qiniu.com/" target="_blank">七牛云</a>提供的云存储及CDN服务</p>
<a href="javascript:void();" class="btn btn-primary" id="addQiniu">添加</a>
</div>
</div>
</div>
<div class="col-md-3 md-2 mt-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/oss.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">阿里云OSS</h5>
<p class="card-text">使用<a href="https://www.aliyun.com/product/oss?spm=5176.doc54464.765261.286.v2y7Hk" target="_blank">OSS对象存储</a>存放文件,推荐配合阿里云CDN使用</p>
<a href="javascript:void()" class="btn btn-primary" id="addOss">添加</a>
</div>
</div>
</div>
<div class="col-md-3 md-2 mt-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/upyun.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">又拍云</h5>
<p class="card-text">使用<a href="https://console.upyun.com/register/?invite=ryPX265PW" target="_blank">又拍云存储</a>提供的服务,每月有一定免费额度</p>
<a href="javascript:void()" class="btn btn-primary" id="addUpyun">添加</a>
</div>
</div>
</div>
<div class="col-md-3 mt-2 md-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/s3.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">Amazon S3</h5>
<p class="card-text"><a href="https://aws.amazon.com/cn/s3/?nc1=h_ls" target="_blank">Amazon S3</a>专为数据而构建的对象存储</p>
<a href="/Admin/PolicyAddS3" class="btn btn-primary">添加</a>
</div>
</div>
</div>
<div class="col-md-3 mt-2 md-2">
<div class="card cloud">
<img class="card-img-top" src="/static/img/remote.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">远程服务器</h5>
<p class="card-text">你可以将文件存放在不同于主程序的服务器上。<a href="https://github.com/HFO4/Cloudreve/wiki/%E8%BF%9C%E7%A8%8B%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%90%AD%E5%BB%BA">配置说明</a></p>
<a href="/Admin/PolicyAddRemote" class="btn btn-primary">添加</a>
</div>
</div>
</div>
</div>
</div>
<div class="card" id="local" style="display: none">
<div class="card-header">
添加本地上传策略
</div>
<div class="card-body">
<form id="localPolicy">
<input type="text" class="form-control" name="policy_type" value="local" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">允许获取外链</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="origin_link" id="local_allowd_origin1" value="1" >
<label class="" for="local_allowd_origin1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="origin_link" id="local_allowd_origin2" value="0" checked>
<label class="" for="local_allowd_origin2">禁止</label>
</div>
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</div>
</div>
<div class="row form-setting" id="localOrigin" style="display: none">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">外链根URL</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" value="{$options.siteURL}public/uploads/">
</div>
<div class="col-md-4 option-des"> 一般保持默认。如果你设置了融合CDN等产品,这里可以填写CDN域名,结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">允许的文件后缀</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="autoname" id="autoname1" value="1" checked>
<label class="" for="autoname1" >开启</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="autoname" id="autoname2" value="0" >
<label class="" for="autoname2">关闭</label>
</div>
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
</div>
<div class="row form-setting" id="autoname_form" >
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="namerule" value="{uid}_{randomkey8}_{originname}" spellcheck="false" required>
</div>
<div class="col-md-4 option-des"> 你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTable">变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
</div>
<div class="col-md-4 input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon2">
/public/uploads/
</span>
</div>
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
</div>
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTableFolder">目录变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="savePolicy">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
<div class="card" id="qiniu" style="display: none">
<div class="card-header">
添加七牛上传策略
</div>
<div class="card-body">
<form id="qiniuPolicy">
<input type="text" class="form-control" name="policy_type" value="qiniu" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="ak" class="col-form-label col-form-label-sm">AccessKey </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="ak" required></div>
<div class="col-md-4 option-des"> 七牛账号的AccessKey,请在七牛控制面板查看</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="sk" class="col-form-label col-form-label-sm">SecretKey </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="sk" required></div>
<div class="col-md-4 option-des"> 七牛账号的SecretKey,请在七牛控制面板查看</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="bucketname" class="col-form-label col-form-label-sm">存储空间名称 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
<div class="col-md-4 option-des"> 创建空间时填写的空间名</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">空间属性</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="bucket_private" id="bucket_private_1" value="1" checked>
<label class="" for="bucket_private_1" >私有空间</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="bucket_private" id="bucket_private_0" value="0">
<label class="" for="bucket_private_0">公开空间</label>
</div>
<div class="col-md-4 option-des"> 与七牛空间访问控制设置保持一致,推荐设置为私有空间</div>
</div>
<div class="row form-setting" id="outlink" style="display: none">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">允许获取外链</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="origin_link" id="qiniu_allowd_origin1" value="1" >
<label class="" for="qiniu_allowd_origin1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="origin_link" id="qiniu_allowd_origin2" value="0" checked>
<label class="" for="qiniu_allowd_origin2">禁止</label>
</div>
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">空间域名</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" required>
</div>
<div class="col-md-4 option-des"> 七牛空间绑定的域名,结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">允许的文件后缀</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="mimetype" class="col-form-label col-form-label-sm">允许的mimeType</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="mimetype" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角分号";"隔开,留空表示不限制。示例:image/*表示只允许上传图片类型,image/jpeg;image/png表示只允许上传jpg和png类型的图片,!application/json;text/plain表示禁止上传json文本和纯文本。注意最前面的感叹号!</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="autoname" id="qiniu_autoname1" value="1" checked>
<label class="" for="qiniu_autoname1" >开启</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="autoname" id="qiniu_autoname2" value="0" >
<label class="" for="qiniu_autoname2">关闭</label>
</div>
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
</div>
<div class="row form-setting" id="qiniu_autoname_form" >
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="namerule" value="{uid}_{randomkey8}_{originname}" spellcheck="false" required>
</div>
<div class="col-md-4 option-des"> 你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTable">变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
</div>
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTableFolder">目录变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveQiniu">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
<div id="oss" style="display: none">
<div class="alert alert-primary" role="alert">
阿里云OSS创建空间后请进行如下操作,否则无法正常上传。
<ul>
<li>转到 空间管理 - 基础设置 - 跨域设置;</li>
<li>创建规则,其中来源填写“*”,允许 Methods全部勾选,允许 Headers填写“*”,其他保持默认,点击确定保存.</li>
</ul>
</div>
<div class="card" >
<div class="card-header">
添加阿里云OSS上传策略
</div>
<div class="card-body">
<form id="ossPolicy">
<input type="text" class="form-control" name="policy_type" value="oss" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="ak" class="col-form-label col-form-label-sm">Access Key ID </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="ak" pattern="[^\s]+" title="请不要包含空格" required></div>
<div class="col-md-4 option-des"> 阿里云账号的Access Key ID,请在阿里云控制面板-Access Key管理中创建或查看</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="sk" class="col-form-label col-form-label-sm"> Access Key Secret </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="sk" pattern="[^\s]+" title="请不要包含空格" required></div>
<div class="col-md-4 option-des"> 获取方法同上一项</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="bucketname" class="col-form-label col-form-label-sm">Bucket名称 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
<div class="col-md-4 option-des"> 创建空间时填写的Bucket名</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">读写权限</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="bucket_private" id="oss_private_1" value="1" checked>
<label class="" for="oss_private_1" >私有</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="bucket_private" id="oss_private_0" value="0">
<label class="" for="oss_private_0">公共读</label>
</div>
<div class="col-md-4 option-des"> 与OSS空间访问控制设置保持一致,推荐设置为私有空间</div>
</div>
<div class="row form-setting" id="oss_outlink" style="display: none">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">允许获取外链</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="origin_link" id="oss_allowd_origin1" value="1" >
<label class="" for="oss_allowd_origin1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="origin_link" id="oss_allowd_origin2" value="0" checked>
<label class="" for="oss_allowd_origin2">禁止</label>
</div>
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">空间域名</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" value="http(s)://" required>
</div>
<div class="col-md-4 option-des"> OSS空间绑定的域名,用于文件下载、访问,结尾要加"/"(推荐配合阿里云CDN使用,此处填写CDN域名)</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="server" class="col-form-label col-form-label-sm">上传域名</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="server" value="http(s)://" required>
</div>
<div class="col-md-4 option-des"> OSS空间的域名,一般与上一项保持一致。(如果上一项填写的是CDN域名,则此处与上一项不应相同)</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">允许的文件后缀</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="autoname" id="oss_autoname1" value="1" checked>
<label class="" for="oss_autoname1" >开启</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="autoname" id="oss_autoname2" value="0" >
<label class="" for="oss_autoname2">关闭</label>
</div>
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
</div>
<div class="row form-setting" id="oss_autoname_form" >
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="namerule" value="{uid}_{randomkey8}_{originname}" spellcheck="false" required>
</div>
<div class="col-md-4 option-des"> 你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTable">变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
</div>
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTableFolder">目录变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveOss">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
</div>
<div class="card" id="upyun" style="display: none">
<div class="card-header">
又拍云
</div>
<div class="card-body">
<form id="upyunPolicy">
<input type="text" class="form-control" name="policy_type" value="upyun" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="ak" class="col-form-label col-form-label-sm">操作员名称 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="op_name" required></div>
<div class="col-md-4 option-des"> 创建存储服务时授权的操作员名称</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="sk" class="col-form-label col-form-label-sm">操作员密码 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="op_pwd" required></div>
<div class="col-md-4 option-des"> 创建存储服务时授权的操作员密码</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="bucketname" class="col-form-label col-form-label-sm">存储服务名 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
<div class="col-md-4 option-des"> 创建存储服务时填写的名称</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">Token 防盗链</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="bucket_private" id="upyun_bucket_private_1" value="1" checked>
<label class="" for="upyun_bucket_private_1" >开启</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="bucket_private" id="upyun_bucket_private_0" value="0">
<label class="" for="upyun_bucket_private_0">关闭</label>
</div>
<div class="col-md-4 option-des"> 与 功能配置-访问配置-Token 防盗链 保持一致,推荐设置为开启</div>
</div>
<div class="row form-setting" id="upyun_token" style="">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">防盗链密钥</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="sk"></div>
<div class="col-md-4 option-des"> 与 功能配置-访问配置-Token防盗链 中的密钥保持一致</div>
</div>
<div class="row form-setting" id="upyun_outlink" style="display: none">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">允许获取外链</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="origin_link" id="upyun_allowd_origin1" value="1" >
<label class="" for="upyun_allowd_origin1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="origin_link" id="upyun_allowd_origin2" value="0" checked>
<label class="" for="upyun_allowd_origin2">禁止</label>
</div>
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">空间域名</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" required>
</div>
<div class="col-md-4 option-des"> 绑定的域名,开头要加http(s)://结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">允许的文件后缀</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<input type="text" name="autoname" value="1" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
</div>
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTableFolder">目录变量对照表</a>中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveUpyun">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
<br>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
<div class="modal fade" tabindex="-1" role="dialog" id="varTable">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">自动重命名变量对照表</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th >变量字段</th>
<th >说明</th>
<th >示例</th>
<th >适用范围</th>
</tr>
</thead>
<tbody>
<tr>
<td >{date}</td>
<td>上传日期</td>
<td>20180118</td>
<td>全部</td>
</tr>
<tr>
<td >{datetime}</td>
<td>上传日期时间</td>
<td>20180118121049</td>
<td>全部</td>
</tr>
<tr>
<td >{uid}</td>
<td>上传者UID</td>
<td>154</td>
<td>全部</td>
</tr>
<tr>
<td >{timestamp}</td>
<td>时间戳</td>
<td>1516277624</td>
<td>全部</td>
</tr>
<tr>
<td >{randomkey16}</td>
<td>16位随机字符</td>
<td>16D8lhjErTDWAQjW</td>
<td>全部</td>
</tr>
<tr>
<td >{randomkey8}</td>
<td>8位随机字符</td>
<td>hM4Tpdh6</td>
<td>全部</td>
</tr>
<tr>
<td >{originname}</td>
<td>原始文件名</td>
<td>plus1s.jpg</td>
<td>全部</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="varTableFolder">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">目录变量对照表</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th >变量字段</th>
<th >说明</th>
<th >示例</th>
<th >适用范围</th>
</tr>
</thead>
<tbody>
<tr>
<td >{date}</td>
<td>上传日期</td>
<td>20180118</td>
<td>全部</td>
</tr>
<tr>
<td >{datetime}</td>
<td>上传日期时间</td>
<td>20180118121049</td>
<td>全部</td>
</tr>
<tr>
<td >{uid}</td>
<td>上传者UID</td>
<td>154</td>
<td>全部</td>
</tr>
<tr>
<td >{timestamp}</td>
<td>时间戳</td>
<td>1516277624</td>
<td>全部</td>
</tr>
<tr>
<td >{randomkey16}</td>
<td>16位随机字符</td>
<td>16D8lhjErTDWAQjW</td>
<td>全部</td>
</tr>
<tr>
<td >{randomkey8}</td>
<td>8位随机字符</td>
<td>hM4Tpdh6</td>
<td>全部</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/add_policy.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,170 @@
{extend name="header_admin" /}
{block name="title"}添加上传策略- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item">
<a href="/Admin/PolicyAdd">上传策略</a>
</li>
<li class="breadcrumb-item active">添加</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>添加上传策略</h2>
<br>
<div class="card" id="s3" >
<div class="card-header">
添加远程上传策略
</div>
<div class="card-body">
<form id="qiniuPolicy">
<input type="text" class="form-control" name="policy_type" value="remote" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="ak" class="col-form-label col-form-label-sm">AccessToken </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="sk" required></div>
<div class="col-md-4 option-des"> 默认随机生成,请与远程服务端配置文件中保持一致</div>
</div>
<input type="text" class="form-control" name="ak" value="0" style="display: none" required>
<input type="text" name="bucket_private" value="1" style="display: none">
<input type="text" name="origin_link" value="0" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">服务端URL</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="server" required>
</div>
<div class="col-md-4 option-des"> 结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">下载根URL</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" required>
</div>
<div class="col-md-4 option-des"> 一般与上一步保持一致,结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="autoname" id="autoname1" value="1" checked>
<label class="" for="autoname1" >开启</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="autoname" id="autoname2" value="0" >
<label class="" for="autoname2">关闭</label>
</div>
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
</div>
<div class="row form-setting" id="autoname_form" >
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="namerule" value="{uid}_{randomkey8}_{originname}" spellcheck="false" required>
</div>
<div class="col-md-4 option-des"> 你可以使用变量对照表中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
</div>
<div class="col-md-4 input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon2">
/public/uploads/
</span>
</div>
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
</div>
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用目录变量对照表中的字段填写</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveQiniu">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
<br>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/add_policy.js"></script>
<script type="text/javascript">
function randomString(len) {
  len = len || 32;
  var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  var maxPos = $chars.length;
  var pwd = '';
  for (i = 0; i < len; i++) {
    pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
}
$("[name='sk']").val(randomString(32));
</script>
{/block}
@@ -0,0 +1,175 @@
{extend name="header_admin" /}
{block name="title"}添加上传策略- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item">
<a href="/Admin/PolicyAdd">上传策略</a>
</li>
<li class="breadcrumb-item active">添加</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>添加上传策略</h2>
<br>
<div class="alert alert-primary" role="alert">
创建储存桶后请在储存桶控制面板添加CORS跨域规则,允许本站的POST请求。请确保您的服务器和用户可以正常连接到AWS服务器。
</ul>
</div>
<div class="card" id="s3" >
<div class="card-header">
添加S3上传策略
</div>
<div class="card-body">
<form id="qiniuPolicy">
<input type="text" class="form-control" name="policy_type" value="s3" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="ak" class="col-form-label col-form-label-sm">AWSAccessKeyId </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="ak" required></div>
<div class="col-md-4 option-des"> AWS账户的访问秘钥信息,请在 控制面板 - 您的安全凭证 中创建</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="sk" class="col-form-label col-form-label-sm">AWSSecretKey </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="sk" required></div>
<div class="col-md-4 option-des"> 同上一项获取</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="bucketname" class="col-form-label col-form-label-sm">存储桶名称 </label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
<div class="col-md-4 option-des"> 创建桶时填写的名称</div>
</div>
<input type="text" name="bucket_private" value="1" style="display: none">
<input type="text" name="origin_link" value="0" style="display: none">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">下载根URL</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="url" required>
</div>
<div class="col-md-4 option-des"> 一般格式为:https://s3-分区名.amazonaws.com/储存桶名/ 结尾要加"/"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">上传服务器URL</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="server" required>
</div>
<div class="col-md-4 option-des"> 一般格式为:https://储存桶名.s3-分区代号.amazonaws.com/</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">储存区域</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="op_name" required>
</div>
<div class="col-md-4 option-des"> 例如:ap-southeast-1</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="url" class="col-form-label col-form-label-sm">EndPoint</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="op_name" required>
</div>
<div class="col-md-4 option-des"> 一般格式为:s3-储存区域.amazonaws.com,只填写域名部分</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">允许的文件后缀</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
</div>
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
</div>
<input type="text" name="autoname" value="0" style="display: none">
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{uid}" style="display: none" required>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveQiniu">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
<bn>
</div>
<br>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/add_policy.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,229 @@
{extend name="header_admin" /}
{block name="title"}管理面板- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="#">管理面板</a>
</li>
<li class="breadcrumb-item active">数据概况</li>
</ol>
<!-- Icon Cards-->
<div class="row">
<div class="col-xl-3 col-sm-6 mb-3">
<div class="card text-white bg-primary o-hidden h-100">
<div class="card-body">
<div class="card-body-icon">
<i class="fa fa-fw fa-users"></i>
</div>
<div class="mr-5">{$statics.userNum} 位用户</div>
</div>
<a class="card-footer text-white clearfix small z-1" href="/Admin/Users">
<span class="float-left">查看详情</span>
<span class="float-right">
<i class="fa fa-angle-right"></i>
</span>
</a>
</div>
</div>
<div class="col-xl-3 col-sm-6 mb-3">
<div class="card text-white bg-warning o-hidden h-100">
<div class="card-body">
<div class="card-body-icon">
<i class="fa fa-fw fa-file"></i>
</div>
<div class="mr-5">{$statics.fileNum} 个文件</div>
</div>
<a class="card-footer text-white clearfix small z-1" href="/Admin/Files">
<span class="float-left">查看详情</span>
<span class="float-right">
<i class="fa fa-angle-right"></i>
</span>
</a>
</div>
</div>
<div class="col-xl-3 col-sm-6 mb-3">
<div class="card text-white bg-success o-hidden h-100">
<div class="card-body">
<div class="card-body-icon">
<i class="fa fa-fw fa-share-alt"></i>
</div>
<div class="mr-5">{$statics.publicShareNum} 个公开分享</div>
</div>
<a class="card-footer text-white clearfix small z-1" href="/Admin/Shares">
<span class="float-left">查看详情</span>
<span class="float-right">
<i class="fa fa-angle-right"></i>
</span>
</a>
</div>
</div>
<div class="col-xl-3 col-sm-6 mb-3">
<div class="card text-white bg-danger o-hidden h-100">
<div class="card-body">
<div class="card-body-icon">
<i class="fa fa-fw fa-lock"></i>
</div>
<div class="mr-5">{$statics.privateShareNum} 个私密分享</div>
</div>
<a class="card-footer text-white clearfix small z-1" href="/Admin/Shares">
<span class="float-left">查看详情</span>
<span class="float-right">
<i class="fa fa-angle-right"></i>
</span>
</a>
</div>
</div>
</div>
<!-- Area Chart Example-->
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-area-chart"></i> 近期趋势</div>
<div class="card-body">
<canvas id="myAreaChart" width="100%" height="30"></canvas>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<!-- Example Bar Chart Card-->
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-bell-o"></i> 订阅新闻</div>
<div class="list-group list-group-flush small" id="news">
</div>
</div>
<!-- Card Columns Example Social Feed-->
<!-- /Card Columns-->
</div>
<div class="col-lg-4">
<!-- Example Pie Chart Card-->
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-pie-chart"></i> 文件组成</div>
<div class="card-body">
<canvas id="myPieChart" width="100%" height="80"></canvas>
</div>
<div class="card-footer small text-muted">*此结果仅供参考</div>
</div>
<!-- Example Notifications Card-->
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
<!-- /.content-wrapper-->
<footer class="sticky-footer">
<div class="container">
<div class="text-center">
<small>Copyright © Cloudreve {php}echo date("Y");{/php} </small>
</div>
</div>
</footer>
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fa fa-angle-up"></i>
</a>
<!-- Logout Modal-->
<!-- Bootstrap core JavaScript-->
{/block}
{block name="js"}
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("https://cloudreve.org/api/notice/?callback=?", function(data){
$("#news").html(data[0]);
})
})
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif',
Chart.defaults.global.defaultFontColor = "#292b2c";
var ctx = document.getElementById("myAreaChart"),
myLineChart = new Chart(ctx, {
type: "line",
data: {
labels: [{$statics.trendDate}],
datasets: [{
label: "上传文件",
lineTension: .3,
backgroundColor: "rgba(2,117,216,0.2)",
borderColor: "rgba(2,117,216,1)",
pointRadius: 5,
pointBackgroundColor: "rgba(2,117,216,1)",
pointBorderColor: "rgba(255,255,255,0.8)",
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(2,117,216,1)",
pointHitRadius: 20,
pointBorderWidth: 2,
data: [{$statics.trendFile}]
},{
label: "注册用户",
lineTension: .3,
backgroundColor: "rgba(83, 216, 2, 0.2)",
borderColor: "#4CAF50",
pointRadius: 5,
pointBackgroundColor: "#4CAF50",
pointBorderColor: "rgba(255,255,255,0.8)",
pointHoverRadius: 5,
pointHoverBackgroundColor: "#4CAF50",
pointHitRadius: 20,
pointBorderWidth: 2,
data: [{$statics.trendUser}]
},
]
},
options: {
scales: {
xAxes: [{
time: {
unit: "date"
},
gridLines: {
display: !1
},
ticks: {
maxTicksLimit: 7
}
}],
yAxes: [{
ticks: {
maxTicksLimit: 5
},
gridLines: {
color: "rgba(0, 0, 0, .125)"
}
}]
},
legend: {
display: !1
}
}
}),
ctx = document.getElementById("myPieChart"),
myPieChart = new Chart(ctx, {
type: "pie",
data: {
labels: ["其他", "图片", "音频", "视频"],
datasets: [{
data: [{$statics.otherRate}, {$statics.imgRate}, {$statics.audioRate}, {$statics.videoRate}],
backgroundColor: ["#007bff", "#dc3545", "#ffc107", "#28a745"]
}]
}
});
</script>
{/block}
@@ -0,0 +1,83 @@
{extend name="header_admin" /}
{block name="title"}基础设置- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">设置</li>
<li class="breadcrumb-item active">基础设置</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>基础设置</h2>
<br>
<form id="basicOptionsForm">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点主标题</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="siteName" value="{$options.siteName}"></div>
<div class="col-md-4 option-des"> 站点的主标题,将会展示在个页面的标题尾部、邮件中。</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点副标题</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="siteTitle" value="{$options.siteTitle}"></div>
<div class="col-md-4 option-des"> 只会展示在首页的副标题。</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点URL</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="siteURL" value="{$options.siteURL}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 站点的URL,此设置很重要,请如实填写,否则会影响系统正常工作.</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点关键词</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="siteKeywords" value="{$options.siteKeywords}"></div>
<div class="col-md-4 option-des"> 位于首页meta标签内的站点关键词</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点描述</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="siteDes" value="{$options.siteDes}"></div>
<div class="col-md-4 option-des"> 位于首页meta标签内的站点描述</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">页脚代码</label>
</div>
<div class="col-md-4"> <textarea class="form-control" name="js_code" rows="4" spellcheck="false">{$options.js_code}</textarea></div>
<div class="col-md-4 option-des"> 位于前台页面底部的页脚代码,你可以在此放置统计代码。</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveBasic">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br> <br>
</div>
</form>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/setting.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,51 @@
{extend name="header_admin" /}
{block name="title"}基础设置- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">设置</li>
<li class="breadcrumb-item active">配置文件</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>配置文件</h2>
{$path}
<br> <br>
<div class="row">
<div class="col-md-9">
<input type="text" id="configType" value="{$type}" style="display: none">
<textarea rows="15" class="form-control" spellcheck="false">{$content}</textarea>
<br>
<button class="btn btn-primary" id="save">保存</button>
<br><br>
</div>
<div class="col-md-3">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link" id="v-pills-home-tab" href="/Admin/Config/type/common" role="tab" data-type="common">系统公共配置</a>
<a class="nav-link" id="v-pills-profile-tab" href="/Admin/Config/type/database" role="tab" data-type="database">数据库</a>
<a class="nav-link" id="v-pills-messages-tab" href="/Admin/Config/type/route" role="tab" data-type="route">路由</a>
<a class="nav-link" id="v-pills-settings-tab" href="/Admin/Config/type/tags" role="tab" data-type="tags">行为扩展</a>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/config.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,84 @@
{extend name="header_admin" /}
{block name="title"}基础设置- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">其他</li>
<li class="breadcrumb-item active">定时任务</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>定时任务</h2>
<br>
{eq name="neverExcute" value="true"}
<div class="alert alert-warning" role="alert">
定时任务从未执行!请将 {$options.siteURL}Cron 加入到您的定时任务列队中(如Crontab)。
</div>
{/eq}
{volist name="cron" id="c"}
<div class="card">
<div class="card-header">
{$c.name}
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>{$c.des}</p>
</blockquote><form id="cronForm" method="post" action="/Admin/SaveCron">
<div class="row">
<input type="text" name="id" value="{$c.id}" style="display: none;">
<div class="col-md-4">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">优先级</span>
</div>
<input type="number" min="0" class="form-control" name="rank" placeholder="值越高越优先" value="{$c.rank}">
</div>
</div>
<div class="col-md-4">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">执行间隔(s)</span>
</div>
<input type="number" min="1" class="form-control" name="interval_s" value="{$c.interval_s}">
</div>
</div>
<div class="col-md-4">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">启用</span>
</div>
<input type="number" min="0" max="1" class="form-control" name="enable" value="{$c.enable}">
</div>
</div>
</div>
<input type="submit" class="btn btn-primary" value="保存">
</form>
</div>
<div class="card-footer text-muted">
上次执行:{eq name="c.last_excute" value="0"}从未执行{else/}{:date("Y-m-d H:i:s",$c.last_excute)}{/eq}
</div>
</div><br>
{/volist}
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,171 @@
{extend name="header_admin" /}
{block name="title"}注册访问- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">用户组</li>
<li class="breadcrumb-item active">编辑用户组</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>编辑用户组</h2>
<br>
<form id="editGroup">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<input type="text" name="id" value="{$group.id}" style="display: none">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组名</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="group_name" value="{$group.group_name}" required></div>
<div class="col-md-4 option-des"> 用户组的名称</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">上传策略</label>
</div>
<div class="col-md-4">
<select name="policy_name" required class="form-control" >
{volist name="policy" id="p"}
<option value="{$p.id}">{$p.policy_name}</option>
{/volist}
</select>
</div>
<div class="col-md-4 option-des"> 为该用户组绑定一个上传策略</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">初始容量</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="max_storage" spellcheck="false" min="0" value="{:countSize($group.max_storage,true)[0]}" required>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
<select name="sizeTimes" class="selectIn" data-value="{:countSize($group.max_storage,true)[1]}">
<option value="1">B</option>
<option value="1024">KB</option>
<option value="1048576" selected>MB</option>
<option value="1073741824">GB</option>
</select>
</span>
</div>
</div>
<div class="col-md-4 option-des"> 该用户组初始最大可用容量</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">下载限速</label>
</div>
<div class="col-md-4 input-group mb-3">
<input type="number" class="form-control" name="speed" spellcheck="false" min="0" placeholder="留空表示不限速,0表示禁止下载" value="{$group.speed}">
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">
Kb/s
</span>
</div>
</div>
<div class="col-md-4 option-des"> 限制该用户组下的用户上传的文件的下载速度,<strong>此设置仅对本地上传方案有效</strong></div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">断点续传及多线程下载</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="range_transfer" value="1" id="allow_range_1">
<label class="" for="allow_range_1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="range_transfer" id="allow_range_0" value="0" >
<label class="" for="allow_range_0">禁止</label></div>
<div class="col-md-4 option-des"> 是否断点续传及多线程下载,关闭后预览视频不支持拖拽播放,<strong>此设置仅对本地上传方案有效</strong></div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">创建分享</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="allow_share" value="1" id="allow_share_1" checked>
<label class="" for="allow_share_1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="allow_share" id="allow_share_0" value="0" >
<label class="" for="allow_share_0">禁止</label></div>
<div class="col-md-4 option-des"> 是否允许创建文件分享链接</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">WebDAV支持</label>
</div>
<div class="col-md-4"> <input class="" type="radio" name="webdav" value="1" id="webdav1" checked>
<label class="" for="webdav1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="webdav" id="webdav0" value="0" >
<label class="" for="webdav0">禁止</label></div>
<div class="col-md-4 option-des"> 是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组标志色</label>
</div>
<div class="col-md-4">
<input class="" type="radio" name="color" value="default" id="default" checked>
<label class="" for="default" ><span class="badge badge-primary">蓝色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="primary" id="primary">
<label class="" for="primary" ><span class="badge badge-secondary">灰色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="success" id="success">
<label class="" for="success" ><span class="badge badge-success">绿色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="danger" id="danger">
<label class="" for="danger" ><span class="badge badge-danger">红色</span></label>
<br>
<input class="" type="radio" name="color" value="warning" id="warning">
<label class="" for="warning" ><span class="badge badge-warning">黄色</span></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="color" value="info" id="info">
<label class="" for="info" ><span class="badge badge-info">浅蓝色</span></label>
&nbsp;&nbsp;&nbsp;
</div>
<div class="col-md-4 option-des"> 用户个人主页展示用户组时的徽章颜色</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveGroup">保存</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/add_group.js"></script>
<script type="text/javascript">
$("option[value='{$group.policy_name}']").attr("selected",true);
$("option[value='{$group.max_storage}']").attr("selected",true);
$("input[name='range_transfer'][value='{$group.range_transfer}']").attr("checked",true);
$("input[name='allow_share'][value='{$group.allow_share}']").attr("checked",true);
$("input[name='color'][value='{$group.color}']").attr("checked",true);
$("input[name='webdav'][value='{$group.webdav}']").attr("checked",true);
</script>
{/block}
File diff suppressed because it is too large Load Diff
+194
View File
@@ -0,0 +1,194 @@
{extend name="header_admin" /}
{block name="title"}文件列表- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">文件</li>
</ol>
<div class="row">
<div class="col-12">
<h2>文件</h2>
<br>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-tags"></i> 条件检索</div>
<div class="card-body">
<div class="row">
<div class="col-1 form-label-search mb-2">排序方式</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="order">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">日期</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="orign_name ASC">文件名</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="size DESC">大小</a>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-1 form-label-search mb-2">上传策略</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="policy_select">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="">全部</a>
</li>
{volist name="policy" id="policy"}
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="{$policy.id}">{$policy.policy_name}</a>
</li>
{/volist}
</ul>
</div>
</div>
<div class="row" style="margin-top: 5px;">
<div class="col-1 form-label-search mb-2">高级检索</div>
<div class="col-md-10">
<div class="row">
<div class="col-md-2">
<select class="form-control form-control-sm" id="searchCol">
<option value="id" selected>ID</option>
<option value="orign_name">文件名</option>
<option value="pre_name">实际文件名</option>
<option value="upload_user">上传者UID</option>
<option value="upload_date">上传日期</option>
<option value="pic_info">图像尺寸</option>
<option value="parent_folder">所属目录ID</option>
<option value="policy_id">上传策略ID</option>
<option value="dir">目录路径</option>
</select>
</div>
<div class="col-md-2">
<input type="text" class="form-control form-control-sm" placeholder="检索表达式" id="searchValue">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-primary btn-sm" id="applySearch">应用</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table"></i> 文件列表</div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select></label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
<div class="table-responsive">
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>文件名</th><th class="textCenter">大小</th><th class="textCenter">上传者</th><th class="textCenter">日期</th><th class="textCenter">操作</th></tr>
</thead>
<tfoot>
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1">文件名</th><th rowspan="1" colspan="1" class="textCenter">大小</th><th rowspan="1" colspan="1" class="textCenter">上传者</th><th rowspan="1" colspan="1" class="textCenter">日期</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
</tfoot>
<tbody>
<tr role="row" class="odd" id="fileList">
{volist name='list' id='file'}
<tr role="row" class="odd">
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-path="{:rtrim($file.dir,'/')}/{$file.orign_name}" data-uid="{$file.upload_user}"></td>
<td>
{eq name=":isPreview($file.orign_name)" value="yes"}
<a href="/Admin/Preview/id/{$file.id}" class="noAColor" target="_blank">{$file.orign_name|htmlspecialchars=ENT_NOQUOTES}</a>
{else}
<a href="/Admin/Download/id/{$file.id}" class="noAColor" target="_blank">{$file.orign_name|htmlspecialchars=ENT_NOQUOTES}</a>
{/eq}
</td>
<td class="textCenter">{:countSize($file.size)}</td>
<td class="textCenter">{$originList[$key]["user"]["user_nick"]}</td>
<td class="textCenter">{$file.upload_date}</td>
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$file.id}"><i class="fa fa-trash" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="下载" data-action="download" data-id="{$file.id}"><i class="fa fa-download" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="详情" data-action="info" data-id="{$file.id}"><i class="fa fa-info-circle" aria-hidden="true"></i></button>
</td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
</div>
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
{$list->render()}
</div></div></div></div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12"><strong>ID:</strong></div>
<div class="col-md-12 break" id="fileId">12</div>
</div>
<div class="row">
<div class="col-md-12"><strong>文件名:</strong></div>
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>源文件名:</strong></div>
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传者UID:</strong></div>
<div class="col-md-12 break" id="fileUID">17</div>
</div>
<div class="row">
<div class="col-md-12"><strong>大小(字节):</strong></div>
<div class="col-md-12 break" id="fileSize">7481817</div>
</div>
<div class="row">
<div class="col-md-12"><strong>图像尺寸:</strong></div>
<div class="col-md-12 break" id="filePic">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传策略:</strong></div>
<div class="col-md-12 break" id="filePolicy">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>所属目录:</strong></div>
<div class="col-md-12 break" id="fileDir">147,445</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/files.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,131 @@
{extend name="header_admin" /}
{block name="title"}上传策略- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">用户组</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>用户组</h2>
<br>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table"></i> 用户组列表</div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select></label></div></div></div><div class="row"><div class="col-sm-12">
<div class="table-responsive">
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row" class="textCenter"><th>#</th><th>名称</th><th class="textCenter">上传策略</th><th class="textCenter">最大容量</th><th class="textCenter">下属用户数</th><th class="textCenter">操作</th></tr>
</thead>
<tfoot>
<tr><th rowspan="1" colspan="1" class="textCenter">#</th><th rowspan="1" colspan="1">名称</th><th rowspan="1" colspan="1" class="textCenter">上传策略</th><th rowspan="1" colspan="1" class="textCenter">最大容量</th><th rowspan="1" colspan="1" class="textCenter">下属用户数</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
</tfoot>
<tbody>
<tr role="row" class="odd" id="fileList">
{volist name='list' id='group'}
<tr role="row" class="odd">
<td class="sorting_1 textCenter">{$group.id}</td>
<td>
{$group.group_name}
</td>
<td class="textCenter">
{$originList[$key]["policy"]["policy_name"]}
</td>
<td class="textCenter">{:countSize($group["max_storage"])}</td>
<td class="textCenter">{$originList[$key]["user_num"]}</td>
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$group.id}" data-unable="{eq name="$originList[$key]['user_num']" value="0"}0{else}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$group.id}"><i class="fa fa-edit" aria-hidden="true"></i></button>
</td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
</div>
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
{$list->render()}
</div></div></div></div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12"><strong>ID:</strong></div>
<div class="col-md-12 break" id="fileId">12</div>
</div>
<div class="row">
<div class="col-md-12"><strong>文件名:</strong></div>
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>源文件名:</strong></div>
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传者UID:</strong></div>
<div class="col-md-12 break" id="fileUID">17</div>
</div>
<div class="row">
<div class="col-md-12"><strong>大小(字节):</strong></div>
<div class="col-md-12 break" id="fileSize">7481817</div>
</div>
<div class="row">
<div class="col-md-12"><strong>图像尺寸:</strong></div>
<div class="col-md-12 break" id="filePic">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传策略:</strong></div>
<div class="col-md-12 break" id="filePolicy">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>所属目录:</strong></div>
<div class="col-md-12 break" id="fileDir">147,445</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/group_list.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,206 @@
{extend name="header_admin" /}
{block name="title"}邮件收发- {$options.siteName}{/block}
{block name="content"}
<link href="/static/css/admin/summernote.css" rel="stylesheet">
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">设置</li>
<li class="breadcrumb-item active">邮件设置</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>邮件收发</h2>
<br>
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#basic" role="tab" aria-controls="pills-home" aria-selected="true">基本设置</a>
</li>
<li class="nav-item">
<a class="nav-link" id="pills-profile-tab" data-toggle="pill" href="#test" role="tab" aria-controls="pills-profile" aria-selected="false">发信测试</a>
</li>
<li class="nav-item">
<a class="nav-link" id="pills-contact-tab" data-toggle="pill" href="#template" role="tab" aria-controls="pills-contact" aria-selected="false">邮件模板</a>
</li>
</ul>
<div class="tab-content" >
<div class="tab-pane fade show active" id="basic" role="tabpanel" aria-labelledby="pills-home-tab">
<form id="basicOptionsForm">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">发件人姓名</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="fromName" value="{$optionsForSet.fromName}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 显示在邮件发件邮箱旁的发件人姓名</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromAdress" class="col-form-label col-form-label-sm">发件人邮箱</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="fromAdress" value="{$optionsForSet.fromAdress}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 发件邮箱的地址</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="smtpHost" class="col-form-label col-form-label-sm">SMTP服务器</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="smtpHost" value="{$optionsForSet.smtpHost}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 发信邮箱的SMTP服务器地址</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="smtpPort" class="col-form-label col-form-label-sm">端口</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="smtpPort" value="{$optionsForSet.smtpPort}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 发信邮箱SMTP服务器的端口</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="smtpPort" class="col-form-label col-form-label-sm">加密方式</label>
</div>
<div class="col-md-4">
<select class="form-control" name="encriptionType">
<option value="no" {eq name="$optionsForSet.encriptionType" value="no"}selected{/eq}>不启用</option>
<option value="tls" {eq name="$optionsForSet.encriptionType" value="tls"}selected{/eq}>TLS</option>
<option value="ssl" {eq name="$optionsForSet.encriptionType" value="ssl"}selected{/eq}>SSL</option>
</select>
</div>
<div class="col-md-4 option-des"> </div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="smtpUser" class="col-form-label col-form-label-sm">用户名</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="smtpUser" value="{$optionsForSet.smtpUser}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 发信邮箱用户名,一般与邮箱相同</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="smtpPass" class="col-form-label col-form-label-sm">密码</label>
</div>
<div class="col-md-4"> <input type="password" class="form-control" name="smtpPass" value="{$optionsForSet.smtpPass}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 发信邮箱密码</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="replyTo" class="col-form-label col-form-label-sm">回信邮箱</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="replyTo" value="{$optionsForSet.replyTo}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 用户回复系统发送的邮件时,用于接收回信的邮箱</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveMail">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
<div class="tab-pane fade" id="test" role="tabpanel" aria-labelledby="pills-profile-tab">
<form id="testMail">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">收件人邮箱</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="receiveMail" spellcheck="false"></div>
<div class="col-md-4 option-des"> 接受测试邮件的收件人邮箱</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">主题</label>
</div>
<div class="col-md-4"> <input type="text" class="form-control" name="subject" spellcheck="false" value="这是一封测试邮件"></div>
<div class="col-md-4 option-des"> 测试邮件的主题</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">正文</label>
</div>
<div class="col-md-8"> <textarea class="form-control" name="content" spellcheck="false" id="content" > 这是一封由Cloudreve发出的测试邮件,用于测试邮件设置是否正常工作。</textarea></div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="sendMail">发送测试邮件</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
<div class="tab-pane fade" id="template" role="tabpanel" aria-labelledby="pills-profile-tab">
<form id="mailTemplate">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">账户激活</label>
</div>
<div class="col-md-8"> <textarea class="form-control textEdit" name="mail_activation_template" spellcheck="false" > {$optionsForSet.mail_activation_template}</textarea>
</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="fromName" class="col-form-label col-form-label-sm">重设密码</label>
</div>
<div class="col-md-8"> <textarea class="form-control textEdit" name="mail_reset_pwd_template" spellcheck="false" > {$optionsForSet.mail_reset_pwd_template}</textarea>
</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveTemplate">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/summernote.min.js"></script>
<script src="/static/js/admin/summernote-zh-CN.min.js"></script>
<script src="/static/js/admin/setting.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#content').summernote({
lang:"zh-CN",
height: 150,
});
});
$(document).ready(function() {
$('.textEdit').summernote({
lang:"zh-CN",
height: 300,
});
});
</script>
{/block}
@@ -0,0 +1,127 @@
{extend name="header_admin" /}
{block name="title"}注册访问- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">设置</li>
<li class="breadcrumb-item active">杂项</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>杂项设置</h2>
<br>
<form id="mailTemplate">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="maxEditSize" class="col-form-label col-form-label-sm">文本编辑大小限制</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="maxEditSize" value="{$optionsForSet.maxEditSize}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 用户可在线编辑的文本类文件的最大尺寸。单位:字节</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="maxEditSize" class="col-form-label col-form-label-sm">允许游客下载</label>
</div>
<div class="col-md-4">
{eq name="$optionsForSet.allowdVisitorDownload" value="true"}
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio1" value="true" checked>
<label class="" for="inlineRadio1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio2" value="false">
<label class="" for="inlineRadio2">拒绝</label>
{else}
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio1" value="true">
<label class="" for="inlineRadio1" >允许</label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio2" value="false" checked>
<label class="" for="inlineRadio2">拒绝</label>
{/eq}
</div>
<div class="col-md-4 option-des"> 是否允许未登录用户下载被分享的文件</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="hot_share_num" class="col-form-label col-form-label-sm">热门分享展示数量</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="hot_share_num" value="{$optionsForSet.hot_share_num}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 在用户个人主页展示的热门分享的个数</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="gravatar_server" class="col-form-label col-form-label-sm">Gravatar服务器</label>
</div>
<div class="col-md-4"> <input type="email" class="form-control" name="gravatar_server" value="{$optionsForSet.gravatar_server}" spellcheck="false"></div>
<div class="col-md-4 option-des"> 用于展示用户头像的Gravatar服务器地址</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="gravatar_server" class="col-form-label col-form-label-sm">文件数据发送模式</label>
</div>
<div class="col-md-4">
<select class="form-control" name="sendfile">
<option value="0">传统</option>
<option value="1" {eq name="optionsForSet.sendfile" value="1"}selected{/eq}>X-Sendfile</option>
</select>
</div>
<div class="col-md-4 option-des"> 推荐使用X-Sendfile以获得高效的文件传输,启用前请确保服务器安装X-Sendfile模块并在站点配置文件中启用。</div>
</div>
<div class="row form-setting" style="{eq name="optionsForSet.sendfile" value="0"}display:none{/eq}" id="sendfile_header">
<div class="col-md-1 form-label ">
<label for="gravatar_server" class="col-form-label col-form-label-sm">Sendfile Header</label>
</div>
<div class="col-md-4">
<select class="form-control" name="header">
<option value="X-Sendfile" {eq name="optionsForSet.header" value="X-Sendfile"}selected{/eq}>X-Sendfile [Apache,Lighttpd v1.5,Cherokee]</option>
<option value="X-LIGHTTPD-send-file" {eq name="optionsForSet.header" value="X-LIGHTTPD-send-file"}selected{/eq}>X-LIGHTTPD-send-file [Lighttpd v1.4]</option>
<option value="X-Accel-Redirect" {eq name="optionsForSet.header" value="X-Accel-Redirect"}selected{/eq}>X-Accel-Redirect [Nginx,Cherokee]</option>
</select>
</div>
<div class="col-md-4 option-des"> 请根据你所使用的服务器软件选择合适的header</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveTemplate">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/setting.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,172 @@
{extend name="header_admin" /}
{block name="title"}上传策略- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">上传策略</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>上传策略</h2>
<br>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-tags"></i> 条件检索</div>
<div class="card-body">
<div class="row">
<div class="col-1 form-label-search mb-2">类型</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="policyType">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="">全部</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="local">本地</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="qiniu">七牛</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="oss">OSS</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="upyun">又拍云</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="s3">S3</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-policy="remote">远程</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table"></i> 上传策略列表</div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select></label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
<div class="table-responsive">
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row" class="textCenter"><th>#</th><th>名称</th><th class="textCenter">类型</th><th class="textCenter">下属文件数</th><th class="textCenter">数据量</th><th class="textCenter">操作</th></tr>
</thead>
<tfoot>
<tr><th rowspan="1" colspan="1" class="textCenter">#</th><th rowspan="1" colspan="1">名称</th><th rowspan="1" colspan="1" class="textCenter">类型</th><th rowspan="1" colspan="1" class="textCenter">下属文件数</th><th rowspan="1" colspan="1" class="textCenter">数据量</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
</tfoot>
<tbody>
<tr role="row" class="odd" id="fileList">
{volist name='list' id='policy'}
<tr role="row" class="odd">
<td class="sorting_1 textCenter">{$policy.id}</td>
<td>
{$policy.policy_name}
</td>
<td class="textCenter">
{switch name="policy.policy_type"}
{case value="local"}本地{/case}
{case value="qiniu"}七牛{/case}
{case value="oss"}OSS{/case}
{case value="upyun"}又拍云{/case}
{case value="s3"}Amazon S3{/case}
{case value="remote"}远程{/case}
{default /}其他
{/switch}
</td>
<td class="textCenter">{$originList[$key]["file_num"]}</td>
<td class="textCenter">{:countSize($originList[$key]["file_size"])}</td>
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$policy.id}" data-unable="{eq name="$originList[$key]['file_num']" value="0"}0{else}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$policy.id}"><i class="fa fa-edit" aria-hidden="true"></i></button>
</td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
</div>
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
{$list->render()}
</div></div></div></div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12"><strong>ID:</strong></div>
<div class="col-md-12 break" id="fileId">12</div>
</div>
<div class="row">
<div class="col-md-12"><strong>文件名:</strong></div>
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>源文件名:</strong></div>
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传者UID:</strong></div>
<div class="col-md-12 break" id="fileUID">17</div>
</div>
<div class="row">
<div class="col-md-12"><strong>大小(字节):</strong></div>
<div class="col-md-12 break" id="fileSize">7481817</div>
</div>
<div class="row">
<div class="col-md-12"><strong>图像尺寸:</strong></div>
<div class="col-md-12 break" id="filePic">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>上传策略:</strong></div>
<div class="col-md-12 break" id="filePolicy">147,445</div>
</div>
<div class="row">
<div class="col-md-12"><strong>所属目录:</strong></div>
<div class="col-md-12 break" id="fileDir">147,445</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/policy.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,134 @@
{extend name="header_admin" /}
{block name="title"}注册访问- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">设置</li>
<li class="breadcrumb-item active">注册访问</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>注册与访问</h2>
<br>
<form id="basicOptionsForm">
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">允许注册</label>
</div>
<div class="col-md-4">
{eq name="$optionsForSet.regStatus" value="0"}
<input class="" type="radio" name="regStatus" id="inlineRadio1" value="0"checked>
<label class="" for="inlineRadio1" ></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="regStatus" id="inlineRadio2" value="1">
<label class="" for="inlineRadio2"></label>
{else}
<input class="" type="radio" name="regStatus" id="inlineRadio1" value="0">
<label class="" for="inlineRadio1" ></label>
&nbsp;&nbsp;&nbsp;
<input class="" type="radio" name="regStatus" id="inlineRadio2" value="1" checked>
<label class="" for="inlineRadio2"></label>
{/eq}
</div>
<div class="col-md-4 option-des"> 是否允许新用户注册</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">默认用户组</label>
</div>
<div class="col-md-4">
<select class="form-control" name="defaultGroup">
{volist name="groups" id="group"}
{eq name="$group.id" value="$optionsForSet.defaultGroup"}
<option value="{$group.id}" selected>{$group.group_name}</option>
{else}
<option value="{$group.id}">{$group.group_name}</option>
{/eq}
{/volist}
</select>
</div>
<div class="col-md-4 option-des"> 用户注册后默认属于的用户组</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">邮件激活</label>
</div>
<div class="col-md-4">
<input type="checkbox" id="inlineCheckbox3" name="email_active" value="1" {eq name="$optionsForSet.email_active" value="1" }checked{/eq}>
<label for="inlineCheckbox3">启用</label>
</div>
<div class="col-md-4 option-des"> 启用后,新用户注册需要点击邮件中的激活链接才能完成。请确认邮件发送设置是否正确,否则激活邮件无法送达</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">登录验证码</label>
</div>
<div class="col-md-4"> <input type="checkbox" id="login_captcha" name="login_captcha" value="1" {eq name="$optionsForSet.login_captcha" value="1" }checked{/eq}>
<label for="login_captcha">启用</label>
</div>
<div class="col-md-4 option-des"> 是否启用登录表单验证码</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">注册验证码</label>
</div>
<div class="col-md-4"> <input type="checkbox" id="reg_captcha" name="reg_captcha" value="1" {eq name="$optionsForSet.reg_captcha" value="1" }checked{/eq}>
<label for="reg_captcha">启用</label>
</div>
<div class="col-md-4 option-des"> 是否启用注册表单验证码</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">找回密码验证码</label>
</div>
<div class="col-md-4"> <input type="checkbox" id="forget_captcha" name="forget_captcha" value="1" {eq name="$optionsForSet.forget_captcha" value="1" }checked{/eq}>
<label for="forget_captcha">启用</label>
</div>
<div class="col-md-4 option-des"> 是否启用找回密码表单验证码</div>
</div>
<div class="row form-setting">
<div class="col-md-1 form-label ">
</div>
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveReg">保存设置</button></div>
<div class="col-md-4 option-des"> </div>
<br><br><br>
</div>
</form>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/setting.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,110 @@
{extend name="header_admin" /}
{block name="title"}文件列表- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">分享</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>分享</h2>
<br>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-tags"></i> 条件检索</div>
<div class="card-body">
<div class="row">
<div class="col-1 form-label-search mb-2">排序方式</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="order">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">日期</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="download_num DESC">下载次数</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="view_num DESC">浏览次数</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table"></i> 分享列表</div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select></label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
<div class="table-responsive">
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>分享名称</th><th class="textCenter">分享者</th><th class="textCenter">类型</th><th class="textCenter">日期</th><th class="textCenter">浏览次数</th><th class="textCenter">下载次数</th><th class="textCenter">操作</th></tr>
</thead>
<tfoot>
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1" class="textCenter">分享名称</th><th rowspan="1" colspan="1" class="textCenter">分享者</th><th rowspan="1" colspan="1" class="textCenter">类型</th><th rowspan="1" colspan="1" class="textCenter">日期</th><th rowspan="1" colspan="1" class="textCenter">浏览次数</th><th rowspan="1" colspan="1" class="textCenter">下载次数</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
</tfoot>
<tbody>
<tr role="row" class="odd" id="fileList">
{volist name='list' id='share'}
<tr role="row" class="odd">
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-id="{$share.id}"></td>
<td>
{eq name="$share.source_type" value="dir"}
<i class="fa fa-folder-open-o" aria-hidden="true"></i> <a href="/S/{$share.share_key}?pwd={$share.share_pwd}" class="noAColor" target="_blank">{:htmlspecialchars(getDirName($share.source_name),ENT_NOQUOTES)}</a>
{else}
<i class="fa fa-file" aria-hidden="true"></i> <a href="/S/{$share.share_key}?pwd={$share.share_pwd}" class="noAColor" target="_blank">{$share.origin_name|htmlspecialchars=ENT_NOQUOTES}</a>
{/eq}
</td>
<td class="textCenter">{$originList[$key]["user"]["user_nick"]}</td>
<td class="textCenter">
{eq name="share.type" value="public"}
<i class="fa fa-eye" aria-hidden="true"></i> 公开
{else/}
<i class="fa fa-lock" aria-hidden="true"></i> 私密
{/eq}
</td>
<td class="textCenter">{$share.share_time}</td>
<td class="textCenter">{$share.view_num}</td>
<td class="textCenter">{$share.download_num}</td>
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$share.id}"><i class="fa fa-trash" aria-hidden="true"></i></button> <button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="变更分享类型" data-action="change" data-id="{$share.share_key}"><i class="fa fa-lock" aria-hidden="true"></i></button></td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
</div>
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
{$list->render()}
</div></div></div></div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/shares.js"></script>
<script type="text/javascript">
</script>
{/block}
+51
View File
@@ -0,0 +1,51 @@
{extend name="header_admin" /}
{block name="title"}基础设置- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">模板</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>编辑模板</h2>
application/index/view/{:rtrim($path,"/")}/{$name}.html
<br> <br>
<div class="row">
<div class="col-md-9">
<input type="text" id="fileName" value="{$name}" style="display: none">
<textarea rows="15" class="form-control" spellcheck="false" style=" font-family: 'Courier New';">{:htmlspecialchars($content)}</textarea>
<br>
<button class="btn btn-primary" id="saveTheme">保存</button>
<br><br>
</div>
<div class="col-md-3">
<div class="file_side">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
{volist name="list" id="file"}
<a class="nav-link" id="v-pills-home-tab" href="/Admin/Theme/name/{:str_replace(".html","",$file)}" role="tab" data-name="{:str_replace(".html","",$file)}">{$file}</a>
{/volist}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
{/block}
{block name="js"}
<script src="/static/js/admin/config.js"></script>
<script type="text/javascript">
</script>
{/block}
+298
View File
@@ -0,0 +1,298 @@
{extend name="header_admin" /}
{block name="title"}文件列表- {$options.siteName}{/block}
{block name="content"}
<div class="content-wrapper">
<div class="container-fluid">
<!-- Breadcrumbs-->
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Admin">管理面板</a>
</li>
<li class="breadcrumb-item active">用户</li>
</ol>
<!-- Area Chart Example-->
<div class="row">
<div class="col-12">
<h2>用户 <button class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#addUser"><li class="fa fa-plus"></li></button></h2>
<br>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-tags"></i> 条件检索</div>
<div class="card-body">
<div class="row">
<div class="col-1 form-label-search mb-2">排序方式</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="order">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="user_nick ASC">用户名</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">注册日期</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-method="used_storage DESC">已用空间</a>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-1 form-label-search mb-2">用户组</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="groupS">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-group="">全部</a>
</li>
{volist name="group" id="group"}
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-group="{$group.id}">{$group.group_name}</a>
</li>
{/volist}
</ul>
</div>
</div>
<div class="row">
<div class="col-1 form-label-search mb-2">用户状态</div>
<div class="col-md-10">
<ul class="nav nav-pills" id="status">
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-status="">全部</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-status="1">正常</a>
</li>
<li class="nav-item">
<a class="nav-link selectLab" href="javascript:void()" data-status="2">封禁/未激活</a>
</li>
</ul>
</div>
</div>
<div class="row" style="margin-top: 5px;">
<div class="col-1 form-label-search mb-2">高级检索</div>
<div class="col-md-10">
<div class="row">
<div class="col-md-2">
<select class="form-control form-control-sm" id="searchColUser">
<option value="id">用户UID</option>
<option value="user_nick">用户昵称</option>
<option value="user_date">注册日期</option>
<option value="user_email">邮箱</option>
<option value="group_primary">初始用户组</option>
<option value="user_activation_key">邮箱激活密钥</option>
<option value="used_storage">已用空间</option>
<option value="delay_time">用户组过期日期</option>
<option value="avatar">头像标识</option>
<option value="profile">个人主页状态</option>
</select>
</div>
<div class="col-md-2">
<input type="text" class="form-control form-control-sm" placeholder="检索表达式" id="searchValueUser">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-primary btn-sm" id="applySearch">应用</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table"></i> 用户列表 </div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select></label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
<div class="table-responsive">
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>UID</th><th>昵称</th><th class="textCenter">邮箱</th><th class="textCenter">用户组</th><th class="textCenter">空间用量</th><th class="textCenter">状态</th><th class="textCenter">操作</th></tr>
</thead>
<tfoot>
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1" class="textCenter">UID</th><th rowspan="1" colspan="1" class="textCenter">昵称</th><th rowspan="1" colspan="1" class="textCenter">邮箱</th><th rowspan="1" colspan="1" class="textCenter">用户组</th><th rowspan="1" colspan="1" class="textCenter">空间用量</th><th rowspan="1" colspan="1" class="textCenter">状态</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
</tfoot>
<tbody>
<tr role="row" class="odd" id="userList">
{volist name='list' id='user'}
<tr role="row" class="odd">
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-id="{$user.id}"></td>
<td class="textCenter">{$user.id}</td>
<td class="textCenter">{$user.user_nick}</td>
<td class="textCenter">{$user.user_email}</td>
<td class="textCenter">{:$originList[$key]["group"]["group_name"]}</td>
<td class="textCenter">{:countSize($user.used_storage)}</td>
<td class="textCenter">
{eq name="user.user_status" value="0"}
<span class="order_success">正常</span>
{else/}
<span class="order_warning">封禁/未激活</span>
{/eq}
</td>
<td class="textCenter">
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$user.id}" data-unable="{eq name="user.used_storage" value="0"}0{else/}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$user.id}"><i class="fa fa-id-card" aria-hidden="true"></i></button>
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="封号/解封" data-action="ban" data-id="{$user.id}"><i class="fa fa-ban" aria-hidden="true"></i></button>
</td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中用户</button>
</div>
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
{$list->render()}
</div></div></div></div>
</div>
</div>
</div>
</div>
</div>
<!-- Example DataTables Card-->
</div>
<!-- /.container-fluid-->
</div>
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="editUser">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">用户详情</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editUserForm">
<div class="form-group">
<label>
头像
</label>
<img src="" id="user_avatar">
</div>
<div class="form-group">
<label for="name">UID</label>
<input type="text" name="uid" id="uid" style="display: none;">
<input class="form-control" id="id" type="text" value="17" readonly>
</div>
<div class="form-group">
<label for="lovelyname">昵称</label>
<input type="text " class="form-control" id="user_nick" name="user_nick" required>
</div>
<div class="form-group">
<label for="InputPassword1">密码</label>
<input type="password" class="form-control" id="user_pass" name="user_pass" placeholder="如果不修改密码则留空" >
</div>
<div class="form-group">
<label for="InputEmail1">邮箱</label>
<input type="email" class="form-control" id="user_email" name="user_email" placeholder="Email" required>
</div>
<div class="form-group">
<label for="date">注册日期</label>
<input class="form-control" id="user_date" type="text" value="2017.12.31" readonly>
</div>
<div class="form-group">
<label for="space">已用空间</label>
<input class="form-control" id="used_storage" type="text" value="500M" readonly>
</div>
<div class="form-group">
<label for="openid">二步验证秘钥</label>
<input type="text " class="form-control" id="two_step" name="two_step" placeholder="取消二步验证请填写0" required="">
</div>
<div class="form-group">
<label for="inputState">用户状态</label>
<select class="form-control" id="user_status" name="user_status">
<option value="0">正常</option>
<option value="1">封禁/未激活</option>
</select>
</div>
<div class="form-group">
<label for="inputState">用户组</label>
<select id="user_group" class="form-control" name="user_group">
{foreach $groups as $g}
<option value="{$g.id}">{$g.group_name}</option>
{/foreach}
</select>
</div>
<div class="form-group">
<label for="inputState">个人主页状态</label>
<div class="radio">
<label>
<input type="radio" name="profile" id="profile1" value="1">
开启
</label>
<label>
<input type="radio" name="profile" id="profile0" value="0">
关闭
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary" id="editUserSubmit">保存</button>
</div></form>
</div>
</div>
</div>
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="addUser">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">添加用户</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="addUserForm">
<div class="form-group">
<label for="lovelyname">昵称</label>
<input type="text " class="form-control" id="user_nick" name="user_nick" required>
</div>
<div class="form-group">
<label for="InputPassword1">密码</label>
<input type="password" class="form-control" id="user_pass" name="user_pass" required>
</div>
<div class="form-group">
<label for="InputEmail1">邮箱</label>
<input type="email" class="form-control" id="user_email" name="user_email" placeholder="Email" required>
</div>
<div class="form-group">
<label for="inputState">用户状态</label>
<select class="form-control" name="user_status">
<option value="0">正常</option>
<option value="1">封禁/未激活</option>
</select>
</div>
<div class="form-group">
<label for="inputState">用户组</label>
<select class="form-control" name="user_group">
{foreach $groups as $g}
<option value="{$g.id}">{$g.group_name}</option>
{/foreach}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary" id="addUserSubmit">保存</button>
</div></form>
</div>
</div>
</div>
<!-- /.content-wrapper-->
{/block}
{block name="js"}
<script src="/static/js/admin/users.js"></script>
<script type="text/javascript">
</script>
{/block}
@@ -0,0 +1,23 @@
{extend name="header_public" /}
{block name="title"}支付成功 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/error.css" />
</head>
<body data-ma-header="teal">
<div class="container" align="center">
<header align="left">
<br>
<img src="/img/logo_s.png" style="width:192px;">
</header>
<div class="error_content" >
<div class="jumbotron animated bounce" style="padding-left:30px;">
<h1>支付成功</h1>
<br>
<p> 付款成功,您所购买的服务已开通。</p>
<p><a class="btn btn-primary btn-lg" href="/Home/Quota">查看详情</a></p>
</div>
</div>
</div>
</body>
{/block}
+24
View File
@@ -0,0 +1,24 @@
{extend name="header_public" /}
{block name="title"}错误提示 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/error.css" />
</head>
<body data-ma-header="teal">
<div class="container" align="center">
<header align="left">
<br>
<img src="/static/img/logo_s.png" style="width:192px;">
</header>
<div class="error_content" >
<div class="jumbotron animated bounce" style="padding-left:30px;">
<h1>发生错误</h1>
<br>
<p> {$msg}</p>
<p><a class="btn btn-primary btn-lg" onclick="history.go(-1);"><< 返回</a></p>
</div>
</div>
</div>
{$options.js_code}
</body>
{/block}
+24
View File
@@ -0,0 +1,24 @@
{extend name="header_public" /}
{block name="title"}错误提示 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/error.css" />
</head>
<body data-ma-header="teal">
<div class="container" align="center">
<header align="left">
<br>
<img src="/static/img/logo_s.png" style="width:192px;">
</header>
<div class="error_content" >
<div class="jumbotron animated bounce" style="padding-left:30px;">
<h1>发生错误</h1>
<br>
<p> {$msg}</p>
<p><a class="btn btn-primary btn-lg" onclick="history.go(-1);"><< 返回</a></p>
</div>
</div>
</div>
{$options.js_code}
</body>
{/block}
@@ -0,0 +1,76 @@
{extend name="header_public" /}
{block name="title"}“{$keyWords}”搜索结果 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/search.css" />
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main-h">
<div class="col-md-12">
<h1>搜索分享</h1>
<input type="text" placeholder="请输入关键词,回车键发起搜索" value="{$keyWords}" autofocus="true"><br><br>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th width="50%">文件名 </th>
<th class="cent">分享日期</th>
<th class="cent">下载次数</th>
<th class="cent">浏览次数</th>
</tr>
</thead>
<tbody>{volist name='list' id='shares'}
<tr>
<td >{switch $shares.source_type}
{case file}<i class="fa fa-file" aria-hidden="true"></i> {/case}
{case dir}<i class="fa fa-folder-open blue" aria-hidden="true"></i> {/case}
{/switch} <a href="/s/{$shares.share_key}" class="notWave" target="_blank">{$shares.fileData|htmlspecialchars=ENT_NOQUOTES}</a></td>
<td class="cent">{$shares.share_time}</td>
<td align="center">{$shares.download_num}</td>
<td align="center">{$shares.view_num}</td>
</tr>
{/volist}
</tbody>
</table>
</div>
{$listOrigin->render()}
</div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/material.js"></script>
<script >
$.material.init();
document.onkeydown=function(){
if (event.keyCode == 13){
keyWords = $("input").val();
if(keyWords ==""){
toastr["warning"]("关键字不能为空");
}else{
window.location="/Explore/S/"+keyWords;
}
}
else{
}
}
</script>
{$options.js_code}
{/block}
@@ -0,0 +1,47 @@
{extend name="header_public" /}
{block name="title"}用户主页 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/search.css" />
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main-h">
<div class="col-md-12">
<h1>搜索分享</h1>
<input type="text" placeholder="请输入关键词,回车键发起搜索" autofocus="true">
</div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/material.js"></script>
<script >
document.onkeydown=function(){
if (event.keyCode == 13){
keyWords = $("input").val();
if(keyWords ==""){
toastr["warning"]("关键字不能为空");
}else{
window.location="/Explore/S/"+keyWords;
}
}
else{
}
}
</script>
{$options.js_code}
{/block}
@@ -0,0 +1,5 @@
下载已开始...
<a href="{$url}" download="" id="downloadA">手动下载</a>
<script type="text/javascript">
document.getElementById("downloadA").click();
</script>
+37
View File
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html class="full-height">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="keywords" content="{$options.siteKeywords}"/>
<meta name="description" content="{$options.siteDes}"/>
<meta name="theme-color" content="#4e64d9"/>
<title>{$options.siteName} - {$options.siteTitle}</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<!-- Bootstrap core CSS -->
<link href="/static/css/bootstrap4/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="/static/css/mdb.css" rel="stylesheet">
</head>
<body class="grey-skin intro-page creative-lp">
<!--Navigation & Intro-->
<header>
<!--Navbar-->
<nav class="navbar fixed-top navbar-dark ">
<div class="container">
<a class="navbar-brand" href="#">
<img src="static/img/logo_s.png" style=" width: 192px;">
</a>
</div>
</nav>
<!--/Navbar-->
+194
View File
@@ -0,0 +1,194 @@
<!DOCTYPE html>
<html lang="zh_cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>{block name="title"}{/block}</title>
<!-- Bootstrap core CSS-->
<link href="/static/css/bootstrap4/bootstrap.min.css" rel="stylesheet">
<!-- Custom fonts for this template-->
<link href="/static/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<!-- Page level plugin CSS-->
<link href="/static/css/datatables/dataTables.bootstrap4.css" rel="stylesheet">
<link href="/static/css/toastr.min.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="/static/css/sb-admin.css" rel="stylesheet">
</head>
<body class="{$options.admin_color_body}" id="page-top">
<!-- Navigation-->
<nav class="{$options.admin_color_nav}" id="mainNav">
<a class="navbar-brand" href="index.html">Cloudreve</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav navbar-sidenav" id="exampleAccordion">
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="面板首页">
<a class="nav-link" href="/Admin">
<i class="fa fa-fw fa-dashboard"></i>
<span class="nav-link-text">面板首页</span>
</a>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="设置">
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#collapseComponents" data-parent="#exampleAccordion">
<i class="fa fa-fw fa-wrench"></i>
<span class="nav-link-text">设置</span>
</a>
<ul class="sidenav-second-level collapse" id="collapseComponents">
<li>
<a href="/Admin/Setting">基础设置</a>
</li>
<li>
<a href="/Admin/SettingReg">注册访问</a>
</li>
<li>
<a href="/Admin/SettingMail">邮件发送</a>
</li>
<li>
<a href="/Admin/Config">配置文件</a>
</li>
<li>
<a href="/Admin/SettingOther">杂项</a>
</li>
</ul>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="模板">
<a class="nav-link" href="/Admin/Theme">
<i class="fa fa-fw fa-paint-brush"></i>
<span class="nav-link-text">模板</span>
</a>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="文件">
<a class="nav-link" href="/Admin/Files">
<i class="fa fa-fw fa-folder"></i>
<span class="nav-link-text">文件</span>
</a>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="分享">
<a class="nav-link" href="/Admin/Shares">
<i class="fa fa-fw fa-send"></i>
<span class="nav-link-text">分享</span>
</a>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="用户">
<a class="nav-link" href="/Admin/Users" data-parent="#user">
<i class="fa fa-fw fa-user"></i>
<span class="nav-link-text">用户</span>
</a>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="用户组">
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#group" data-parent="#group">
<i class="fa fa-fw fa-users"></i>
<span class="nav-link-text">用户组</span>
</a>
<ul class="sidenav-second-level collapse" id="group">
<li>
<a href="/Admin/GroupList">管理</a>
</li>
<li>
<a href="/Admin/GroupAdd">添加</a>
</li>
</ul>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="上传策略">
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#policy" data-parent="#policy">
<i class="fa fa-fw fa-upload"></i>
<span class="nav-link-text">上传策略</span>
</a>
<ul class="sidenav-second-level collapse" id="policy">
<li>
<a href="/Admin/PolicyList">管理</a>
</li>
<li>
<a href="/Admin/PolicyAdd">添加</a>
</li>
</ul>
</li>
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="其他">
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#else" data-parent="#else">
<i class="fa fa-fw fa-ellipsis-h"></i>
<span class="nav-link-text">其他</span>
</a>
<ul class="sidenav-second-level collapse" id="else">
<li>
<a href="/Admin/Cron">定时任务</a>
</li>
<li>
<a href="/Admin/About">关于</a>
</li>
</ul>
</li>
</ul>
<ul class="navbar-nav sidenav-toggler">
<li class="nav-item">
<a class="nav-link text-center" id="sidenavToggler">
<i class="fa fa-fw fa-angle-left"></i>
</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="javascript:void" id="toggleNavColor">
<i class="fa fa-fw fa-toggle-on" aria-hidden="true"></i>切换配色</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/">
<i class="fa fa-fw fa-home"></i>返回首页</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="modal" data-target="#exampleModal">
<i class="fa fa-fw fa-sign-out"></i>登出</a>
</li>
</ul>
</div>
</nav>
{block name="content"}{/block}
<footer class="sticky-footer">
<div class="container">
<div class="text-center">
<small>Copyright © Cloudreve {php}echo date("Y");{/php} </small>
</div>
</div>
</footer>
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fa fa-angle-up"></i>
</a>
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">确认</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">点击“登出”按钮退出当前账户。</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">取消</button>
<a class="btn btn-primary" href="/Member/LogOut">登出</a>
</div>
</div>
</div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/bootstrap4/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="/static/js/chart.js/Chart.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="/static/js/sb-admin.min.js"></script>
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
{block name="js"}
{/block}
</div>
</body>
</html>
@@ -0,0 +1,15 @@
<html lang="zh-cn" data-ng-app="FileManagerApp">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>{block name="title"}{/block}</title>
<!-- third party -->
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/material.css" />
<link rel="stylesheet" href="/static/css/animate.css" />
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<!-- /third party -->
<!-- Comment if you need to use raw source code -->
<link href="/static/css/toastr.min.css" rel="stylesheet">
<!-- /Comment if you need to use raw source code -->
{block name="content"}{/block}
+18
View File
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="zh-cn" data-ng-app="FileManagerApp">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<meta name="theme-color" content="#4e64d9"/>
<title>{block name="title"}{/block}</title>
<script src="/static/js/jquery.min.js"></script>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/material.css" />
<script src="/static/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<link href="/static/css/angular-filemanager.min.css" rel="stylesheet">
<link href="/static/css/toastr.min.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
<script type="text/javascript">
</script>
{block name="content"}{/block}
+20
View File
@@ -0,0 +1,20 @@
<html lang="zh-cn" data-ng-app="FileManagerApp">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<meta name="theme-color" content="#4e64d9"/>
<title>{block name="title"}{/block}</title>
<!-- third party -->
<script src="/static/js/jquery.min.js"></script>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/material.css" />
<link rel="stylesheet" href="/static/css/animate.css" />
<script src="/static/js/material.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<!-- /third party -->
<!-- Comment if you need to use raw source code -->
<link href="/static/css/toastr.min.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
<!-- /Comment if you need to use raw source code -->
{block name="content"}{/block}
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<!--
Multiverse by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>图片集 - {$options.siteName}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<!--[if lte IE 8]><script src="https://file.aoaoao.me/content/themes/material/pages/js/ie/html5shiv.js"></script><![endif]-->
<link rel="stylesheet" href="/static/css/main.css" />
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
<!--[if lte IE 9]><link rel="stylesheet" href="https://file.aoaoao.me/content/themes/material/pages/css/ie9.css" /><![endif]-->
<!--[if lte IE 8]><link rel="stylesheet" href="https://file.aoaoao.me/content/themes/material/pages/css/ie8.css" /><![endif]-->
<style type="text/css">
body{
font-family: "微软雅黑","黑体";
}
</style>
</head>
<body>
<!-- Wrapper -->
<div id="wrapper">
<!-- Header -->
<div id="main">
{volist name='list' id='pic'}
<article class="thumb">
<a href="/File/Preview?action=preview&path={$pic.dir|urlencode}/{$pic.orign_name|urlencode}" class="image"><img src="/File/Preview?action=preview&path={$pic.dir|urlencode}/{$pic.orign_name|urlencode}" alt="" /></a>
<h2>{$pic.orign_name}</h2>
</article>
{/volist}
</div>
<header id="header">
<h1><a href="/Home"><strong>图片集</strong> {$options.siteName}</a></h1>
<nav>
<ul>
<li><a href="javascript:previous();" class="icon fa-arrow-circle-left">上一页</a></li>
{$page}/{$pageCount} <li><a href="javascript:next();" class="icon fa-arrow-circle-right">下一页</a></li>
</ul>
</nav>
</header>
<!-- Main -->
<!-- Footer -->
</div>
<!-- Scripts -->
<script src = "/static/js/jquery.min.js"></script>
<script src="/static/js/jquery.poptrox.min.js"></script>
<script src="/static/js/skel.min.js"></script>
<script src="/static/js/util.js"></script>
<!--[if lte IE 8]><script src="assets/js/ie/respond.min.js"></script><![endif]-->
<script src="/static/js/album.js"></script>
<script type="text/javascript">
pageNow = {$page};
pageTotal = {$pageCount};
function next(){
if(pageNow == pageTotal){
}else{
window.location.href="/Home/Album?page="+(pageNow+1);
}
}
function previous(){
if(pageNow == 1){
}else{
window.location.href="/Home/Album?page="+(pageNow-1);
}
}
</script>
{$options.js_code}
</body>
</html>
+98
View File
@@ -0,0 +1,98 @@
<!doctype html>
<html lang="zh_cn" data-ng-app="FileManagerApp">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<meta name="theme-color" content="#4e64d9"/>
<title>我的文件 - {$options.siteName}</title>
<script src="/static/js/angular.min.js"></script>
<script src="/static/js/angular-translate.min.js"></script>
<script src="/static/js/jquery.min.js"></script>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/material.css" />
<script src="/static/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<link href="/static/css/angular-filemanager.min.css" rel="stylesheet">
<link href="/static/css/toastr.min.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
<script src="/static/js/angular-filemanager.min.js"></script>
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script type="text/javascript">
uploadConfig={
saveType : "{$policyData.policy_type}",
maxSize : "{$policyData.max_size}mb",
allowedType: [
{$extLimit}
],
allowSource : "{$policyData.origin_link}",
upUrl : "{$policyData.server}",
allowShare:"{$groupData.allow_share}",
};
</script>
<script src="/static/js/home.js"></script>
</head>
<body class="ng-cloak">
<div id="container">
{include file="navbar_home" /}
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element, as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides. PhotoSwipe keeps only 3 slides in DOM to save memory. -->
<div class="pswp__container">
<!-- don't modify these 3 pswp__item elements, data is added later on -->
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
<div class="col-md-10 max_height">
<angular-filemanager></angular-filemanager>
</div>
</div>
</body>
<script src="/static/js/material.js"></script>
<script type="text/javascript">
upload_load=0;
</script>
{$options.js_code}
</html>
+49
View File
@@ -0,0 +1,49 @@
{include file="header" /}
<!--Video-->
<div class="intro-video view" id="home">
<div class="hm-gradient">
<div class="full-bg-img flex-center">
<div class="container smooth-scroll">
<div class="row">
<div class="col-md-12 white-text text-center smooth-scroll">
<div class="fadeInDown" data-wow-delay="0.2s">
<h3 class="brand-name font-bold white-text mb-2">开始云上之旅</h3>
<hr class="hr-light">
<h4 class="subtext-header mt-2 mb-2">只需十秒钟,注册后即可开始使用免费高速的云存储服务</h4>
</div>
<a href="/Login" class="btn btn-rounded btn-light-green-2" ><i class="fa fa-paper-plane-o"></i> 注册</a>
<a href="/Home" class="btn btn-rounded btn-light-green-2" ><i class="fa fa-sign-in"></i> 登录</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/Video-->
</header>
<!--/.Content-->
</div>
</div>
<!-- JQuery -->
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script>
</script>
</body>
</html>
@@ -0,0 +1,59 @@
{extend name="header_public" /}
{block name="title"}注册成功- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/login.css" />
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script src="/static/js/jquery.color.js"></script>
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" loginStatus=$loginStatus userData=$userData /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main" >
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="jumbotron" >
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-check" aria-hidden="true"></i></div>
<div class="login-text">注册成功</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<br>
您已成功激活账号。<br><br>
<a class="btn btn-raised btn-primary" href="/Login">立即登录</a>
</div>
</div>
</div>
</div>
</div></div>
<div class="col-md-4"></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/two_step.js"> </script>
{$options.js_code}
{/block}
+185
View File
@@ -0,0 +1,185 @@
{extend name="header_public" /}
{block name="title"}登录- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/login.css" />
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script src="/static/js/jquery.color.js"></script>
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" loginStatus=$loginStatus userData=$userData /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main" >
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="jumbotron" id="logForm">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-user-circle-o" aria-hidden="true"></i></div>
<div class="login-text">登录后方可享用精彩内容</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="loginForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">Email 电子邮箱</label>
<input type="text" class="form-control" id="inputEmail" name="userMail">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">密码</label>
<input type="password" class="form-control" id="inputPwd" name="userPass">
</div>
{eq name="$RegOptions.login_captcha" value="1"}
<div class="input-group form-group label-floating">
<label class="control-label" for="captcha">验证码</label>
<input type="text" id="captcha" class="form-control" name="captchaCode">
<span class="input-group-btn">
<div class="captcha_img">{:captcha_img()}</div>
</span>
</div>
{else/}
{/eq}
</form> <button class="btn btn-raised btn-primary" id="loginButton">登录</button>
<div class="link-group">
<a href="javascript:void" class="noWave" id="create" data-change="true">创建一个账户</a><br>
<a href="javascript:void" class="noWave" id="forgetSwitch2" data-change="true">忘记密码?</a>
</div>
</div>
</div>
</div>
<div class="jumbotron" id="regForm" style="display: none;">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-sign-in" aria-hidden="true"></i></div>
<div class="login-text">注册账户</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="registerForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">Email 电子邮箱</label>
<input type="text" class="form-control" id="inputEmail" name="username-reg">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">密码</label>
<input type="password" class="form-control" id="inputPwd" name="password-reg">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">重复密码</label>
<input type="password" class="form-control" id="inputPwd" name="password-check">
</div>
{eq name="$RegOptions.reg_captcha" value="1"}
<div class="input-group form-group label-floating">
<label class="control-label" for="captcha">验证码</label>
<input type="text" id="captcha" class="form-control" name="captchaCode">
<span class="input-group-btn">
<div class="captcha_img">{:captcha_img()}</div>
</span>
</div>
{else/}
{/eq}
</form> <button class="btn btn-raised btn-primary" id="regButton">注册</button> <div class="link-group">
<a href="javascript:void" class="noWave" id="loginSwitch3" data-change="true">已有账号?立即登录</a><br>
<a href="javascript:void" class="noWave" id="forgetSwitch" data-change="true">忘记密码?</a>
</div>
</div>
</div>
</div>
<div class="jumbotron" id="emailCheck" style="display: none;">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-envelope" aria-hidden="true"></i></div>
<div class="login-text">激活账户</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width"><br>
我们已经向您的注册邮箱发送了一封确认邮件,请访问邮件中的激活链接以完成注册。如果未收到邮件,请检查您的垃圾邮件。<br><br>如果还仍无法接受邮件,请尝试更换注册邮箱或联系站点管理员。
</div>
</div>
</div>
<div class="jumbotron" id="forgetForm" style="display: none;">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-question-circle-o" aria-hidden="true"></i></div>
<div class="login-text">找回密码</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="forgetPwdForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">请填写注册时绑定的邮箱</label>
<input type="text" class="form-control" id="regEmail" name="regEmail">
</div>
{eq name="$RegOptions.forget_captcha" value="1"}
<div class="input-group form-group label-floating">
<label class="control-label" for="captcha">验证码</label>
<input type="text" id="captcha" class="form-control" name="captchaCode">
<span class="input-group-btn">
<div class="captcha_img">{:captcha_img()}</div>
</span>
</div>
{else/}
{/eq}
</form> <button class="btn btn-raised btn-primary" id="findMyFuckingPwd">找回密码</button> <div class="link-group">
<a href="javascript:void" class="noWave" id="loginSwitch2" data-change="true">返回登录</a><br>
</div>
</div>
</div>
</div>
</div></div>
<div class="col-md-4"></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/login.js"> </script>
{$options.js_code}
{/block}
@@ -0,0 +1,122 @@
{extend name="header_public" /}
{block name="title"}登录- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/login.css" />
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script src="/static/js/jquery.color.js"></script>
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" loginStatus=$loginStatus userData=$userData /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main" >
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="jumbotron" id="logForm">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-user-circle-o" aria-hidden="true"></i></div>
<div class="login-text">登录后方可享用精彩内容</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="loginForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">Email 电子邮箱</label>
<input type="text" class="form-control" id="inputEmail" name="userMail">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">密码</label>
<input type="password" class="form-control" id="inputPwd" name="userPass">
</div>
{eq name="$RegOptions.login_captcha" value="1"}
<div class="input-group form-group label-floating">
<label class="control-label" for="captcha">验证码</label>
<input type="text" id="captcha" class="form-control" name="captchaCode">
<span class="input-group-btn">
<div class="captcha_img">{:captcha_img()}</div>
</span>
</div>
{else/}
{/eq}
</form> <button class="btn btn-raised btn-primary" id="loginButton">登录</button> <button class="btn btn-raised btn-info" ><i class="fa fa-qq" aria-hidden="true"></i> 使用QQ账号登录</button><div class="link-group">
<a href="#" class="noWave">创建一个账户</a><br>
<a href="#" class="noWave">忘记密码?</a>
</div>
</div>
</div>
</div>
<div class="jumbotron" id="regForm">
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-user-circle-o" aria-hidden="true"></i></div>
<div class="login-text">登录后方可享用精彩内容</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="loginForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">Email 电子邮箱</label>
<input type="text" class="form-control" id="inputEmail" name="userMail">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">密码</label>
<input type="password" class="form-control" id="inputPwd" name="userPass">
</div>
{eq name="$RegOptions.login_captcha" value="1"}
<div class="input-group form-group label-floating">
<label class="control-label" for="captcha">验证码</label>
<input type="text" id="captcha" class="form-control" name="captchaCode">
<span class="input-group-btn">
<div class="captcha_img">{:captcha_img()}</div>
</span>
</div>
{else/}
{/eq}
</form> <button class="btn btn-raised btn-primary" id="loginButton">登录</button> <button class="btn btn-raised btn-info" ><i class="fa fa-qq" aria-hidden="true"></i> 使用QQ账号登录</button><div class="link-group">
<a href="#" class="noWave">创建一个账户</a><br>
<a href="#" class="noWave">忘记密码?</a>
</div>
</div>
</div>
</div>
</div></div>
<div class="col-md-4"></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/login_bind.js"> </script>
{$options.js_code}
{/block}
@@ -0,0 +1,70 @@
{extend name="header_public" /}
{block name="title"}密码重置- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/login.css" />
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script src="/static/js/jquery.color.js"></script>
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" loginStatus=$loginStatus userData=$userData /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main" >
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="jumbotron" >
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-id-card-o" aria-hidden="true"></i></div>
<div class="login-text">密码重置</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="resetForm">
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">请输入新密码</label>
<input type="password" class="form-control" id="inputPwd" name="password-reg">
</div>
<div class="form-group label-floating">
<label class="control-label" for="inputPwd">重复密码</label>
<input type="password" class="form-control" id="inputPwd" name="password-check">
</div>
<input type="text" style="display:none" class="form-control" id="resetKey" name="key" value="{$key}">
</form> <button class="btn btn-raised btn-primary" id="regButton">重设密码</button>
</div>
</div>
</div>
</div>
</div></div>
<div class="col-md-4"></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/reset.js"> </script>
{$options.js_code}
{/block}
+265
View File
@@ -0,0 +1,265 @@
{extend name="header_home" /}
{block name="title"}用户设置- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/setting.css" />
<style type="text/css">
.col-md-3{
padding-right: 15px;
padding-left: 15px;
}
</style>
</head>
<body >
<div id="container">
{include file="navbar_home" /}
<div class="col-md-10 quota_content">
<h1>用户设置</h1>
<br>
<div class="fix_side">
<div class="fix">
<div class="col-md-9">
<ul class="nav nav-tabs" >
<li class="active"><a href="#home" data-toggle="tab" aria-expanded="true">基本信息<div class="ripple-container"></div></a></li>
<li class=""><a href="#security" data-toggle="tab" aria-expanded="false">安全隐私<div class="ripple-container"></div></a></li>
<li class=""><a href="#password" data-toggle="tab" aria-expanded="false">修改密码<div class="ripple-container"></div></a></li>
<li class=""><a href="#webdav" data-toggle="tab" aria-expanded="false">WebDAV<div class="ripple-container"></div></a></li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="home">
<div class="panel panel-default">
<div class="panel-body" id="packs">
<div class="col-md-8">
<div class="row fix">
<div class="col-md-3 option_name"><label for="uid">UID</label></div>
<div class="col-md-9">
<div class="non_input">{$userInfo.uid}</div>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="nick">昵称:</label></div>
<div class="col-md-6">
<input type="text" class="form-control" id="nick" value="{$userInfo.userNick}" >
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="email">Email</label></div>
<div class="col-md-9">
<input type="email" class="form-control" id="email" value="{$userInfo.userMail}" disabled>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">用户组:</label></div>
<div class="col-md-9">
<div class="non_input group">{$groupData.group_name} </div>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">注册日期:</label></div>
<div class="col-md-9">
<div class="non_input ">{$userInfo.regDate}</div>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail"></label></div>
<div class="col-md-9">
<div class="non_input "><button class="btn btn-raised btn-primary" id="saveNick">保存更改</button></div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="avatar">
<img src="/Member/Avatar/{$userInfo.uid}/l?cache=no" class="img-circle avatar-img"><br>
<button class="btn btn-primary" data-toggle="modal" data-target="#avatar_modal"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> 修改头像</button>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="security">
<div class="panel panel-default">
<div class="panel-body" >
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">个人主页:</label></div>
<div class="col-md-9">
<div ><div class="togglebutton">
<label>
<input type="checkbox" id="homePage" {eq name="$userSQL.profile" value="1"}checked{else}{/eq}>
</label>
</div></div>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name" style="margin-top: 10px;"><label for="inputEmail">二步验证:</label></div>
<div class="col-md-9">
{eq name="$userSQL.two_step" value="0"}
<button class="btn btn-primary btn-raised" id="twoStep"><i class="fa fa-lock" aria-hidden="true"></i> 开启二步验证</button>
{else}
<button class="btn btn-primary btn-raised"><i class="fa fa-check" aria-hidden="true"></i> 已开启</button>
{/eq}
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="password">
<div class="panel panel-default">
<div class="panel-body" >
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">原密码:</label></div>
<div class="col-md-6">
<input type="password" class="form-control" id="passOrigin" >
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">新密码:</label></div>
<div class="col-md-6">
<input type="password" class="form-control" id="passNew" >
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">确认新密码:</label></div>
<div class="col-md-6">
<input type="password" class="form-control" id="passNewRepet" >
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail"></label></div>
<div class="col-md-9">
<div class="non_input "><button class="btn btn-raised btn-primary waves-effect" id="savePwd">保存更改</button></div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="webdav">
<div class="panel panel-default">
<div class="panel-body" >
{eq name="groupData.webdav" value="0"}
<div class="alert alert-warning" role="alert">
您当前的用户组不支持WebDAV
</div>
{else/}
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">连接地址:</label></div>
<div class="col-md-6">
<input type="text" class="form-control" id="webdavUrl" value="{$options.siteURL}WebDav/Api/uid/{$userInfo.uid}" spellcheck="false" readonly>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name"><label for="inputEmail">用户名:</label></div>
<div class="col-md-6">
<input type="text" class="form-control" id="webdavUsername" value="{$userInfo.userMail}" spellcheck="false" readonly>
</div>
</div>
<div class="row fix">
<div class="col-md-3 option_name" style="margin-top: 10px;"><label for="inputEmail">登录密码:</label></div>
<div class="col-md-9">
<button class="btn btn-primary btn-raised" id="setWebdavPwd"><i class="fa fa-lock" aria-hidden="true"></i> 设置/更改密码</button>
</div>
</div>
{/eq}<br>
<p>你可以使用任何支持WebDAV协议的文件管理工具或操作系统将网盘映射到本地,方便多端同步管理。初次使用请先设置WebDAV登录密码,此密码默认与登录密码不相同。</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3"><div class="panel panel-default">
<div class="panel-heading">公告</div>
<div class="panel-body">
公告内容
</div>
</div></div>
</div>
</div>
<br>
<div class="fix_side">
<div class="fix">
</div>
</div>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="avatar_modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">修改头像</h4>
</div>
<div class="modal-body">
<div class="row fix">
<div class="col-md-4"><div class="avatar"><img src="/Member/Avatar/{$userInfo.uid}/l?cache=no" class="img-circle avatar-img"><br></div></div>
<div class="col-md-8">
<span class="btn btn-raised btn-info fileinput-button" id="uploadAvatar">
<span id="upload-text">上传头像</span>
<input type="file" accept="image/*" id="avatar_file" name="avatar">
</span>
<br><button class="btn btn-raised btn-info" id="useGravatar">使用Gravatar头像</button>
<br>修改头像后请清理浏览器缓存
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary " data-dismiss="modal">取消</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" tabindex="-1" role="dialog" id="two_step_modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">开启二步验证</h4>
</div>
<div class="modal-body">
<div class="row fix">
<div class="col-md-4"><img id="qrcode"></div>
<div class="col-md-8">
<div class="alert alert-success" role="alert">请使用任意二步验证APP或者支持二步验证的密码管理软件扫描左侧二维码添加本站。扫描完成后请填写二步验证APP给出的6位验证码以开启二步验证。</div>
<input type="number" class="form-control" placeholder="请输入6位验证码" id="vCode">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-info " id="confirm">确认开启</button>
<button class="btn btn-primary " data-dismiss="modal">取消</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" tabindex="-1" role="dialog" id="set_webdav_pwd">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">设置WebDAV认证密码</h4>
</div>
<div class="modal-body">
<div class="row fix">
<label>请输入密码:</label>
<input type="password" id="webdav_pwd" class="form-control" autocomplete="false">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-info " id="confirmWebdav">保存</button>
<button class="btn btn-primary " data-dismiss="modal">取消</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</body>
<script src="/static/js/material.js"></script>
<script src="/static/js/uploader.min.js"></script>
<script type="text/javascript">
upload_load=0;
</script>
<script src="/static/js/setting.js"></script>
{$options.js_code}
</html>
{/block}
@@ -0,0 +1,66 @@
{extend name="header_public" /}
{block name="title"}两步验证- {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/login.css" />
<link rel="stylesheet" href="/static/css/photoswipe.css">
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
<script src="/static/js/jquery.color.js"></script>
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" loginStatus=$loginStatus userData=$userData /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main" >
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="jumbotron" >
<div class="card_top">
<div class="row top-color">
<div class="card-top-row">
<div class="login-icon"><i class="fa fa-lock" aria-hidden="true"></i></div>
<div class="login-text">由于您开启了两步验证,请输入您的两步验证APP上显示的验证码</div>
</div>
</div>
</div>
<div class="card_botom">
<div class="row bottom-width">
<form id="loginForm">
<div class="form-group label-floating">
<label class="control-label" for="inputEmail">验证码</label>
<input type="text" class="form-control" id="inputEmail" name="code">
</div>
</form> <button class="btn btn-raised btn-primary" id="loginButton">继续登录</button>
<br>如果您丢失了两步验证秘钥,请联系站点管理员核验身份后取消二步验证。
</div>
</div>
</div>
</div>
</div></div>
<div class="col-md-4"></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/two_step.js"> </script>
{$options.js_code}
{/block}
+140
View File
@@ -0,0 +1,140 @@
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<a class="navbar-brand" href="/">
</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle avatar-a" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userInfo.uid}/s" class="img-circle avatar-s"> {$userInfo.userNick} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/Profile/{$userInfo.uid}">个人主页</a></li>
<li><a href="/Member/Setting">设置</a></li>
<li role="separator" class="divider"></li>
<li><a href="/Member/LogOut">退出登录</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!-- Modal -->
<div class="modal fade" id="upload_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" onclick = "closeUpload()" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title" id="myModalLabel">上传文件</h4>
</div>
<div class="modal-body">
<div class="row" style="margin-top: 20px;">
<input type="hidden" id="domain" value="http://7xocov.com1.z0.glb.clouddn.com/">
<input type="hidden" id="uptoken_url" value="uptoken">
<div class="up_button col-md-4">
<div id="container">
<button class="btn btn-raised btn-info btn-lg upload_button" id="pickfiles" >
<i class="glyphicon glyphicon-plus"></i>
<span id="up_text"></span>
</button>
</div>
</div>
<div style="display:none" id="success" class="indo col-md-8">
<div class="alert alert-success">
队列全部文件处理完毕
</div>
</div>
<div class="col-md-12 " align="center">
<div class="info_box" id="info_box">
<br>
<div class="drag_info">
<span class="info_icon"><i class="glyphicon glyphicon-inbox"></i></span>
<div class="info_text">拖动文件至此开始上传</div>
</div>
</div>
<div class="upload_box" style="display:none;" id="upload_box">
<table class="table table-striped table-hover text-left" style="display:none;">
<thead>
<tr>
<th class="col-md-4">文件名</th>
<th class="col-md-2">大小</th>
<th class="col-md-6">进度</th>
</tr>
</thead>
<tbody id="fsUploadProgress">
</tbody>
</table>
</div>
</div>
<div class="container" style="display: none;">
<div class="body">
</div>
</div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</div>
<div class="col-md-2 s" id="side">
<div class="list-group" id="b">
<a href="/Home" class="list-group-item">
<i class="fa fa-file" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 我的文件
</a>
<a href="/Share/My" class="list-group-item"> <i class="fa fa-share-alt" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 我的分享
</a>
<a href="/Explore/Search" class="list-group-item">
<i class="fa fa-search" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 搜索分享
</a>
<a href="/Home/Album" class="list-group-item">
<i class="fa fa-picture-o" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 图片集
</a>
</div>
<div clss="usage" style=" visibility: visible;
position: absolute;
width: 100%;
height: 100px;
top: auto;
bottom: 0px;
background-color: #f9f9f9;padding: 15px">
<div class="usage-title">容量使用:</div>
<div class="usage-bar">
<div class="progress progress-striped active">
<div class="progress-bar" id="memory_bar"></div>
</div>
</div>
<div class="usage-text"><span id="used">--</span>/<span id="total">--</span></div>
</div>
</div>
+42
View File
@@ -0,0 +1,42 @@
<div class="navbar-header">
<div >
<a class="navbar-brand" href="/">
</a>
</div>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
{eq name="$loginStatus" value="1"}
<li class="dropdown">
<a href="#" class="dropdown-toggle avatar-a" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userData.id}/s" class="img-circle avatar-s"> {$userData.user_nick} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/Home">我的文件</a></li>
<li><a href="/Profile/{$userData.id}">个人主页</a></li>
<li><a href="/Member/Setting">设置</a></li>
<li role="separator" class="divider"></li>
<li><a href="/Member/LogOut">退出登录</a></li>
</ul>
</li>
{else/}
<li >
<a href="/Login" class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-user mr-1"></i> 登录/注册 </a>
</li>
{/eq}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</div>
</nav>
+115
View File
@@ -0,0 +1,115 @@
{extend name="header_public" /}
{block name="title"}用户主页 - {$options.siteName}{/block}
{block name="content"}
<link rel="stylesheet" href="/static/css/profile.css" />
</head>
<body data-ma-header="teal">
<nav class="navbar navbar-inverse" >
<div class="container-fluid">
<div class="container" >
{include file="navbar_public" /}
<div class="header-panel shadow-z-2">
<div class="container-fluid">
<div class="row">
</div>
</div>
</div>
<div class="container main-h">
<div class="col-md-3">
<div class="card type--profile">
<header class="card-heading card-background" id="card_img_02">
<img src="/Member/Avatar/{$userInfo.id}/l" alt="" class="img-circle">
<ul class="card-actions icons right-top">
<li class="dropdown" style="display: none;">
<a href="javascript:void(0)" data-toggle="dropdown" aria-expanded="false">
<i class="zmdi zmdi-more-vert text-white"></i>
</a>
<ul class="dropdown-menu dropdown-menu-right">
<li>
<a href="javascript:void(0)">Option One</a>
</li>
<li>
<a href="javascript:void(0)">Option Two</a>
</li>
<li>
<a href="javascript:void(0)">Option Three</a>
</li>
</ul>
</li>
</ul>
</header>
<div class="card-body">
<h3 class="name">{$userInfo.user_nick|htmlspecialchars=ENT_NOQUOTES}</h3>
<span class="title span-fix"><span class="label span-fix label-{$groupData.color}">{$groupData.group_name}</span></span>
</div>
<footer class="card-footer border-top">
<div class="row row p-t-10 p-b-10">
<div class="col-xs-4"><span class="count">{$shareCount}</span><span>公开分享</span></div>
<div class="col-xs-4"><span class="count">{$regDays}</span><span>注册天数</span></div>
<div class="col-xs-4"><span class="count">{$userInfo.id}</span><span>用户编号</span></div>
</div>
</footer>
</div>
</div>
<div class="col-md-9">
<div class="jumbotron">
<div class="card_botom">
<div class="row bottom-width">
<ul class="nav nav-tabs" >
<li id="all"><a href="?page=1" aria-expanded="true">全部分享<div class="ripple-container"></div></a></li>
<li id="hot"><a href="?type=hot" aria-expanded="false">热门分享<div class="ripple-container"></div></a></li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in">
<div class="panel panel-default">
<div class="panel-body" >
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th width="50%">文件名 </th>
<th class="cent">分享日期</th>
<th class="cent">下载次数</th>
<th class="cent">浏览次数</th>
</tr>
</thead>
<tbody>{volist name='list' id='shares'}
<tr>
<td >{switch $shares.source_type}
{case file}<i class="fa fa-file" aria-hidden="true"></i> {/case}
{case dir}<i class="fa fa-folder-open blue" aria-hidden="true"></i> {/case}
{/switch} <a href="/s/{$shares.share_key}" class="fname" target="_blank">{$shares.fileData|htmlspecialchars=ENT_NOQUOTES}</a></td>
<td class="cent">{$shares.share_time}</td>
<td align="center">{$shares.download_num}</td>
<td align="center">{$shares.view_num}</td>
</tr>
{/volist}
</tbody>
</table>
</div>
<div class="navi">
{eq name="$type" value="hot"}
{else/}
{$listOrigin->render()}
{/eq}
</div>
</div></div></div></div>
</div>
</div>
</div></div>
</div>
</div>
</body>
<script type="text/javascript">
</script>
<script src="/static/js/material.js"></script>
<script src="/static/js/profile.js"> </script>
{$options.js_code}
{/block}
+83
View File
@@ -0,0 +1,83 @@
<!doctype html>
<html lang="zh_cn" data-ng-app="FileManagerApp">
<head>
<!--
* Angular FileManager v1.5.1 (https://github.com/joni2back/angular-filemanager)
* Jonas Sciangula Street <joni2back@gmail.com>
* Licensed under MIT (https://github.com/joni2back/angular-filemanager/blob/master/LICENSE)
-->
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>我的文件 - {$options.siteName}</title>
<!-- third party -->
<script src="/static/js/angular.min.js"></script>
<script src="/static/js/angular-translate.min.js"></script>
<script src="/static/js/jquery.min.js"></script>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/material.css" />
<script src="/static/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
<!-- /third party -->
<!-- Comment if you need to use raw source code -->
<link href="/static/css/angular-filemanager.min.css" rel="stylesheet">
<link href="/static/css/toastr.min.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
<script src="/static/js/angular-filemanager.min.js"></script>
<!-- /Comment if you need to use raw source code -->
<script type="text/javascript">
uploadConfig={
saveType : "{$policyData.policy_type}",
maxSize : "{$policyData.max_size}mb",
allowedType: [
{$extLimit}
],
allowSource : "{$policyData.origin_link}",
upUrl : "{$policyData.server}",
allowShare:"{$groupData.allow_share}",
};
</script>
<script src="/static/js/home.js"></script>
</head>
<body class="ng-cloak">
<div id="container">
{include file="navbar_home" /}
<div class="col-md-2 s" id="side">
<div class="list-group" id="b">
<a href="/Home" class="list-group-item active">
<i class="fa fa-file" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 我的文件
</a>
<a href="/Share" class="list-group-item"> <i class="fa fa-share-alt" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 我的分享
</a>
<a href="#" class="list-group-item"><i class="fa fa-database" aria-hidden="true"></i>&nbsp;&nbsp;&nbsp; 容量配额
</a>
</div>
<div clss="usage" style=" visibility: visible;
position: absolute;
width: 100%;
height: 100px;
top: auto;
bottom: 0px;
background-color: #f3f3f3;padding: 15px">
<div class="usage-title">容量使用:</div>
<div class="usage-bar">
<div class="progress progress-striped active">
<div class="progress-bar" id="memory_bar"></div>
</div>
</div>
<div class="usage-text"><span id="used">--</span>/<span id="total">--</span></div>
</div>
</div>
<div class="col-md-10">
<angular-filemanager></angular-filemanager>
</div>
</div>
</body>
<script src="/static/js/material.js"></script>
<script type="text/javascript">
upload_load=0;
</script>
{$options.js_code}
</html>

Some files were not shown because too many files have changed in this diff Show More