Compare commits
No commits in common. "dev" and "v5" have entirely different histories.
|
|
@ -1,45 +0,0 @@
|
||||||
APP_DEBUG=true
|
|
||||||
APP_ENV=development
|
|
||||||
APP_FALLBACK_LOCALE=en
|
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
|
||||||
DB_HOST=127.0.0.1
|
|
||||||
DB_PORT=3306
|
|
||||||
DB_DATABASE=blessingskin
|
|
||||||
DB_USERNAME=username
|
|
||||||
DB_PASSWORD=secret
|
|
||||||
DB_PREFIX=
|
|
||||||
|
|
||||||
# Hash Algorithm for Passwords
|
|
||||||
#
|
|
||||||
# Available values:
|
|
||||||
# - BCRYPT, ARGON2I, PHP_PASSWORD_HASH
|
|
||||||
# - MD5, SALTED2MD5
|
|
||||||
# - SHA256, SALTED2SHA256
|
|
||||||
# - SHA512, SALTED2SHA512
|
|
||||||
#
|
|
||||||
# New sites are *highly* recommended to use BCRYPT.
|
|
||||||
#
|
|
||||||
PWD_METHOD=BCRYPT
|
|
||||||
APP_KEY=base64:JaytOHG/JlLgulTVAhiS0tRqnAfCkQydbdP6VRmoAMY=
|
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
|
||||||
MAIL_HOST=
|
|
||||||
MAIL_PORT=465
|
|
||||||
MAIL_USERNAME=
|
|
||||||
MAIL_PASSWORD=
|
|
||||||
MAIL_ENCRYPTION=
|
|
||||||
MAIL_FROM_ADDRESS=
|
|
||||||
MAIL_FROM_NAME=
|
|
||||||
|
|
||||||
CACHE_DRIVER=file
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
QUEUE_CONNECTION=sync
|
|
||||||
|
|
||||||
REDIS_CLIENT=phpredis
|
|
||||||
REDIS_HOST=127.0.0.1
|
|
||||||
REDIS_PASSWORD=null
|
|
||||||
REDIS_PORT=6379
|
|
||||||
|
|
||||||
PLUGINS_DIR=null
|
|
||||||
PLUGINS_URL=null
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
# [Choice] PHP version (use -bullseye variants on local arm64/Apple Silicon): 8, 8.1, 8.0, 7, 7.4, 7.3, 8-bullseye, 8.1-bullseye, 8.0-bullseye, 7-bullseye, 7.4-bullseye, 7.3-bullseye, 8-buster, 8.1-buster, 8.0-buster, 7-buster, 7.4-buster
|
|
||||||
ARG VARIANT=8-bullseye
|
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/php:0-${VARIANT}
|
|
||||||
|
|
||||||
# Install MariaDB client
|
|
||||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
||||||
&& apt-get install -y mariadb-client zlib1g-dev libpng-dev libzip-dev libwebp-dev \
|
|
||||||
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install php-mysql driver
|
|
||||||
RUN docker-php-ext-install mysqli pdo pdo_mysql gd zip
|
|
||||||
|
|
||||||
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
|
||||||
ARG NODE_VERSION="none"
|
|
||||||
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
|
||||||
|
|
||||||
# Enable Apache rewrite module
|
|
||||||
RUN a2enmod rewrite
|
|
||||||
|
|
||||||
# [Optional] Uncomment this section to install additional OS packages.
|
|
||||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
||||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
|
||||||
|
|
||||||
# [Optional] Uncomment this line to install global node packages.
|
|
||||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
|
||||||
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
Listen 8080
|
|
||||||
|
|
||||||
<Directory /workspace/public/>
|
|
||||||
Options Indexes FollowSymLinks
|
|
||||||
AllowOverride All
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
<VirtualHost *:8080>
|
|
||||||
DocumentRoot /workspace/public
|
|
||||||
ErrorLog /workspace/storage/logs/apache-error.log
|
|
||||||
CustomLog /workspace/storage/logs/apache-access.log combined
|
|
||||||
</VirtualHost>
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
|
||||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.231.6/containers/php-mariadb
|
|
||||||
// Update the VARIANT arg in docker-compose.yml to pick a PHP version
|
|
||||||
{
|
|
||||||
"name": "PHP & MariaDB (Community)",
|
|
||||||
"dockerComposeFile": "docker-compose.yml",
|
|
||||||
"service": "app",
|
|
||||||
"workspaceFolder": "/workspace",
|
|
||||||
|
|
||||||
// Set *default* container specific settings.json values on container create.
|
|
||||||
"settings": {},
|
|
||||||
|
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
|
||||||
"extensions": [
|
|
||||||
"xdebug.php-debug",
|
|
||||||
"bmewburn.vscode-intelephense-client",
|
|
||||||
"mrmlnc.vscode-apache"
|
|
||||||
],
|
|
||||||
|
|
||||||
// For use with PHP or Apache (e.g.php -S localhost:8080 or apache2ctl start)
|
|
||||||
"forwardPorts": [8080, 3306],
|
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
|
||||||
"postCreateCommand": "sudo truncate -s 0 /etc/apache2/ports.conf && sudo rm -f /etc/apache2/sites-enabled/000-default.conf && sudo ln -sf /workspace/.devcontainer/blessing-skin.apache.conf /etc/apache2/sites-enabled/ && ln -sf .devcontainer/.env.devcontainer .env && composer install && yarn install",
|
|
||||||
|
|
||||||
// Start apache2 after the container is started
|
|
||||||
"postStartCommand": "apache2ctl start && echo '\\n👉 \\e[0;32mPlease run '\\'yarn build\\'' to build the frontend. Application is available on port 8080.\\e[0m 👈\\n'",
|
|
||||||
|
|
||||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
||||||
"remoteUser": "vscode",
|
|
||||||
"features": {
|
|
||||||
"powershell": "latest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
# Update 'VARIANT' to pick a version of PHP version: 8, 8.1, 8.0, 7, 7.4
|
|
||||||
# Append -bullseye or -buster to pin to an OS version.
|
|
||||||
# Use -bullseye variants on local arm64/Apple Silicon.
|
|
||||||
VARIANT: "8-bullseye"
|
|
||||||
# Optional Node.js version
|
|
||||||
NODE_VERSION: "lts/*"
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- ..:/workspace:cached
|
|
||||||
|
|
||||||
# Overrides default command so things don't shut down after the process ends.
|
|
||||||
command: sleep infinity
|
|
||||||
|
|
||||||
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
|
|
||||||
network_mode: service:db
|
|
||||||
|
|
||||||
# Uncomment the next line to use a non-root user for all processes.
|
|
||||||
# user: vscode
|
|
||||||
|
|
||||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
|
||||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: mariadb:10.4
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- mariadb-data:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: mariadb
|
|
||||||
MYSQL_DATABASE: blessingskin
|
|
||||||
MYSQL_USER: username
|
|
||||||
MYSQL_PASSWORD: secret
|
|
||||||
|
|
||||||
# Add "forwardPorts": ["3306"] to **devcontainer.json** to forward MariaDB locally.
|
|
||||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
mariadb-data:
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
.git/
|
.git/
|
||||||
.github/
|
.github/
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
|
||||||
.cache/
|
|
||||||
.cache-loader/
|
|
||||||
coverage/
|
coverage/
|
||||||
node_modules/
|
node_modules/
|
||||||
plugins/**
|
plugins/**
|
||||||
|
|
@ -11,13 +8,7 @@ public/app/*
|
||||||
public/lang/*
|
public/lang/*
|
||||||
public/plugins/**
|
public/plugins/**
|
||||||
resources/assets/tests/
|
resources/assets/tests/
|
||||||
storage/*.db
|
scripts/
|
||||||
storage/*.sqlite
|
|
||||||
storage/insane-profile-cache
|
|
||||||
storage/oauth-public.key
|
|
||||||
storage/oauth-private.key
|
|
||||||
storage/install.lock
|
|
||||||
storage/options.php
|
|
||||||
storage/debugbar
|
storage/debugbar
|
||||||
storage/framework/cache/**
|
storage/framework/cache/**
|
||||||
storage/framework/sessions/**
|
storage/framework/sessions/**
|
||||||
|
|
@ -26,34 +17,24 @@ storage/framework/views/**
|
||||||
storage/logs/**
|
storage/logs/**
|
||||||
storage/packages/**
|
storage/packages/**
|
||||||
storage/textures/*
|
storage/textures/*
|
||||||
storage/update_cache/*
|
|
||||||
target/
|
|
||||||
tests/
|
tests/
|
||||||
vendor/*
|
vendor/
|
||||||
_ide_helper.php
|
_ide_helper.php
|
||||||
.dockerignore
|
.dockerignore
|
||||||
.editorconfig
|
.editorconfig
|
||||||
.env
|
.env
|
||||||
.env.testing
|
.env.testing
|
||||||
.eslintignore
|
.eslintignore
|
||||||
.eslintrc.yml
|
|
||||||
.gitignore
|
.gitignore
|
||||||
.php_cs.*
|
.php_cs.*
|
||||||
.php-cs-fixer.cache
|
|
||||||
.php-cs-fixer.dist.php
|
|
||||||
.phpstorm.meta.php
|
.phpstorm.meta.php
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
.sass-cache
|
|
||||||
.uini
|
|
||||||
azure-pipelines.yml
|
azure-pipelines.yml
|
||||||
crowdin.yml
|
crowdin.yml
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
Dockerfile*
|
*.Dockerfile
|
||||||
index.html
|
index.html
|
||||||
junit.xml
|
|
||||||
phpunit.xml
|
phpunit.xml
|
||||||
README*.md
|
README*.md
|
||||||
server.php
|
server.php
|
||||||
tsconfig.dev.json
|
|
||||||
tsconfig.eslint.json
|
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ APP_DEBUG=false
|
||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
|
|
||||||
|
ASSET_ENV=production
|
||||||
|
ASSET_URL=
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
|
|
|
||||||
68
.env.testing
68
.env.testing
|
|
@ -35,71 +35,3 @@ PLUGINS_URL=
|
||||||
TEXTURES_DIR=
|
TEXTURES_DIR=
|
||||||
|
|
||||||
JWT_SECRET=1tdM3gXarxYI4KlAHMBo238iC2tEb4I3EtBlZTQQXvInXIt7V2ix7hJ1KTvxCKZW
|
JWT_SECRET=1tdM3gXarxYI4KlAHMBo238iC2tEb4I3EtBlZTQQXvInXIt7V2ix7hJ1KTvxCKZW
|
||||||
|
|
||||||
PASSPORT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC6q6SCprX3yfOE
|
|
||||||
DFBnfFk3R+33qvoe26nYQkavKfv7zA9KQxCBNHEsFKOQ6ui+ViebVHAIHBPm2518
|
|
||||||
REVMLN2JONvXbPETV6gJO/b6FFwo2Aow/GbTnesLhWEAPW11ei0/hBbjWF9hQZ/n
|
|
||||||
x3YsFk0xtml2iPDijfUohwp50iFyCQylw4S5Sy3vuVdM063dkxvECsU6wmHDev9C
|
|
||||||
PxFZGl3W2iLSwttYl7xmlwll8xuqxDQUJpJbOxrPeDKdDI1ikarSqA1c8bV1YLT+
|
|
||||||
CHxB7T5b1EPeaYRmeLl+wyd/ZxeBWWgDLBusi5wPFpSEIVxu1RzTYarOXEpD+XNV
|
|
||||||
Ohpb7LxpbJx8YRJru1B6CBouVO2pqoCEM21GtG7zSDNtaY+yVcj9Kf2SIbfz0e6a
|
|
||||||
SLAcyOT0q3aId4+z9q8TAfPVV7y0D7B3PaOz/3pMC+jHDjCRwQkN/DR7ODUKEjCd
|
|
||||||
UjsveGHtseBa3qBoKWcg39ZvwYeDF0P/cFa/yOqw5JxyWhbjk95YdPaSixdUyyMG
|
|
||||||
XkFTOrnBREVtBAfdTOG6WTFcIlyJK+ST0cJXVcrjFonbmJCCwTJqxz9t+935CfTt
|
|
||||||
CzLLPdONU16jZJ7j1cVoWb4L8o0OA+FBSawBxFOKyhFlh3+HKRnSCZSDqaSDsYUf
|
|
||||||
M3IupiGUcByhpZ9mNqhnLeivIXwapwIDAQABAoICAFu27F+S2DH0A9S7lh+aPV1H
|
|
||||||
VniKhVR2+aZ6va7fUmJ++n4yoB/TK82MIGcZu5uUyeXr4RVi8jZJbcF565BHNNtw
|
|
||||||
V7cq2/F0bmeHEkwBh9w7dRpnUIAlhS/GawfKpoaDLksYM4SkzUwECbQ/0GRN2sST
|
|
||||||
ipKGKtAtDihI3RFIeE1Ge/PPsdy2Ps4bAnUJRdHpLsmtvwSlL5JzUonyYawlI7jl
|
|
||||||
uRlTSqDnAFZpW+E+xjerKalC4EK5se0AceGuoqKszkCs98/UJCMVDigH9EER9sL4
|
|
||||||
chYLQtVz+DN7X+MdPDO9wThZygkHGPhi0DpxB7CevYhv4pN8TbLDE3Lq1ruWf2T3
|
|
||||||
7ts21ymjVIiOayBA9l86P0FSS/lP9KF53LyeNkOJKUy5On6xHoW5IKlrMJdmGwFH
|
|
||||||
B4yaR7bw5vxErhpMTzcYJVWqjCbo+PBJhdy7x+2XrrBLs9X0hfS/jeeAIuRlzju1
|
|
||||||
9xe3zO6U41sDjkCkrUavOn57DL6jh9LMgxT8cZkSdrP6rpawEyjPUi5kMbbQkv0j
|
|
||||||
eWiqz0vozJN5HcVpj36F5kqZyCnIojmeo4FCKdn7n/wvyGYQPSAekVpV80KzoJ2j
|
|
||||||
GQ440Q7Sgozj/Lw4cCPgG3/MA1Dwu+TUuaddFjBH2oqZ2X0bCqVCEVWhfmaD4z2R
|
|
||||||
I9C9nLvpxoMtcCHkG1VFAoIBAQDfawcBHMPxZQOy/qTqXZd7YR3bzGgd/SkLEWwg
|
|
||||||
PtDGKe36tDf3E/RGRij4HGl9v/fA7N/CufW0tJY7Ii/cn7yYdZg/dzaCoYIZbICl
|
|
||||||
CytWtsM0iH3XPuY3UpgsOwML0xK8hdD1U7qBKk5rnjF9Q9vKrB8ATR9hM0bPaGtr
|
|
||||||
Bqfx8A+kj6wqRpA8jbN0kZxJVv0/LgZSCrH3qUjHfXoYYtLhMBZd8UydyvyETo/1
|
|
||||||
Z44WS9oNqX8mBUvHjsuOQx3+eFPOr69QPIo06QMxytSEzMilgz40QUBWF68gKwGi
|
|
||||||
NYdUfR3IXVTmvJhYH2mQWqMKVk+KJFd2UanjKbBCOKrDSG4TAoIBAQDV5LMp/ztd
|
|
||||||
YQvMCWJzUrpazGqkoEGli/qxWb/pDpemgQT++lt6PBRQmmLKXZfNp9VJdZdP6+lF
|
|
||||||
ypGcA8tACY93m7Fk4wtewXG+0oTxmBkWqSiiO3ExoBQTxXLoZ9GwKt/exaM25QJ1
|
|
||||||
O2livxrYFFJbUe1YRqQENIURYk13RgeIaWS0gd9vp/yp0EhZAvGUPHFjKRsLjw7Y
|
|
||||||
gZDJ+lXj2pXg9THUzkhVDm+fM6blIsLcvf7qc8yKQI3nwZr00e/ba7xSNF8AhpdP
|
|
||||||
rxw59vm1RzsngZpZOK0Z1143gFRtGhhVWtvmhCvJo1EOssFu01ixE0bNq5nRIIJo
|
|
||||||
O/mY7NC9bCOdAoIBAEBfcyYz5pUwGM/DJTtN+i6XfeXt0HYLkn7Y50GnN7pRLHuW
|
|
||||||
36U2P6Tb5EQQ06hi3nzdA1/0+sG1Yq/pGsdD0zBOea6Xp8IdzQGMTMjBHhyfDkGd
|
|
||||||
rjyNqAF6r9PWsPsANx7Qo7N8C3nZ+bxyWSoRmkucKlaI4ii8gIOUP5cX1N4V4Dv3
|
|
||||||
FZEcwcRgw7srlU9gXBmPJk0PPdXxFcI8+if6mW4+z8MDmqLAcN+iT0JTMxJjipFz
|
|
||||||
K+qFjh8Smr4Dwqmme+dKoYXJ27yBAuWe3nrhElL2LL8bqfDkZBYtrgvRxotmfWVU
|
|
||||||
1vigkHibnGv2YZHB6qsP649w2jVUtq9t6m3X+bcCggEAEKDqCN7N17GewCsOm1aY
|
|
||||||
JEz2EXxf/iXGxJjsoYq/4XLwV35RNEyNa8LE4WSrU5KzszVQISd/CCz6av2khIL5
|
|
||||||
w1u4S9aW4LP7StGFAl9HvApEnXAvmaMPTIYyK70+gQqkQuZsjOz65vBKfiHLTXcu
|
|
||||||
++h/ojhDsgv/OF3DFf28wi8nZB0gqMaPjwghR8JB07trOUFN1/U0O0K/ZeRvXvp0
|
|
||||||
YnvNdvTejLZFmUPjuracHZsrwUBla24fWiAkEtprYkya5G0r4ZeVFd3QPPVlbmFu
|
|
||||||
SOD7heoxEuw6Z+gzKBQ6RhB9PguSd+eZeqINBbeqkoGkJIMtvyNe4AmhmvD2PXO1
|
|
||||||
xQKCAQAx12vD3q2+DHrpJ4fKGp1RbCxFIOYgXcBJ6zCozVZXpLUa54IBTLyQyDNF
|
|
||||||
D8+Wq5b1IbCnxBn55tsgq/CSLkVHigVfUDGnAt3lD+ggLdZmu7ayQY0BNe1quF5M
|
|
||||||
EgkOE0uYtq+2p+u4gxRB+gnQd1YIlPs0U0mrawbzV5ZX2vR5Ry1XpBno75JpnUbN
|
|
||||||
3D9DuIDVLuqsKJcx6KClWef2PzJB2uN7jDf4UnCtp5QCFB1GNt+5AzCNh9Bozas8
|
|
||||||
OflASrSn64AeyCZycCplmRY/F4BnH++7YI0Q/mjawByW7qYoHkFzmKuUcgakh200
|
|
||||||
y/ieeWy8Vunl0e4T4Bz/0zInBifn
|
|
||||||
-----END PRIVATE KEY-----"
|
|
||||||
|
|
||||||
PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
|
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuqukgqa198nzhAxQZ3xZ
|
|
||||||
N0ft96r6Htup2EJGryn7+8wPSkMQgTRxLBSjkOrovlYnm1RwCBwT5tudfERFTCzd
|
|
||||||
iTjb12zxE1eoCTv2+hRcKNgKMPxm053rC4VhAD1tdXotP4QW41hfYUGf58d2LBZN
|
|
||||||
MbZpdojw4o31KIcKedIhcgkMpcOEuUst77lXTNOt3ZMbxArFOsJhw3r/Qj8RWRpd
|
|
||||||
1toi0sLbWJe8ZpcJZfMbqsQ0FCaSWzsaz3gynQyNYpGq0qgNXPG1dWC0/gh8Qe0+
|
|
||||||
W9RD3mmEZni5fsMnf2cXgVloAywbrIucDxaUhCFcbtUc02GqzlxKQ/lzVToaW+y8
|
|
||||||
aWycfGESa7tQeggaLlTtqaqAhDNtRrRu80gzbWmPslXI/Sn9kiG389HumkiwHMjk
|
|
||||||
9Kt2iHePs/avEwHz1Ve8tA+wdz2js/96TAvoxw4wkcEJDfw0ezg1ChIwnVI7L3hh
|
|
||||||
7bHgWt6gaClnIN/Wb8GHgxdD/3BWv8jqsOSccloW45PeWHT2kosXVMsjBl5BUzq5
|
|
||||||
wURFbQQH3UzhulkxXCJciSvkk9HCV1XK4xaJ25iQgsEyasc/bfvd+Qn07Qsyyz3T
|
|
||||||
jVNeo2Se49XFaFm+C/KNDgPhQUmsAcRTisoRZYd/hykZ0gmUg6mkg7GFHzNyLqYh
|
|
||||||
lHAcoaWfZjaoZy3oryF8GqcCAwEAAQ==
|
|
||||||
-----END PUBLIC KEY-----"
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ extends:
|
||||||
- eslint:recommended
|
- eslint:recommended
|
||||||
- plugin:@typescript-eslint/recommended
|
- plugin:@typescript-eslint/recommended
|
||||||
- plugin:@typescript-eslint/recommended-requiring-type-checking
|
- plugin:@typescript-eslint/recommended-requiring-type-checking
|
||||||
- plugin:react-hooks/recommended
|
|
||||||
rules:
|
rules:
|
||||||
prefer-const: error
|
prefer-const: error
|
||||||
'@typescript-eslint/no-unsafe-assignment': off
|
'@typescript-eslint/no-unsafe-assignment': off
|
||||||
|
|
@ -24,4 +23,3 @@ rules:
|
||||||
- off
|
- off
|
||||||
- checksVoidReturn: false
|
- checksVoidReturn: false
|
||||||
'@typescript-eslint/unbound-method': off
|
'@typescript-eslint/unbound-method': off
|
||||||
'@typescript-eslint/restrict-template-expressions': off
|
|
||||||
|
|
|
||||||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
|
@ -46,7 +46,7 @@ location ~* \w+\.hot-update\.json$ {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
当 `APP_ENV` 为其它值时,您需要事先执行 `pwsh ./tools/build.ps1`。此命令将构建并压缩前端资源。通常用于生产环境。
|
当 `APP_ENV` 为其它值时,您需要事先执行 `pwsh ./scripts/build.ps1`。此命令将构建并压缩前端资源。通常用于生产环境。
|
||||||
|
|
||||||
> 如果传递 `-Simple` 参数给 `build.ps1` 脚本,则只会运行 webpack 来编译代码,而不会复制首页背景以及生成 commit 信息。
|
> 如果传递 `-Simple` 参数给 `build.ps1` 脚本,则只会运行 webpack 来编译代码,而不会复制首页背景以及生成 commit 信息。
|
||||||
|
|
||||||
|
|
|
||||||
36
.github/ISSUE_TEMPLATE.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!-- 在提交一个新 issue 前,请先阅读以下内容: -->
|
||||||
|
<!-- Before opening a new issue, please make sure to READ the articles below: -->
|
||||||
|
<!-- * FAQ 常见问题: https://git.io/fjRtn -->
|
||||||
|
<!-- * 报告问题的正确姿势:https://git.io/fjRtc -->
|
||||||
|
|
||||||
|
<!-- 把下面模板中的占位文字删除,并按照你的情况认真填写,谢谢 -->
|
||||||
|
<!-- Please remove the placeholders and fill in the template according to your situation. -->
|
||||||
|
|
||||||
|
## The Problem 问题描述
|
||||||
|
|
||||||
|
<!-- 如果您要报告的问题是与插件相关的,请在 bs-community/blessing-skin-plugins 提 issue,谢谢合作 -->
|
||||||
|
<!-- If you're going to report a problem related to plugins, please open issue at bs-community/blessing-skin-plugins. -->
|
||||||
|
|
||||||
|
## Environment 运行环境
|
||||||
|
|
||||||
|
- Blessing Skin 版本 (Version of Blessing Skin):
|
||||||
|
- PHP 版本 (Version of PHP):
|
||||||
|
- Apache / Nginx:
|
||||||
|
- 什么浏览器,出现错误时的地址栏 URL 是什么 (Which browser and URL):
|
||||||
|
|
||||||
|
## Error Message 错误信息
|
||||||
|
|
||||||
|
<!--
|
||||||
|
请提供详细信息,如截图。日志内容请不要直接贴出来,请把它放在 pastebin 等网站上。
|
||||||
|
不提供详细信息的 issue 或不按要求提供日志的将被直接忽略,谢谢合作。
|
||||||
|
Please provide more information, such as screenshots.
|
||||||
|
For logs, don't paste it in issue directly. You can paste in on pastebin.
|
||||||
|
You will be ignored if you don't provide enough information or
|
||||||
|
your logs messes up the issue.
|
||||||
|
Thanks for your cooperation.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Steps to Reproduce 重现步骤
|
||||||
|
|
||||||
|
<!-- Tell us how to reproduce this issue. -->
|
||||||
|
<!-- 详细描述你出错前的操作步骤 -->
|
||||||
71
.github/ISSUE_TEMPLATE/bug-report-zh.yml
vendored
71
.github/ISSUE_TEMPLATE/bug-report-zh.yml
vendored
|
|
@ -1,71 +0,0 @@
|
||||||
name: Bug 报告
|
|
||||||
description: 发起 bug 报告
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
在报告问题之前,请确保您已经 **认真** 阅读:
|
|
||||||
- [FAQ](https://blessing.netlify.app/en/faq.html)
|
|
||||||
- [报告问题的正确姿势](https://blessing.netlify.app/report.html)
|
|
||||||
- type: input
|
|
||||||
id: bs
|
|
||||||
attributes:
|
|
||||||
label: Blessing Skin 版本
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: php
|
|
||||||
attributes:
|
|
||||||
label: PHP 版本
|
|
||||||
options:
|
|
||||||
- '7.3'
|
|
||||||
- '7.4'
|
|
||||||
- '8.0'
|
|
||||||
- '8.1'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: browsers
|
|
||||||
attributes:
|
|
||||||
label: 出现问题时所使用的浏览器
|
|
||||||
multiple: true
|
|
||||||
options:
|
|
||||||
- Firefox
|
|
||||||
- Chrome
|
|
||||||
- Safari
|
|
||||||
- Microsoft Edge
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: web-server
|
|
||||||
attributes:
|
|
||||||
label: 您正在使用的 Web Server
|
|
||||||
options:
|
|
||||||
- Nginx
|
|
||||||
- Apache
|
|
||||||
- type: checkboxes
|
|
||||||
id: baota
|
|
||||||
attributes:
|
|
||||||
label: 您正在使用宝塔吗?
|
|
||||||
options:
|
|
||||||
- label: 是
|
|
||||||
- type: textarea
|
|
||||||
id: what-happened
|
|
||||||
attributes:
|
|
||||||
label: 出现了什么问题?
|
|
||||||
description: 顺便告诉我们,您期望的行为是怎样的?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: 错误日志
|
|
||||||
description: 您可以粘贴 Blessing Skin 的日志或 Web Server 的日志。Blessing Skin 的日志位于 `storage/logs` 目录里。
|
|
||||||
render: text
|
|
||||||
- type: textarea
|
|
||||||
id: reproduction
|
|
||||||
attributes:
|
|
||||||
label: 重现步骤
|
|
||||||
description: 详细描述您出错前的操作步骤
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
64
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
64
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
name: Bug Report
|
|
||||||
description: File a bug report
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Please filing an issue, please make sure you've read:
|
|
||||||
- [FAQ](https://blessing.netlify.app/en/faq.html)
|
|
||||||
- type: input
|
|
||||||
id: bs
|
|
||||||
attributes:
|
|
||||||
label: Which version of Blessing Skin are you using?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: php
|
|
||||||
attributes:
|
|
||||||
label: Which version of PHP are you using?
|
|
||||||
options:
|
|
||||||
- '7.3'
|
|
||||||
- '7.4'
|
|
||||||
- '8.0'
|
|
||||||
- '8.1'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: browsers
|
|
||||||
attributes:
|
|
||||||
label: What browsers are you seeing the problem on?
|
|
||||||
multiple: true
|
|
||||||
options:
|
|
||||||
- Firefox
|
|
||||||
- Chrome
|
|
||||||
- Safari
|
|
||||||
- Microsoft Edge
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: web-server
|
|
||||||
attributes:
|
|
||||||
label: Which web server are you using?
|
|
||||||
options:
|
|
||||||
- Nginx
|
|
||||||
- Apache
|
|
||||||
- type: textarea
|
|
||||||
id: what-happened
|
|
||||||
attributes:
|
|
||||||
label: What happened?
|
|
||||||
description: Also tell us, what did you expect to happen?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: Error Logs
|
|
||||||
description: You can paste logs of Blessing Skin or your web server. Logs of Blessing Skin can be found at `storage/logs` directory.
|
|
||||||
render: text
|
|
||||||
- type: textarea
|
|
||||||
id: reproduction
|
|
||||||
attributes:
|
|
||||||
label: Steps to Reproduce
|
|
||||||
description: Tell us how to reproduce this issue.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
20
.github/ISSUE_TEMPLATE/config.yml
vendored
20
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Ask questions about using Blessing Skin
|
|
||||||
url: https://github.com/bs-community/blessing-skin-server/discussions
|
|
||||||
about: If you're not going to report a bug, please ask and answer questions there.
|
|
||||||
- name: Report Issue about Blessing Skin plugins
|
|
||||||
url: https://github.com/bs-community/blessing-skin-plugins/issues
|
|
||||||
about: Please ask and answer questions there.
|
|
||||||
- name: Report Issue about integrating with Flarum
|
|
||||||
url: https://github.com/bs-community/flarum-oauth-client/issues
|
|
||||||
about: Please ask and answer questions there.
|
|
||||||
- name: 询问关于使用 Blessing Skin 的问题
|
|
||||||
url: https://github.com/bs-community/blessing-skin-server/discussions
|
|
||||||
about: 如果您并不是要报告 bug,请在那里进行讨论。
|
|
||||||
- name: 报告与 Blessing Skin 插件有关的问题
|
|
||||||
url: https://github.com/bs-community/blessing-skin-plugins/issues
|
|
||||||
about: 请在那里报告问题。
|
|
||||||
- name: 报告与 Flarum 对接有关的问题
|
|
||||||
url: https://github.com/bs-community/flarum-oauth-client/issues
|
|
||||||
about: 请在那里报告问题。
|
|
||||||
204
.github/workflows/CI.yml
vendored
204
.github/workflows/CI.yml
vendored
|
|
@ -18,138 +18,104 @@ jobs:
|
||||||
php-lint:
|
php-lint:
|
||||||
name: PHP Linting
|
name: PHP Linting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
php-version: 8.3
|
php-version: 7.4
|
||||||
coverage: none
|
coverage: none
|
||||||
extensions: mbstring, dom, fileinfo, gd, imagick
|
extensions: mbstring, dom, fileinfo, gd
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
composer install --prefer-dist --no-progress
|
composer install --prefer-dist --no-progress --no-suggest
|
||||||
- name: Prepare
|
composer global require friendsofphp/php-cs-fixer
|
||||||
run: |
|
- name: Prepare
|
||||||
cp .env.example .env
|
run: |
|
||||||
mkdir -p resources/views/overrides
|
cp .env.example .env
|
||||||
- name: Validate Twig templates
|
php artisan key:generate
|
||||||
run: php artisan twig:lint -v
|
mkdir -p resources/views/overrides
|
||||||
- name: Check coding style
|
- name: Validate Twig templates
|
||||||
run: ./vendor/bin/php-cs-fixer fix --dry-run --stop-on-violation --diff --format=txt
|
run: php artisan twig:lint -v
|
||||||
|
- name: Check coding style
|
||||||
|
run: php-cs-fixer fix --dry-run --stop-on-violation --diff-format=udiff
|
||||||
php:
|
php:
|
||||||
name: PHP ${{ matrix.php }} Tests
|
name: PHP ${{ matrix.php }} Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
php: ['8.2', '8.3']
|
php: ['7.2', '7.3', '7.4']
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Setup PHP only
|
- name: Setup PHP only
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
if: matrix.php != '8.3'
|
if: matrix.php != '7.2'
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php }}
|
php-version: ${{ matrix.php }}
|
||||||
coverage: none
|
coverage: none
|
||||||
extensions: mbstring, dom, fileinfo, sqlite, gd, zip, imagick
|
extensions: mbstring, dom, fileinfo, sqlite, gd, zip
|
||||||
- name: Setup PHP with Xdebug
|
- name: Setup PHP with Xdebug
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
if: matrix.php == '8.3'
|
if: matrix.php == '7.2'
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php }}
|
php-version: ${{ matrix.php }}
|
||||||
coverage: xdebug
|
coverage: xdebug
|
||||||
extensions: mbstring, dom, fileinfo, sqlite, gd, zip, imagick
|
extensions: mbstring, dom, fileinfo, sqlite, gd, zip
|
||||||
- name: Cache Composer dependencies
|
- name: Cache Composer dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v1
|
||||||
with:
|
with:
|
||||||
path: vendor
|
path: vendor
|
||||||
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
|
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
|
||||||
restore-keys: ${{ runner.os }}-composer-
|
restore-keys: ${{ runner.os }}-composer-
|
||||||
- name: Install Composer dependencies
|
- name: Install Composer dependencies
|
||||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
|
||||||
- name: Run tests only
|
- name: Run tests only
|
||||||
if: matrix.php != '8.3'
|
if: matrix.php != '7.2'
|
||||||
run: ./vendor/bin/phpunit
|
run: ./vendor/bin/phpunit
|
||||||
- name: Run tests with coverage report
|
shell: pwsh
|
||||||
if: matrix.php == '8.3'
|
- name: Run tests with coverage report
|
||||||
run: ./vendor/bin/phpunit --coverage-clover=coverage.xml
|
if: matrix.php == '7.2'
|
||||||
- name: Upload coverage report
|
run: ./vendor/bin/phpunit --coverage-clover=coverage.xml
|
||||||
uses: codecov/codecov-action@v1
|
shell: pwsh
|
||||||
if: matrix.php == '8.3' && success()
|
- name: Upload coverage report
|
||||||
with:
|
uses: codecov/codecov-action@v1
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
if: matrix.php == '7.2' && success()
|
||||||
name: github-actions
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
name: github-actions
|
||||||
lint:
|
lint:
|
||||||
name: Frontend Linting
|
name: Frontend Linting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn
|
||||||
- name: Run checks
|
- name: Run checks
|
||||||
run: |
|
run: |
|
||||||
yarn lint
|
yarn lint
|
||||||
yarn fmt:check
|
yarn fmt:check
|
||||||
yarn type:check
|
yarn tsc -p . --noEmit
|
||||||
|
yarn tsc -p ./resources/assets/tests --noEmit
|
||||||
jest:
|
jest:
|
||||||
name: Frontend Tests
|
name: Frontend Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: yarn test --coverage
|
run: yarn test --coverage
|
||||||
- name: Upload coverage report
|
- name: Upload coverage report
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
name: github-actions
|
name: github-actions
|
||||||
build:
|
|
||||||
name: Snapshot Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: 8.2
|
|
||||||
coverage: none
|
|
||||||
extensions: mbstring, dom, fileinfo, sqlite, gd, zip, imagick
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Cache Node dependencies
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-yarn-lock-${{ hashFiles('yarn.lock') }}
|
|
||||||
restore-keys: ${{ runner.os }}-yarn-lock-
|
|
||||||
- name: Cache Composer dependencies
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: vendor
|
|
||||||
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
|
|
||||||
restore-keys: ${{ runner.os }}-composer-
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
composer install --prefer-dist --no-progress --no-dev
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
- name: Build frontend
|
|
||||||
run: |
|
|
||||||
yarn build
|
|
||||||
cp resources/assets/src/images/bg.webp public/app/
|
|
||||||
cp resources/assets/src/images/favicon.ico public/app/
|
|
||||||
- uses: benjlevesque/short-sha@v3.0
|
|
||||||
id: short-sha
|
|
||||||
- name: Archive release
|
|
||||||
run: zip -9 -r blessing-skin-server-${{ steps.short-sha.outputs.sha }}.zip app bootstrap config database plugins public resources/lang resources/views resources/misc/textures routes storage vendor .env.example artisan LICENSE README.md README-zh.md index.html
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
if-no-files-found: error
|
|
||||||
name: blessing-skin-server-${{ steps.short-sha.outputs.sha }}.zip
|
|
||||||
path: blessing-skin-server-${{ steps.short-sha.outputs.sha }}.zip
|
|
||||||
|
|
|
||||||
57
.github/workflows/Release.yml
vendored
57
.github/workflows/Release.yml
vendored
|
|
@ -9,32 +9,31 @@ jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- name: Build and create archive
|
- name: Build and create archive
|
||||||
run: ./tools/release.ps1
|
run: ./scripts/release.ps1
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}
|
AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
release_name: ${{ github.ref }}
|
release_name: ${{ github.ref }}
|
||||||
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
|
- name: Get version
|
||||||
- name: Get version
|
id: get_version
|
||||||
id: get_version
|
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
|
- name: Upload release asset
|
||||||
- name: Upload release asset
|
id: upload_release_asset
|
||||||
id: upload_release_asset
|
uses: actions/upload-release-asset@v1
|
||||||
uses: actions/upload-release-asset@v1
|
env:
|
||||||
env:
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
with:
|
||||||
with:
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
asset_path: ./blessing-skin-server-${{ steps.get_version.outputs.VERSION }}.zip
|
||||||
asset_path: ./blessing-skin-server-${{ steps.get_version.outputs.VERSION }}.zip
|
asset_name: blessing-skin-server-${{ steps.get_version.outputs.VERSION }}.zip
|
||||||
asset_name: blessing-skin-server-${{ steps.get_version.outputs.VERSION }}.zip
|
asset_content_type: application/zip
|
||||||
asset_content_type: application/zip
|
|
||||||
|
|
|
||||||
29
.github/workflows/Telegram.yml
vendored
29
.github/workflows/Telegram.yml
vendored
|
|
@ -14,24 +14,23 @@ on:
|
||||||
- 'routes/**'
|
- 'routes/**'
|
||||||
- '*.lock'
|
- '*.lock'
|
||||||
- 'webpack.*'
|
- 'webpack.*'
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
notification:
|
notification:
|
||||||
name: Send Message
|
name: Send Message
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download bot
|
- name: Download bot
|
||||||
run: |
|
run: |
|
||||||
$headers = @{ Authorization = 'Bearer ${{ secrets.GITHUB_TOKEN }}' }
|
$headers = @{ Authorization = 'Bearer ${{ secrets.GITHUB_TOKEN }}' }
|
||||||
$botRelease = (Invoke-WebRequest -Headers $headers 'https://api.github.com/repos/bs-community/telegram-bot/releases/latest').Content | ConvertFrom-Json
|
$botRelease = (Invoke-WebRequest -Headers $headers 'https://api.github.com/repos/bs-community/telegram-bot/releases/latest').Content | ConvertFrom-Json
|
||||||
$botBinUrl = ((Invoke-WebRequest -Headers $headers $botRelease.assets_url).Content | ConvertFrom-Json).browser_download_url
|
$botBinUrl = ((Invoke-WebRequest -Headers $headers $botRelease.assets_url).Content | ConvertFrom-Json).browser_download_url
|
||||||
bash -c "curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -fSL $botBinUrl -o bot"
|
bash -c "curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -fSL $botBinUrl -o bot"
|
||||||
chmod +x ./bot
|
chmod +x ./bot
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Run bot
|
- name: Run bot
|
||||||
run: ./bot diff
|
run: ./bot diff
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||||||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||||||
|
|
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
.env
|
.env
|
||||||
.sass-cache
|
.sass-cache
|
||||||
coverage
|
coverage
|
||||||
|
|
@ -23,7 +24,7 @@ storage/oauth-private.key
|
||||||
storage/install.lock
|
storage/install.lock
|
||||||
storage/options.php
|
storage/options.php
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
.php-cs-fixer.cache
|
.php_cs.cache
|
||||||
resources/views/overrides
|
resources/views/overrides
|
||||||
.DS_Store
|
public/sw.js
|
||||||
*/.DS_Store
|
public/meta.js
|
||||||
|
|
|
||||||
41
.gitpod.yml
41
.gitpod.yml
|
|
@ -1,41 +0,0 @@
|
||||||
tasks:
|
|
||||||
- init: yarn install
|
|
||||||
command: yarn dev
|
|
||||||
- init: composer install
|
|
||||||
command: |
|
|
||||||
cp .env.example .env
|
|
||||||
mkdir public/app/
|
|
||||||
cp resources/assets/src/images/bg.webp resources/assets/src/images/favicon.ico public/app
|
|
||||||
touch storage/database.db
|
|
||||||
sed 's/DB_CONNECTION=mysql/DB_CONNECTION=sqlite/' -i .env
|
|
||||||
sed 's/DB_DATABASE=blessingskin/DB_DATABASE=\/workspace\/blessing-skin-server\/storage\/database\.db/' -i .env
|
|
||||||
php artisan key:generate
|
|
||||||
php artisan serve --host=0.0.0.0
|
|
||||||
- command: gp ports await 8080 && gp preview $(gp url 8000)
|
|
||||||
|
|
||||||
github:
|
|
||||||
prebuilds:
|
|
||||||
# enable for the master/default branch (defaults to true)
|
|
||||||
master: true
|
|
||||||
# enable for all branches in this repo (defaults to false)
|
|
||||||
branches: false
|
|
||||||
# enable for pull requests coming from this repo (defaults to true)
|
|
||||||
pullRequests: true
|
|
||||||
# add a check to pull requests (defaults to true)
|
|
||||||
addCheck: true
|
|
||||||
# add a "Review in Gitpod" button as a comment to pull requests (defaults to false)
|
|
||||||
addComment: false
|
|
||||||
|
|
||||||
vscode:
|
|
||||||
extensions:
|
|
||||||
- 'editorconfig.editorconfig'
|
|
||||||
- 'eamodio.gitlens'
|
|
||||||
- 'bmewburn.vscode-intelephense-client'
|
|
||||||
- 'esbenp.prettier-vscode'
|
|
||||||
- 'jpoissonnier.vscode-styled-components'
|
|
||||||
- 'mblode.twig-language-2'
|
|
||||||
- 'felixfbecker.php-debug'
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- port: 8080
|
|
||||||
visibility: public
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
yarn pretty-quick --staged
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$finder = PhpCsFixer\Finder::create()
|
|
||||||
->in('app')
|
|
||||||
->in('database')
|
|
||||||
->in('routes')
|
|
||||||
->in('tests');
|
|
||||||
|
|
||||||
$config = new PhpCsFixer\Config();
|
|
||||||
return $config->setRules([
|
|
||||||
'@Symfony' => true,
|
|
||||||
'align_multiline_comment' => true,
|
|
||||||
'array_syntax' => ['syntax' => 'short'],
|
|
||||||
'increment_style' => ['style' => 'post'],
|
|
||||||
'list_syntax' => ['syntax' => 'short'],
|
|
||||||
'yoda_style' => false,
|
|
||||||
'global_namespace_import' => [
|
|
||||||
'import_constants' => true,
|
|
||||||
'import_functions' => true,
|
|
||||||
'import_classes' => null,
|
|
||||||
],
|
|
||||||
])
|
|
||||||
->setFinder($finder);
|
|
||||||
21
.php_cs.dist
Normal file
21
.php_cs.dist
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$finder = PhpCsFixer\Finder::create()
|
||||||
|
->in('app')
|
||||||
|
->in('database')
|
||||||
|
->in('routes')
|
||||||
|
->in('tests')
|
||||||
|
;
|
||||||
|
|
||||||
|
return PhpCsFixer\Config::create()
|
||||||
|
->setRules([
|
||||||
|
'@Symfony' => true,
|
||||||
|
'align_multiline_comment' => true,
|
||||||
|
'array_syntax' => ['syntax' => 'short'],
|
||||||
|
'increment_style' => ['style' => 'post'],
|
||||||
|
'list_syntax' => ['syntax' => 'short'],
|
||||||
|
'yoda_style' => false,
|
||||||
|
|
||||||
|
])
|
||||||
|
->setFinder($finder)
|
||||||
|
;
|
||||||
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
|
|
@ -1,7 +1,12 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"editorconfig.editorconfig",
|
"editorconfig.editorconfig",
|
||||||
|
"eamodio.gitlens",
|
||||||
"bmewburn.vscode-intelephense-client",
|
"bmewburn.vscode-intelephense-client",
|
||||||
"esbenp.prettier-vscode"
|
"esbenp.prettier-vscode",
|
||||||
|
"jpoissonnier.vscode-styled-components",
|
||||||
|
"mblode.twig-language-2",
|
||||||
|
"firefox-devtools.vscode-firefox-debug",
|
||||||
|
"felixfbecker.php-debug"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
.vscode/launch.json
vendored
68
.vscode/launch.json
vendored
|
|
@ -1,34 +1,38 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Launch Jest Tests",
|
"name": "Launch Jest Tests",
|
||||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||||
"args": ["${file}"],
|
"args": ["${file}"],
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
"skipFiles": ["<node_internals>/**"]
|
"skipFiles": [
|
||||||
},
|
"<node_internals>/**"
|
||||||
{
|
]
|
||||||
"type": "php",
|
},
|
||||||
"request": "launch",
|
{
|
||||||
"name": "Launch with XDebug",
|
"type": "php",
|
||||||
"ignore": ["**/vendor/**/*.php"]
|
"request": "launch",
|
||||||
},
|
"name": "Launch with XDebug",
|
||||||
{
|
"ignore": [
|
||||||
"type": "firefox",
|
"**/vendor/**/*.php"
|
||||||
"request": "launch",
|
]
|
||||||
"reAttach": true,
|
},
|
||||||
"name": "Launch with Firefox Debugger",
|
{
|
||||||
"url": "http://localhost/",
|
"type": "firefox",
|
||||||
"webRoot": "${workspaceFolder}",
|
"request": "launch",
|
||||||
"pathMappings": [
|
"reAttach": true,
|
||||||
{
|
"name": "Launch with Firefox Debugger",
|
||||||
"url": "webpack:///",
|
"url": "http://localhost/",
|
||||||
"path": "${workspaceFolder}/"
|
"webRoot": "${workspaceFolder}",
|
||||||
}
|
"pathMappings": [
|
||||||
]
|
{
|
||||||
}
|
"url": "webpack:///",
|
||||||
]
|
"path": "${workspaceFolder}/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
|
||||||
}
|
|
||||||
82
Dockerfile
82
Dockerfile
|
|
@ -1,82 +0,0 @@
|
||||||
FROM composer:latest as vendor
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY composer.json composer.lock ./
|
|
||||||
|
|
||||||
RUN composer install \
|
|
||||||
--prefer-dist \
|
|
||||||
--no-dev \
|
|
||||||
--no-suggest \
|
|
||||||
--no-progress \
|
|
||||||
--no-autoloader \
|
|
||||||
--no-scripts \
|
|
||||||
--no-interaction \
|
|
||||||
--ignore-platform-reqs
|
|
||||||
|
|
||||||
FROM node:alpine as frontend
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY package.json yarn.lock ./
|
|
||||||
RUN yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY postcss.config.js tsconfig.build.json tsconfig.json webpack.config.ts ./
|
|
||||||
COPY tools/*Plugin.ts ./tools/
|
|
||||||
|
|
||||||
COPY resources ./resources
|
|
||||||
|
|
||||||
RUN yarn build && \
|
|
||||||
cp resources/assets/src/images/bg.webp public/app/ && \
|
|
||||||
cp resources/assets/src/images/favicon.ico public/app/ && \
|
|
||||||
# Strip unused files
|
|
||||||
rm -rf *.config.js *.config.ts tsconfig.* \
|
|
||||||
package.json yarn.lock node_modules/ \
|
|
||||||
resources/assets/ resources/lang resources/misc resources/misc/backgrounds/ \
|
|
||||||
tools/
|
|
||||||
|
|
||||||
FROM composer:latest as builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY . ./
|
|
||||||
|
|
||||||
COPY --from=vendor /app ./
|
|
||||||
COPY --from=frontend /app/public ./public
|
|
||||||
COPY --from=frontend /app/resources/views/assets ./resources/views/assets
|
|
||||||
|
|
||||||
RUN composer dump-autoload -o --no-dev -n && \
|
|
||||||
rm -rf *.config.js *.config.ts tsconfig.* \
|
|
||||||
package.json yarn.lock node_modules/ \
|
|
||||||
resources/assets/ resources/misc resources/misc/backgrounds/ \
|
|
||||||
tools/ && \
|
|
||||||
mv .env.example .env && \
|
|
||||||
php artisan key:generate && \
|
|
||||||
mv .env storage/ && \
|
|
||||||
ln -s storage/.env .env && \
|
|
||||||
touch storage/database.db && \
|
|
||||||
mkdir storage/plugins && \
|
|
||||||
sed 's/PLUGINS_DIR=null/PLUGINS_DIR=\/app\/storage\/plugins/' -i storage/.env && \
|
|
||||||
sed 's/DB_CONNECTION=mysql/DB_CONNECTION=sqlite/' -i storage/.env && \
|
|
||||||
sed 's/DB_DATABASE=blessingskin/DB_DATABASE=\/app\/storage\/database\.db/' -i storage/.env
|
|
||||||
|
|
||||||
FROM php:8-apache
|
|
||||||
|
|
||||||
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
|
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/install-php-extensions && \
|
|
||||||
install-php-extensions gd zip
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=builder /app ./
|
|
||||||
|
|
||||||
ENV APACHE_DOCUMENT_ROOT /app/public
|
|
||||||
RUN chown -R www-data:www-data . && \
|
|
||||||
sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf && \
|
|
||||||
sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf && \
|
|
||||||
a2enmod rewrite headers
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
VOLUME ["/app/storage"]
|
|
||||||
92
README-zh.md
92
README-zh.md
|
|
@ -1,92 +0,0 @@
|
||||||
- **简体中文**
|
|
||||||
- [English](./README.md)
|
|
||||||
|
|
||||||
<p align="center"><img src="https://media.githubusercontent.com/media/bs-community/logo/main/logo.png"></p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/bs-community/blessing-skin-server/CI?style=flat-square"></a>
|
|
||||||
<a href="https://codecov.io/gh/bs-community/blessing-skin-server"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/bs-community/blessing-skin-server?style=flat-square"></a>
|
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/releases"><img alt="GitHub release (latest SemVer including pre-releases)" src="https://img.shields.io/github/v/release/bs-community/blessing-skin-server?include_prereleases&style=flat-square"></a>
|
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/blob/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/bs-community/blessing-skin-server?style=flat-square"></a>
|
|
||||||
<a href="https://discord.com/invite/QAsyEyt"><img alt="Discord" src="https://discord.com/api/guilds/761226550921658380/widget.png"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
优雅的开源 Minecraft 皮肤站,现在,回应您的等待。
|
|
||||||
|
|
||||||
Blessing Skin 是一款能让您上传、管理和分享您的 Minecraft 皮肤和披风的 Web 应用程序。与修改游戏材质包不同的是,所有人都能在游戏中看到各自的皮肤和披风(当然,前提是玩家们要使用同一个皮肤站)。
|
|
||||||
|
|
||||||
Blessing Skin 是一个开源的 PHP 项目,这意味着您可以自由地在您的服务器上部署它。
|
|
||||||
|
|
||||||
## 特性
|
|
||||||
|
|
||||||
- 完整实现了一个皮肤站该有的功能
|
|
||||||
- 支持单用户多个角色
|
|
||||||
- 通过皮肤库来分享您的皮肤和披风!
|
|
||||||
- 易于使用
|
|
||||||
- 可视化的用户、角色、材质管理页面
|
|
||||||
- 详细的站点配置页面
|
|
||||||
- 多处 UI/UX 优化只为更好的用户体验
|
|
||||||
- 安全
|
|
||||||
- 支持多种安全密码 Hash 算法
|
|
||||||
- 注册可要求 Email 验证
|
|
||||||
- 防止恶意请求的积分系统
|
|
||||||
- 强大的可扩展性
|
|
||||||
- 多种多样的插件
|
|
||||||
- 支持与 Authme/Discuz 等程序的用户数据对接(插件)
|
|
||||||
- 支持自定义 Yggdrasil API 外置登录系统(插件)
|
|
||||||
|
|
||||||
## 环境要求
|
|
||||||
|
|
||||||
Blessing Skin 对您的服务器有一定的要求。在大多数情况下,下列所需的 PHP 扩展已经开启。
|
|
||||||
|
|
||||||
- 一台支持 URL 重写的主机,Nginx 或 Apache
|
|
||||||
- PHP >= 8.1.0
|
|
||||||
- 安装并启用如下 PHP 扩展:
|
|
||||||
- OpenSSL >= 1.1.1 (TLS 1.3)
|
|
||||||
- PDO
|
|
||||||
- Mbstring
|
|
||||||
- Tokenizer
|
|
||||||
- GD
|
|
||||||
- XML
|
|
||||||
- Ctype
|
|
||||||
- JSON
|
|
||||||
- fileinfo
|
|
||||||
- zip
|
|
||||||
- Imagick
|
|
||||||
|
|
||||||
## 快速使用
|
|
||||||
|
|
||||||
请参阅 [安装指南](https://blessing.netlify.app/setup.html)。
|
|
||||||
|
|
||||||
## 插件系统
|
|
||||||
|
|
||||||
Blessing Skin 提供了强大的插件系统,您可以通过添加多种多样的插件来为您的皮肤站添加功能。
|
|
||||||
|
|
||||||
## 自行构建
|
|
||||||
|
|
||||||
详情可阅读 [这里](https://blessing.netlify.app/build.html)。
|
|
||||||
|
|
||||||
> 您可以订阅我们的 Telegram 频道 [Blessing Skin News](https://t.me/blessing_skin_news) 来获取最新开发动态。当有新的 Commit 被推送时,我们的机器人将会在频道内发送一条消息来提示您能否拉取最新代码,以及拉取后应该做什么。
|
|
||||||
|
|
||||||
## 国际化(i18n)
|
|
||||||
|
|
||||||
Blessing Skin 可支持多种语言,当前支持英语、简体中文和西班牙语。
|
|
||||||
|
|
||||||
如果您愿意将您的翻译贡献出来,欢迎参与 [我们的 Crowdin 项目](https://crowdin.com/project/blessing-skin)。
|
|
||||||
|
|
||||||
## 问题报告
|
|
||||||
|
|
||||||
请参阅 [报告问题的正确姿势](https://blessing.netlify.app/report.html)。
|
|
||||||
|
|
||||||
## 相关链接
|
|
||||||
|
|
||||||
- [用户手册](https://blessing.netlify.app/)
|
|
||||||
- [插件开发文档](https://bs-plugin.netlify.app/)
|
|
||||||
|
|
||||||
## 版权
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016-present The Blessing Skin Team
|
|
||||||
|
|
||||||
程序原作者为 [@printempw](https://printempw.github.io/),转载请注明。
|
|
||||||
173
README.md
173
README.md
|
|
@ -1,48 +1,48 @@
|
||||||
- [简体中文](./README-zh.md)
|
- **简体中文**
|
||||||
- **English**
|
- [English](./README_EN.md)
|
||||||
|
|
||||||
<p align="center"><img src="https://media.githubusercontent.com/media/bs-community/logo/main/logo.png"></p>
|
<p align="center"><img src="https://img.blessing.studio/images/2017/01/01/bs-logo.png"></p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/bs-community/blessing-skin-server/CI.yml?branch=dev&style=flat-square"></a>
|
<a href="https://github.com/bs-community/blessing-skin-server/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/bs-community/blessing-skin-server/CI?style=flat-square"></a>
|
||||||
<a href="https://codecov.io/gh/bs-community/blessing-skin-server"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/bs-community/blessing-skin-server?style=flat-square"></a>
|
<a href="https://codecov.io/gh/bs-community/blessing-skin-server"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/bs-community/blessing-skin-server?style=flat-square"></a>
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/releases"><img alt="GitHub release (latest SemVer including pre-releases)" src="https://img.shields.io/github/v/release/bs-community/blessing-skin-server?include_prereleases&style=flat-square"></a>
|
<a href="https://github.com/bs-community/blessing-skin-server/releases"><img alt="GitHub release (latest SemVer including pre-releases)" src="https://img.shields.io/github/v/release/bs-community/blessing-skin-server?include_prereleases&style=flat-square"></a>
|
||||||
<a href="https://github.com/bs-community/blessing-skin-server/blob/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/bs-community/blessing-skin-server?style=flat-square"></a>
|
<a href="https://github.com/bs-community/blessing-skin-server/blob/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/bs-community/blessing-skin-server?style=flat-square"></a>
|
||||||
<a href="https://discord.com/invite/QAsyEyt"><img alt="Discord" src="https://discord.com/api/guilds/761226550921658380/widget.png"></a>
|
<a href="https://discord.com/invite/QAsyEyt"><img alt="Discord" src="https://discord.com/api/guilds/761226550921658380/widget.png"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Puzzled by losing your custom skins in Minecraft servers runing in offline mode? Now you can easily get them back with the help of Blessing Skin!
|
优雅的开源 Minecraft 皮肤站,现在,回应您的等待。
|
||||||
|
|
||||||
Blessing Skin is a web application where you can upload, manage and share your custom skins & capes! Unlike modifying a resource pack, everyone in the game will see the different skins of each other (of course they should register at the same website too).
|
Blessing Skin 是一款能让您上传、管理和分享您的 Minecraft 皮肤和披风的 Web 应用程序。与修改游戏材质包不同的是,所有人都能在游戏中看到各自的皮肤和披风(当然,前提是玩家们要使用同一个皮肤站)。
|
||||||
|
|
||||||
Blessing Skin is an open-source project written in PHP, which means you can deploy it freely on your own web server!
|
Blessing Skin 是一个开源的 PHP 项目,这意味着您可以自由地在您的服务器上部署它。
|
||||||
|
|
||||||
## Features
|
## 特性
|
||||||
|
|
||||||
- A fully functional skin hosting service
|
- 完整实现了一个皮肤站该有的功能
|
||||||
- Multiple player names can be owned by one user on the website
|
- 支持单用户多个角色
|
||||||
- Share your skins and capes online with skin library!
|
- 通过皮肤库来分享您的皮肤和披风!
|
||||||
- Easy-to-use
|
- 易于使用
|
||||||
- Visual page for user/player/texture management
|
- 可视化的用户、角色、材质管理页面
|
||||||
- Detailed option pages
|
- 详细的站点配置页面
|
||||||
- Many tweaks for a better UI/UX
|
- 多处 UI/UX 优化只为更好的用户体验
|
||||||
- Security
|
- 安全
|
||||||
- Support many secure password hash algorithms
|
- 支持多种安全密码 Hash 算法
|
||||||
- Email verification for registration
|
- 注册可要求 Email 验证
|
||||||
- Score system for preventing evil requests
|
- 防止恶意请求的积分系统
|
||||||
- Incredibly extensible
|
- 强大的可扩展性
|
||||||
- Plenty of plugins available
|
- 多种多样的插件
|
||||||
- Integration with Authme/Discuz (available as plugin)
|
- 支持与 Authme/Discuz 等程序的用户数据对接(插件)
|
||||||
- Support custom Yggdrasil API authentication (available as plugin)
|
- 支持自定义 Yggdrasil API 外置登录系统(插件)
|
||||||
|
|
||||||
## Requirements
|
## 环境要求
|
||||||
|
|
||||||
Blessing Skin has only a few system requirements. In most cases, these PHP extensions are already enabled.
|
Blessing Skin 对您的服务器有一定的要求。在大多数情况下,下列所需的 PHP 扩展已经开启。
|
||||||
|
|
||||||
- Web server with URL rewriting enabled (Nginx or Apache)
|
- 一台支持 URL 重写的主机,Nginx 或 Apache
|
||||||
- PHP >= 8.1.0
|
- PHP >= 7.2.5
|
||||||
- PHP Extensions
|
- 安装并启用如下 PHP 扩展:
|
||||||
- OpenSSL >= 1.1.1 (TLS 1.3)
|
- OpenSSL
|
||||||
- PDO
|
- PDO
|
||||||
- Mbstring
|
- Mbstring
|
||||||
- Tokenizer
|
- Tokenizer
|
||||||
|
|
@ -52,39 +52,120 @@ Blessing Skin has only a few system requirements. In most cases, these PHP exten
|
||||||
- JSON
|
- JSON
|
||||||
- fileinfo
|
- fileinfo
|
||||||
- zip
|
- zip
|
||||||
- Imagick
|
|
||||||
|
|
||||||
## Quick Install
|
## 快速使用
|
||||||
|
|
||||||
Please read [Installation Guide](https://blessing.netlify.app/en/setup.html).
|
请参阅 [安装指南](https://blessing.netlify.app/setup.html)。
|
||||||
|
|
||||||
## Plugin System
|
## 插件系统
|
||||||
|
|
||||||
Blessing Skin provides an elegant and powerful plugin system, and you can attach plenty of functions and customization to your site via installing plugins.
|
Blessing Skin 提供了强大的插件系统,您可以通过添加多种多样的插件来为您的皮肤站添加功能。
|
||||||
|
|
||||||
## Build From Source
|
## 支持并赞助 Blessing Skin
|
||||||
|
|
||||||
Please refer to [Manual Build](https://blessing.netlify.app/build.html).
|
如果您觉得这个软件对您很有帮助,欢迎通过赞助来支持开发!
|
||||||
|
|
||||||
## Internationalization
|
目前可在 [爱发电](https://afdian.net/@blessing-skin) 上赞助。
|
||||||
|
|
||||||
Blessing Skin supports multiple languages, while currently supporting English, Simplified Chinese and Spanish.
|
### Sponsors
|
||||||
|
|
||||||
If you are willing to contribute your translation, welcome to join [our Crowdin project](https://crowdin.com/project/blessing-skin).
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@ValiantShishu976400">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/178a08963a5e11e9addd52540025c377/avatar/ece9f089aaf2c2f83204a8de11697caf_w350_h350_s16.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
飒爽师叔
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@Luohuayu">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/66c740fad75011ea9fce52540025c377/avatar/870ee9ea29a1c179c435f1ad64aee79b_w640_h640_s52.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
落花雨
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
graytoowolf
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/e227ea708ac911eaa6c852540025c377/avatar/a56a7ceafa12e96ba6750e880f04b7e4_w1024_h1024_s883.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
mcha0
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@mengluorj">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/ffc6500452ed11e9994e52540025c377/avatar/ae9c5ec36b51e8314787cc19acf2d12e_w815_h815_s459.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
MengLuoRJ
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
## Report Bugs
|
### Backers
|
||||||
|
|
||||||
Read [FAQ](https://blessing.netlify.app/faq.html) and double check if your situation doesn't suit any case mentioned there before reporting.
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@mfwg6">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/18ad3338e58a11e9b29352540025c377/avatar/eb04b4b54975d0d229e77fbcd4220dc4_w1080_h1920_s541.jpg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
皮皮帕
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/68d07bf851fc11e98e5652540025c377/avatar/48538be153c8eebc3eb5cb6bc085cde9_w574_h574_s173.jpg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
dz_paji
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/b68f3a9aaef511e9826f52540025c377/avatar/03b244e92f9c4198672ce46e3fd7e100_w690_h690_s129.jpeg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
神奇威廉
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
When reporting a problem, please attach your log file (located at `storage/logs/laravel.log`) and the information of your server where the error occured on. You should also read this [guide](https://blessing.netlify.app/report.html) before reporting a problem.
|
## 自行构建
|
||||||
|
|
||||||
## Related Links
|
详情可阅读 [这里](https://blessing.netlify.com/build.html)。
|
||||||
|
|
||||||
- [User Manual](https://blessing.netlify.app/en/)
|
> 您可以订阅我们的 Telegram 频道 [Blessing Skin News](https://t.me/blessing_skin_news) 来获取最新开发动态。当有新的 Commit 被推送时,我们的机器人将会在频道内发送一条消息来提示您能否拉取最新代码,以及拉取后应该做什么。
|
||||||
- [Plugins Development Documentation](https://bs-plugin.netlify.app/)
|
|
||||||
|
|
||||||
## Copyright & License
|
## 国际化(i18n)
|
||||||
|
|
||||||
|
Blessing Skin 可支持多种语言,当前支持英语、简体中文和西班牙语。
|
||||||
|
|
||||||
|
如果您愿意将您的翻译贡献出来,欢迎参与 [我们的 Crowdin 项目](https://crowdin.com/project/blessing-skin)。
|
||||||
|
|
||||||
|
## 问题报告
|
||||||
|
|
||||||
|
请参阅 [报告问题的正确姿势](https://blessing.netlify.com/report.html)。
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- [用户手册](https://blessing.netlify.app/)
|
||||||
|
- [插件开发文档](https://bs-plugin.netlify.app/)
|
||||||
|
|
||||||
|
## 版权
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2016-present The Blessing Skin Team
|
Copyright (c) 2016-present The Blessing Skin Team
|
||||||
|
|
||||||
|
程序原作者为 [@printempw](https://blessing.studio/),转载请注明。
|
||||||
|
|
|
||||||
169
README_EN.md
Normal file
169
README_EN.md
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
- [简体中文](./README.md)
|
||||||
|
- **English**
|
||||||
|
|
||||||
|
<p align="center"><img src="https://img.blessing.studio/images/2017/01/01/bs-logo.png"></p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/bs-community/blessing-skin-server/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/bs-community/blessing-skin-server/CI?style=flat-square"></a>
|
||||||
|
<a href="https://codecov.io/gh/bs-community/blessing-skin-server"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/bs-community/blessing-skin-server?style=flat-square"></a>
|
||||||
|
<a href="https://github.com/bs-community/blessing-skin-server/releases"><img alt="GitHub release (latest SemVer including pre-releases)" src="https://img.shields.io/github/v/release/bs-community/blessing-skin-server?include_prereleases&style=flat-square"></a>
|
||||||
|
<a href="https://github.com/bs-community/blessing-skin-server/blob/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/bs-community/blessing-skin-server?style=flat-square"></a>
|
||||||
|
<a href="https://discord.com/invite/QAsyEyt"><img alt="Discord" src="https://discord.com/api/guilds/761226550921658380/widget.png"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Puzzled by losing your custom skins in Minecraft servers runing in offline mode? Now you can easily get them back with the help of Blessing Skin!
|
||||||
|
|
||||||
|
Blessing Skin is a web application where you can upload, manage and share your custom skins & capes! Unlike modifying a resource pack, everyone in the game will see the different skins of each other (of course they should register at the same website too).
|
||||||
|
|
||||||
|
Blessing Skin is an open-source project written in PHP, which means you can deploy it freely on your own web server!
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- A fully functional skin hosting service
|
||||||
|
- Multiple player names can be owned by one user on the website
|
||||||
|
- Share your skins and capes online with skin library!
|
||||||
|
- Easy-to-use
|
||||||
|
- Visual page for user/player/texture management
|
||||||
|
- Detailed option pages
|
||||||
|
- Many tweaks for a better UI/UX
|
||||||
|
- Security
|
||||||
|
- Support many secure password hash algorithms
|
||||||
|
- Email verification for registration
|
||||||
|
- Score system for preventing evil requests
|
||||||
|
- Incredibly extensible
|
||||||
|
- Plenty of plugins available
|
||||||
|
- Integration with Authme/CrazyLogin/Discuz (available as plugin)
|
||||||
|
- Support custom Yggdrasil API authentication (available as plugin)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Blessing Skin has only a few system requirements. In most cases, these PHP extensions are already enabled.
|
||||||
|
|
||||||
|
- Web server with URL rewriting enabled (Nginx or Apache)
|
||||||
|
- PHP >= 7.2.5
|
||||||
|
- PHP Extensions
|
||||||
|
- OpenSSL
|
||||||
|
- PDO
|
||||||
|
- Mbstring
|
||||||
|
- Tokenizer
|
||||||
|
- GD
|
||||||
|
- XML
|
||||||
|
- Ctype
|
||||||
|
- JSON
|
||||||
|
- fileinfo
|
||||||
|
- zip
|
||||||
|
|
||||||
|
## Quick Install
|
||||||
|
|
||||||
|
Please read [Installation Guide](https://blessing.netlify.app/en/setup.html).
|
||||||
|
|
||||||
|
## Plugin System
|
||||||
|
|
||||||
|
Blessing Skin provides an elegant and powerful plugin system, and you can attach plenty of functions and customization to your site via installing plugins.
|
||||||
|
|
||||||
|
## Supporting Blessing Skin
|
||||||
|
|
||||||
|
Welcome to sponsoring Blessing Skin if this software is useful for you!
|
||||||
|
|
||||||
|
Currently you can sponsor us via [爱发电](https://afdian.net/@blessing-skin).
|
||||||
|
|
||||||
|
### Sponsors
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@ValiantShishu976400">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/178a08963a5e11e9addd52540025c377/avatar/ece9f089aaf2c2f83204a8de11697caf_w350_h350_s16.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
飒爽师叔
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@Luohuayu">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/66c740fad75011ea9fce52540025c377/avatar/870ee9ea29a1c179c435f1ad64aee79b_w640_h640_s52.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
落花雨
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/default/avatar/avatar-purple.png" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
graytoowolf
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/e227ea708ac911eaa6c852540025c377/avatar/a56a7ceafa12e96ba6750e880f04b7e4_w1024_h1024_s883.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
mcha0
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@mengluorj">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/ffc6500452ed11e9994e52540025c377/avatar/ae9c5ec36b51e8314787cc19acf2d12e_w815_h815_s459.jpg" width="120" height="120">
|
||||||
|
<br>
|
||||||
|
MengLuoRJ
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
### Backers
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=center>
|
||||||
|
<a href="https://afdian.net/@mfwg6">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/18ad3338e58a11e9b29352540025c377/avatar/eb04b4b54975d0d229e77fbcd4220dc4_w1080_h1920_s541.jpg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
皮皮帕
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/68d07bf851fc11e98e5652540025c377/avatar/48538be153c8eebc3eb5cb6bc085cde9_w574_h574_s173.jpg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
dz_paji
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align=center>
|
||||||
|
<a href="">
|
||||||
|
<img src="https://pic1.afdiancdn.com/user/b68f3a9aaef511e9826f52540025c377/avatar/03b244e92f9c4198672ce46e3fd7e100_w690_h690_s129.jpeg" width="75" height="75">
|
||||||
|
<br>
|
||||||
|
神奇威廉
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Build From Source
|
||||||
|
|
||||||
|
Please refer to [Manual Build](https://blessing.netlify.app/build.html).
|
||||||
|
|
||||||
|
## Internationalization
|
||||||
|
|
||||||
|
Blessing Skin supports multiple languages, while currently supporting English, Simplified Chinese and Spanish.
|
||||||
|
|
||||||
|
If you are willing to contribute your translation, welcome to join [our Crowdin project](https://crowdin.com/project/blessing-skin).
|
||||||
|
|
||||||
|
## Report Bugs
|
||||||
|
|
||||||
|
Read [FAQ](https://blessing.netlify.app/faq.html) and double check if your situation doesn't suit any case mentioned there before reporting.
|
||||||
|
|
||||||
|
When reporting a problem, please attach your log file (located at `storage/logs/laravel.log`) and the information of your server where the error occured on. You should also read this [guide](https://blessing.netlify.app/report.html) before reporting a problem.
|
||||||
|
|
||||||
|
## Related Links
|
||||||
|
|
||||||
|
- [User Manual](https://blessing.netlify.app/en/)
|
||||||
|
- [Plugins Development Documentation](https://bs-plugin.netlify.app/)
|
||||||
|
|
||||||
|
## Copyright & License
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016-present The Blessing Skin Team
|
||||||
|
|
@ -25,6 +25,7 @@ class BsInstallCommand extends Command
|
||||||
if (!$this->getLaravel()->runningUnitTests()) {
|
if (!$this->getLaravel()->runningUnitTests()) {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
$this->call('key:generate');
|
$this->call('key:generate');
|
||||||
|
$this->call('jwt:secret', ['--no-interaction' => true]);
|
||||||
$this->call('passport:keys', ['--no-interaction' => true]);
|
$this->call('passport:keys', ['--no-interaction' => true]);
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,10 @@ class UpdateCommand extends Command
|
||||||
protected function procedures()
|
protected function procedures()
|
||||||
{
|
{
|
||||||
return collect([
|
return collect([
|
||||||
// this is just for testing
|
'0.0.1' => function () {
|
||||||
'0.0.1' => fn () => event('__0.0.1'),
|
// this is just for testing
|
||||||
|
event('__0.0.1');
|
||||||
|
},
|
||||||
'5.0.0' => function () {
|
'5.0.0' => function () {
|
||||||
if (option('home_pic_url') === './app/bg.jpg') {
|
if (option('home_pic_url') === './app/bg.jpg') {
|
||||||
option(['home_pic_url' => './app/bg.webp']);
|
option(['home_pic_url' => './app/bg.webp']);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ use App\Services\Plugin;
|
||||||
|
|
||||||
class PluginBootFailed extends Event
|
class PluginBootFailed extends Event
|
||||||
{
|
{
|
||||||
public Plugin $plugin;
|
/** @var Plugin */
|
||||||
|
public $plugin;
|
||||||
|
|
||||||
public function __construct(Plugin $plugin)
|
public function __construct(Plugin $plugin)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Passport\Exceptions\MissingScopeException;
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
|
|
@ -31,8 +30,6 @@ class Handler extends ExceptionHandler
|
||||||
if (Str::endsWith($model, 'Texture')) {
|
if (Str::endsWith($model, 'Texture')) {
|
||||||
$exception = new ModelNotFoundException(trans('skinlib.non-existent'));
|
$exception = new ModelNotFoundException(trans('skinlib.non-existent'));
|
||||||
}
|
}
|
||||||
} elseif ($exception instanceof MissingScopeException) {
|
|
||||||
return json($exception->getMessage(), 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::render($request, $exception);
|
return parent::render($request, $exception);
|
||||||
|
|
@ -44,8 +41,12 @@ class Handler extends ExceptionHandler
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'exception' => true,
|
'exception' => true,
|
||||||
'trace' => collect($e->getTrace())
|
'trace' => collect($e->getTrace())
|
||||||
->map(fn ($trace) => Arr::only($trace, ['file', 'line']))
|
->map(function ($trace) {
|
||||||
->filter(fn ($trace) => Arr::has($trace, 'file'))
|
return Arr::only($trace, ['file', 'line']);
|
||||||
|
})
|
||||||
|
->filter(function ($trace) {
|
||||||
|
return Arr::has($trace, 'file');
|
||||||
|
})
|
||||||
->map(function ($trace) {
|
->map(function ($trace) {
|
||||||
$trace['file'] = str_replace(base_path().DIRECTORY_SEPARATOR, '', $trace['file']);
|
$trace['file'] = str_replace(base_path().DIRECTORY_SEPARATOR, '', $trace['file']);
|
||||||
|
|
||||||
|
|
@ -53,9 +54,8 @@ class Handler extends ExceptionHandler
|
||||||
})
|
})
|
||||||
->filter(function ($trace) {
|
->filter(function ($trace) {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
$isFromPlugins = !app()->runningUnitTests()
|
$isFromPlugins = !app()->runningUnitTests() &&
|
||||||
&& Str::contains($trace['file'], resolve('plugins')->getPluginsDirs()->all());
|
Str::contains($trace['file'], resolve('plugins')->getPluginsDirs()->all());
|
||||||
|
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
return Str::startsWith($trace['file'], 'app') || $isFromPlugins;
|
return Str::startsWith($trace['file'], 'app') || $isFromPlugins;
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -47,22 +47,32 @@ class AdminController extends Controller
|
||||||
|
|
||||||
public function chartData()
|
public function chartData()
|
||||||
{
|
{
|
||||||
$xAxis = Collection::times(31, fn ($i) => Carbon::today()->subDays(31 - $i)->isoFormat('l'));
|
$xAxis = Collection::times(31, function ($i) {
|
||||||
|
return Carbon::today()->subDays(31 - $i)->format('m-d');
|
||||||
|
});
|
||||||
|
|
||||||
$oneMonthAgo = Carbon::today()->subMonth();
|
$oneMonthAgo = Carbon::today()->subMonth();
|
||||||
|
|
||||||
$grouping = fn ($field) => fn ($item) => Carbon::parse($item->$field)->isoFormat('l');
|
$grouping = function ($field) {
|
||||||
$mapping = fn ($item) => count($item);
|
return function ($item) use ($field) {
|
||||||
$aligning = fn ($data) => fn ($day) => $data->get($day) ?? 0;
|
return substr($item->$field, 5, 5);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
$mapping = function ($item) {
|
||||||
|
return count($item);
|
||||||
|
};
|
||||||
|
$aligning = function ($data) {
|
||||||
|
return function ($day) use ($data) {
|
||||||
|
return $data->get($day) ?? 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/** @var Collection */
|
|
||||||
$userRegistration = User::where('register_at', '>=', $oneMonthAgo)
|
$userRegistration = User::where('register_at', '>=', $oneMonthAgo)
|
||||||
->select('register_at')
|
->select('register_at')
|
||||||
->get()
|
->get()
|
||||||
->groupBy($grouping('register_at'))
|
->groupBy($grouping('register_at'))
|
||||||
->map($mapping);
|
->map($mapping);
|
||||||
|
|
||||||
/** @var Collection */
|
|
||||||
$textureUploads = Texture::where('upload_at', '>=', $oneMonthAgo)
|
$textureUploads = Texture::where('upload_at', '>=', $oneMonthAgo)
|
||||||
->select('upload_at')
|
->select('upload_at')
|
||||||
->get()
|
->get()
|
||||||
|
|
@ -86,7 +96,7 @@ class AdminController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
PluginManager $plugins,
|
PluginManager $plugins,
|
||||||
Filesystem $filesystem,
|
Filesystem $filesystem,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
$db = config('database.connections.'.config('database.default'));
|
$db = config('database.connections.'.config('database.default'));
|
||||||
$dbType = Arr::get([
|
$dbType = Arr::get([
|
||||||
|
|
@ -95,9 +105,9 @@ class AdminController extends Controller
|
||||||
'pgsql' => 'PostgreSQL',
|
'pgsql' => 'PostgreSQL',
|
||||||
], config('database.default'), '');
|
], config('database.default'), '');
|
||||||
|
|
||||||
$enabledPlugins = $plugins->getEnabledPlugins()->map(fn ($plugin) => [
|
$enabledPlugins = $plugins->getEnabledPlugins()->map(function ($plugin) {
|
||||||
'title' => trans($plugin->title), 'version' => $plugin->version,
|
return ['title' => trans($plugin->title), 'version' => $plugin->version];
|
||||||
]);
|
});
|
||||||
|
|
||||||
if ($filesystem->exists(base_path('.git'))) {
|
if ($filesystem->exists(base_path('.git'))) {
|
||||||
$process = new \Symfony\Component\Process\Process(
|
$process = new \Symfony\Component\Process\Process(
|
||||||
|
|
@ -127,7 +137,11 @@ class AdminController extends Controller
|
||||||
'version' => config('app.version'),
|
'version' => config('app.version'),
|
||||||
'env' => config('app.env'),
|
'env' => config('app.env'),
|
||||||
'debug' => config('app.debug') ? trans('general.yes') : trans('general.no'),
|
'debug' => config('app.debug') ? trans('general.yes') : trans('general.no'),
|
||||||
'commit' => Str::limit($commit ?? '', 16, ''),
|
'commit' => Str::limit(
|
||||||
|
$commit ?? resolve(\App\Services\Webpack::class)->commit,
|
||||||
|
16,
|
||||||
|
''
|
||||||
|
),
|
||||||
'laravel' => app()->version(),
|
'laravel' => app()->version(),
|
||||||
],
|
],
|
||||||
'server' => [
|
'server' => [
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@ use App\Mail\ForgotPassword;
|
||||||
use App\Models\Player;
|
use App\Models\Player;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Rules;
|
use App\Rules;
|
||||||
|
use Auth;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Blessing\Rejection;
|
use Blessing\Rejection;
|
||||||
|
use Cache;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Mail;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Session;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use URL;
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Vectorface\Whip\Whip;
|
use Vectorface\Whip\Whip;
|
||||||
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
|
|
@ -50,7 +50,7 @@ class AuthController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Rules\Captcha $captcha,
|
Rules\Captcha $captcha,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'identification' => 'required',
|
'identification' => 'required',
|
||||||
|
|
@ -151,7 +151,7 @@ class AuthController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Rules\Captcha $captcha,
|
Rules\Captcha $captcha,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
$can = $filter->apply('can_register', null);
|
$can = $filter->apply('can_register', null);
|
||||||
if ($can instanceof Rejection) {
|
if ($can instanceof Rejection) {
|
||||||
|
|
@ -176,8 +176,8 @@ class AuthController extends Controller
|
||||||
$dispatcher->dispatch('auth.registration.attempt', [$data]);
|
$dispatcher->dispatch('auth.registration.attempt', [$data]);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
option('register_with_player_name')
|
option('register_with_player_name') &&
|
||||||
&& Player::where('name', $playerName)->count() > 0
|
Player::where('name', $playerName)->count() > 0
|
||||||
) {
|
) {
|
||||||
return json(trans('user.player.add.repeated'), 1);
|
return json(trans('user.player.add.repeated'), 1);
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +248,7 @@ class AuthController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Rules\Captcha $captcha,
|
Rules\Captcha $captcha,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
|
|
@ -370,4 +370,26 @@ class AuthController extends Controller
|
||||||
|
|
||||||
return redirect()->route('user.home');
|
return redirect()->route('user.home');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function jwtLogin(Request $request)
|
||||||
|
{
|
||||||
|
$token = Auth::guard('jwt')->attempt([
|
||||||
|
'email' => $request->input('email'),
|
||||||
|
'password' => $request->input('password'),
|
||||||
|
]) ?: '';
|
||||||
|
|
||||||
|
return json(compact('token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jwtLogout()
|
||||||
|
{
|
||||||
|
Auth::guard('jwt')->logout();
|
||||||
|
|
||||||
|
return response('', 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jwtRefresh()
|
||||||
|
{
|
||||||
|
return json(['token' => Auth::guard('jwt')->refresh()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Texture;
|
use App\Models\Texture;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Auth;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Blessing\Rejection;
|
use Blessing\Rejection;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class ClosetController extends Controller
|
class ClosetController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -51,16 +51,14 @@ class ClosetController extends Controller
|
||||||
|
|
||||||
return $user
|
return $user
|
||||||
->closet()
|
->closet()
|
||||||
->when(
|
->when($category === 'cape', function (Builder $query) {
|
||||||
$category === 'cape',
|
return $query->where('type', 'cape');
|
||||||
fn (Builder $query) => $query->where('type', 'cape'),
|
}, function (Builder $query) {
|
||||||
fn (Builder $query) => $query->whereIn('type', ['steve', 'alex']),
|
return $query->whereIn('type', ['steve', 'alex']);
|
||||||
)
|
})
|
||||||
->when(
|
->when($request->input('q'), function (Builder $query, $search) {
|
||||||
$request->input('q'),
|
return $query->like('item_name', $search);
|
||||||
fn (Builder $query, $search) => $query->like('item_name', $search)
|
})
|
||||||
)
|
|
||||||
->orderBy('texture_tid', 'DESC')
|
|
||||||
->paginate((int) $request->input('perPage', 6));
|
->paginate((int) $request->input('perPage', 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,7 +73,7 @@ class ClosetController extends Controller
|
||||||
public function add(
|
public function add(
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
['tid' => $tid, 'name' => $name] = $request->validate([
|
['tid' => $tid, 'name' => $name] = $request->validate([
|
||||||
'tid' => 'required|integer',
|
'tid' => 'required|integer',
|
||||||
|
|
@ -132,7 +130,7 @@ class ClosetController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
$tid,
|
$tid
|
||||||
) {
|
) {
|
||||||
['name' => $name] = $request->validate(['name' => 'required']);
|
['name' => $name] = $request->validate(['name' => 'required']);
|
||||||
/** @var User */
|
/** @var User */
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,8 @@ class ClosetManagementController extends Controller
|
||||||
public function add(Request $request, Dispatcher $dispatcher, User $user)
|
public function add(Request $request, Dispatcher $dispatcher, User $user)
|
||||||
{
|
{
|
||||||
$tid = $request->input('tid');
|
$tid = $request->input('tid');
|
||||||
$texture = Texture::find($tid);
|
/** @var Texture */
|
||||||
if (!$texture) {
|
$texture = Texture::findOrFail($tid);
|
||||||
return json(trans('user.closet.add.not-found'), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user->closet()->where('tid', $request->tid)->count() > 0) {
|
|
||||||
return json(trans('user.closet.add.repeated'), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = $texture->name;
|
$name = $texture->name;
|
||||||
|
|
||||||
$dispatcher->dispatch('closet.adding', [$tid, $name, $user]);
|
$dispatcher->dispatch('closet.adding', [$tid, $name, $user]);
|
||||||
|
|
@ -42,14 +35,10 @@ class ClosetManagementController extends Controller
|
||||||
$tid = $request->input('tid');
|
$tid = $request->input('tid');
|
||||||
$dispatcher->dispatch('closet.removing', [$tid, $user]);
|
$dispatcher->dispatch('closet.removing', [$tid, $user]);
|
||||||
|
|
||||||
$item = $user->closet()->find($tid);
|
/** @var Texture */
|
||||||
if (empty($item)) {
|
$texture = Texture::findOrFail($tid);
|
||||||
return json(trans('user.closet.remove.non-existent'), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->closet()->detach($tid);
|
$user->closet()->detach($texture->tid);
|
||||||
|
|
||||||
$texture = Texture::find($tid);
|
|
||||||
|
|
||||||
$dispatcher->dispatch('closet.removed', [$texture, $user]);
|
$dispatcher->dispatch('closet.removed', [$texture, $user]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Services\Webpack;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index(Webpack $webpack)
|
||||||
{
|
{
|
||||||
return view('home')
|
return view('home')
|
||||||
->with('user', auth()->user())
|
->with('user', auth()->user())
|
||||||
|
|
@ -14,7 +15,13 @@ class HomeController extends Controller
|
||||||
->with('transparent_navbar', (bool) option('transparent_navbar', false))
|
->with('transparent_navbar', (bool) option('transparent_navbar', false))
|
||||||
->with('fixed_bg', option('fixed_bg'))
|
->with('fixed_bg', option('fixed_bg'))
|
||||||
->with('hide_intro', option('hide_intro'))
|
->with('hide_intro', option('hide_intro'))
|
||||||
->with('home_pic_url', option('home_pic_url') ?: config('options.home_pic_url'));
|
->with('home_pic_url', option('home_pic_url') ?: config('options.home_pic_url'))
|
||||||
|
->with('home_page_css', $webpack->url('home.css'))
|
||||||
|
->with(
|
||||||
|
'home_page_css_loader',
|
||||||
|
config('app.asset.env') === 'development' ? $webpack->url('home.js') : null
|
||||||
|
)
|
||||||
|
->with('app_js', $webpack->url('app.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apiRoot()
|
public function apiRoot()
|
||||||
|
|
@ -25,8 +32,6 @@ class HomeController extends Controller
|
||||||
'Powered by Blessing Skin Server.',
|
'Powered by Blessing Skin Server.',
|
||||||
'Proudly powered by Blessing Skin Server.',
|
'Proudly powered by Blessing Skin Server.',
|
||||||
'由 Blessing Skin Server 强力驱动。',
|
'由 Blessing Skin Server 强力驱动。',
|
||||||
'采用 Blessing Skin Server 搭建。',
|
|
||||||
'使用 Blessing Skin Server 稳定运行。',
|
|
||||||
'自豪地采用 Blessing Skin Server。',
|
'自豪地采用 Blessing Skin Server。',
|
||||||
],
|
],
|
||||||
option_localized('copyright_prefer', 0)
|
option_localized('copyright_prefer', 0)
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,12 @@ class NotificationsController extends Controller
|
||||||
|
|
||||||
public function all()
|
public function all()
|
||||||
{
|
{
|
||||||
return auth()->user()
|
return auth()->user()->unreadNotifications->map(function ($notification) {
|
||||||
->unreadNotifications
|
return [
|
||||||
->map(fn ($notification) => [
|
|
||||||
'id' => $notification->id,
|
'id' => $notification->id,
|
||||||
'title' => $notification->data['title'],
|
'title' => $notification->data['title'],
|
||||||
]);
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read($id)
|
public function read($id)
|
||||||
|
|
@ -58,14 +58,16 @@ class NotificationsController extends Controller
|
||||||
$notification = auth()
|
$notification = auth()
|
||||||
->user()
|
->user()
|
||||||
->unreadNotifications
|
->unreadNotifications
|
||||||
->first(fn ($notification) => $notification->id === $id);
|
->first(function ($notification) use ($id) {
|
||||||
|
return $notification->id === $id;
|
||||||
|
});
|
||||||
$notification->markAsRead();
|
$notification->markAsRead();
|
||||||
|
|
||||||
$converter = new GithubFlavoredMarkdownConverter();
|
$converter = new GithubFlavoredMarkdownConverter();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'title' => $notification->data['title'],
|
'title' => $notification->data['title'],
|
||||||
'content' => $converter->convertToHtml($notification->data['content'] ?? '')->getContent(),
|
'content' => $converter->convertToHtml($notification->data['content']),
|
||||||
'time' => $notification->created_at->toDateTimeString(),
|
'time' => $notification->created_at->toDateTimeString(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,7 @@ class OptionsController extends Controller
|
||||||
->option('1', 'Powered by Blessing Skin Server.')
|
->option('1', 'Powered by Blessing Skin Server.')
|
||||||
->option('2', 'Proudly powered by Blessing Skin Server.')
|
->option('2', 'Proudly powered by Blessing Skin Server.')
|
||||||
->option('3', '由 Blessing Skin Server 强力驱动。')
|
->option('3', '由 Blessing Skin Server 强力驱动。')
|
||||||
->option('4', '采用 Blessing Skin Server 搭建。')
|
->option('4', '自豪地采用 Blessing Skin Server。')
|
||||||
->option('5', '使用 Blessing Skin Server 稳定运行。')
|
|
||||||
->option('6', '自豪地采用 Blessing Skin Server。')
|
|
||||||
->description();
|
->description();
|
||||||
|
|
||||||
$form->textarea('copyright_text')->rows(6)->description();
|
$form->textarea('copyright_text')->rows(6)->description();
|
||||||
|
|
@ -163,14 +161,9 @@ class OptionsController extends Controller
|
||||||
->text('max_upload_file_size')->addon('KB')
|
->text('max_upload_file_size')->addon('KB')
|
||||||
->hint(trans('options.general.max_upload_file_size.hint', ['size' => ini_get('upload_max_filesize')]));
|
->hint(trans('options.general.max_upload_file_size.hint', ['size' => ini_get('upload_max_filesize')]));
|
||||||
|
|
||||||
$form->group('max_texture_width')
|
|
||||||
->text('max_texture_width')->addon('px')
|
|
||||||
->hint(trans('options.general.max_texture_width.hint'));
|
|
||||||
|
|
||||||
$form->select('player_name_rule')
|
$form->select('player_name_rule')
|
||||||
->option('official', trans('options.general.player_name_rule.official'))
|
->option('official', trans('options.general.player_name_rule.official'))
|
||||||
->option('cjk', trans('options.general.player_name_rule.cjk'))
|
->option('cjk', trans('options.general.player_name_rule.cjk'))
|
||||||
->option('utf8', trans('options.general.player_name_rule.utf8'))
|
|
||||||
->option('custom', trans('options.general.player_name_rule.custom'));
|
->option('custom', trans('options.general.player_name_rule.custom'));
|
||||||
|
|
||||||
$form->text('custom_player_name_regexp')->hint()->placeholder();
|
$form->text('custom_player_name_regexp')->hint()->placeholder();
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ use App\Models\Player;
|
||||||
use App\Models\Texture;
|
use App\Models\Texture;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Rules;
|
use App\Rules;
|
||||||
|
use Auth;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Blessing\Rejection;
|
use Blessing\Rejection;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class PlayerController extends Controller
|
class PlayerController extends Controller
|
||||||
|
|
@ -124,7 +124,7 @@ class PlayerController extends Controller
|
||||||
public function delete(
|
public function delete(
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Player $player,
|
Player $player
|
||||||
) {
|
) {
|
||||||
/** @var User */
|
/** @var User */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
@ -157,7 +157,7 @@ class PlayerController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Player $player,
|
Player $player
|
||||||
) {
|
) {
|
||||||
$name = $request->validate([
|
$name = $request->validate([
|
||||||
'name' => [
|
'name' => [
|
||||||
|
|
@ -194,7 +194,7 @@ class PlayerController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Player $player,
|
Player $player
|
||||||
) {
|
) {
|
||||||
/** @var User */
|
/** @var User */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
@ -234,7 +234,7 @@ class PlayerController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Player $player,
|
Player $player
|
||||||
) {
|
) {
|
||||||
$types = $request->input('type', []);
|
$types = $request->input('type', []);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ class PlayersManagementController extends Controller
|
||||||
$currentUser = $request->user();
|
$currentUser = $request->user();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$owner->uid !== $currentUser->uid
|
$owner->uid !== $currentUser->uid &&
|
||||||
&& $owner->permission >= $currentUser->permission
|
$owner->permission >= $currentUser->permission
|
||||||
) {
|
) {
|
||||||
return json(trans('admin.players.no-permission'), 1)
|
return json(trans('admin.players.no-permission'), 1)
|
||||||
->setStatusCode(403);
|
->setStatusCode(403);
|
||||||
|
|
@ -44,7 +44,7 @@ class PlayersManagementController extends Controller
|
||||||
public function name(
|
public function name(
|
||||||
Player $player,
|
Player $player,
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$name = $request->validate([
|
$name = $request->validate([
|
||||||
'player_name' => [
|
'player_name' => [
|
||||||
|
|
@ -70,7 +70,7 @@ class PlayersManagementController extends Controller
|
||||||
public function owner(
|
public function owner(
|
||||||
Player $player,
|
Player $player,
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$uid = $request->validate(['uid' => 'required|integer'])['uid'];
|
$uid = $request->validate(['uid' => 'required|integer'])['uid'];
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ class PlayersManagementController extends Controller
|
||||||
public function texture(
|
public function texture(
|
||||||
Player $player,
|
Player $player,
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'tid' => 'required|integer',
|
'tid' => 'required|integer',
|
||||||
|
|
@ -123,7 +123,7 @@ class PlayersManagementController extends Controller
|
||||||
|
|
||||||
public function delete(
|
public function delete(
|
||||||
Player $player,
|
Player $player,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$dispatcher->dispatch('player.deleting', [$player]);
|
$dispatcher->dispatch('player.deleting', [$player]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class ReportController extends Controller
|
||||||
public function review(
|
public function review(
|
||||||
Report $report,
|
Report $report,
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'action' => ['required', Rule::in(['delete', 'ban', 'reject'])],
|
'action' => ['required', Rule::in(['delete', 'ban', 'reject'])],
|
||||||
|
|
@ -88,9 +88,9 @@ class ReportController extends Controller
|
||||||
|
|
||||||
if ($action == 'reject') {
|
if ($action == 'reject') {
|
||||||
if (
|
if (
|
||||||
$report->informer
|
$report->informer &&
|
||||||
&& ($score = option('reporter_score_modification', 0)) > 0
|
($score = option('reporter_score_modification', 0)) > 0 &&
|
||||||
&& $report->status == Report::PENDING
|
$report->status == Report::PENDING
|
||||||
) {
|
) {
|
||||||
$report->informer->score -= $score;
|
$report->informer->score -= $score;
|
||||||
$report->informer->save();
|
$report->informer->save();
|
||||||
|
|
@ -150,11 +150,7 @@ class ReportController extends Controller
|
||||||
|
|
||||||
public static function returnScore($report)
|
public static function returnScore($report)
|
||||||
{
|
{
|
||||||
if (
|
if ($report->status == Report::PENDING && ($score = option('reporter_score_modification', 0)) < 0) {
|
||||||
$report->status == Report::PENDING
|
|
||||||
&& ($score = option('reporter_score_modification', 0)) < 0
|
|
||||||
&& $report->informer
|
|
||||||
) {
|
|
||||||
$report->informer->score -= $score;
|
$report->informer->score -= $score;
|
||||||
$report->informer->save();
|
$report->informer->save();
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +158,7 @@ class ReportController extends Controller
|
||||||
|
|
||||||
public static function giveAward($report)
|
public static function giveAward($report)
|
||||||
{
|
{
|
||||||
if ($report->status == Report::PENDING && $report->informer) {
|
if ($report->status == Report::PENDING) {
|
||||||
$report->informer->score += option('reporter_reward_score', 0);
|
$report->informer->score += option('reporter_reward_score', 0);
|
||||||
$report->informer->save();
|
$report->informer->save();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class SetupController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Filesystem $filesystem,
|
Filesystem $filesystem,
|
||||||
Connection $connection,
|
Connection $connection,
|
||||||
DatabaseManager $manager,
|
DatabaseManager $manager
|
||||||
) {
|
) {
|
||||||
if ($request->isMethod('get')) {
|
if ($request->isMethod('get')) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -52,7 +52,7 @@ class SetupController extends Controller
|
||||||
try {
|
try {
|
||||||
$manager->connection('temp')->getPdo();
|
$manager->connection('temp')->getPdo();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$msg = $e->getMessage();
|
$msg = iconv('gbk', 'utf-8', $e->getMessage());
|
||||||
$type = Arr::get([
|
$type = Arr::get([
|
||||||
'mysql' => 'MySQL/MariaDB',
|
'mysql' => 'MySQL/MariaDB',
|
||||||
'sqlite' => 'SQLite',
|
'sqlite' => 'SQLite',
|
||||||
|
|
@ -112,6 +112,7 @@ class SetupController extends Controller
|
||||||
'site_name' => 'required',
|
'site_name' => 'required',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$artisan->call('jwt:secret', ['--no-interaction' => true]);
|
||||||
$artisan->call('passport:keys', ['--no-interaction' => true]);
|
$artisan->call('passport:keys', ['--no-interaction' => true]);
|
||||||
|
|
||||||
// Create tables
|
// Create tables
|
||||||
|
|
@ -121,7 +122,7 @@ class SetupController extends Controller
|
||||||
'database/migrations',
|
'database/migrations',
|
||||||
'vendor/laravel/passport/database/migrations',
|
'vendor/laravel/passport/database/migrations',
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$siteUrl = url('/');
|
$siteUrl = url('/');
|
||||||
if (Str::endsWith($siteUrl, '/index.php')) {
|
if (Str::endsWith($siteUrl, '/index.php')) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Texture;
|
use App\Models\Texture;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Auth;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Blessing\Rejection;
|
use Blessing\Rejection;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
|
|
@ -11,12 +12,10 @@ use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Filesystem\FilesystemAdapter;
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Intervention\Image\Facades\Image;
|
|
||||||
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
class SkinlibController extends Controller
|
class SkinlibController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -69,13 +68,17 @@ class SkinlibController extends Controller
|
||||||
$sortBy = $sort == 'time' ? 'upload_at' : $sort;
|
$sortBy = $sort == 'time' ? 'upload_at' : $sort;
|
||||||
|
|
||||||
return Texture::orderBy($sortBy, 'desc')
|
return Texture::orderBy($sortBy, 'desc')
|
||||||
->when(
|
->when($type === 'skin', function (Builder $query) {
|
||||||
$type === 'skin',
|
return $query->whereIn('type', ['steve', 'alex']);
|
||||||
fn (Builder $query) => $query->whereIn('type', ['steve', 'alex']),
|
}, function (Builder $query) use ($type) {
|
||||||
fn (Builder $query) => $query->where('type', $type),
|
return $query->where('type', $type);
|
||||||
)
|
})
|
||||||
->when($keyword, fn (Builder $query, $keyword) => $query->like('name', $keyword))
|
->when($keyword, function (Builder $query, $keyword) {
|
||||||
->when($uploader, fn (Builder $query, $uploader) => $query->where('uploader', $uploader))
|
return $query->like('name', $keyword);
|
||||||
|
})
|
||||||
|
->when($uploader, function (Builder $query, $uploader) {
|
||||||
|
return $query->where('uploader', $uploader);
|
||||||
|
})
|
||||||
->when($user, function (Builder $query, User $user) {
|
->when($user, function (Builder $query, User $user) {
|
||||||
if (!$user->isAdmin()) {
|
if (!$user->isAdmin()) {
|
||||||
// use closure-style `where` clause to lift up SQL priority
|
// use closure-style `where` clause to lift up SQL priority
|
||||||
|
|
@ -135,7 +138,7 @@ class SkinlibController extends Controller
|
||||||
->with('texture', $texture)
|
->with('texture', $texture)
|
||||||
->with('grid', $grid)
|
->with('grid', $grid)
|
||||||
->with('extra', [
|
->with('extra', [
|
||||||
'download' => (bool) option('allow_downloading_texture'),
|
'download' => option('allow_downloading_texture'),
|
||||||
'currentUid' => $user ? $user->uid : 0,
|
'currentUid' => $user ? $user->uid : 0,
|
||||||
'admin' => $user && $user->isAdmin(),
|
'admin' => $user && $user->isAdmin(),
|
||||||
'inCloset' => $user && $user->closet()->where('tid', $texture->tid)->count() > 0,
|
'inCloset' => $user && $user->closet()->where('tid', $texture->tid)->count() > 0,
|
||||||
|
|
@ -183,14 +186,14 @@ class SkinlibController extends Controller
|
||||||
'scorePrivate' => (int) option('private_score_per_storage'),
|
'scorePrivate' => (int) option('private_score_per_storage'),
|
||||||
'closetItemCost' => (int) option('score_per_closet_item'),
|
'closetItemCost' => (int) option('score_per_closet_item'),
|
||||||
'award' => (int) option('score_award_per_texture'),
|
'award' => (int) option('score_award_per_texture'),
|
||||||
'contentPolicy' => $converter->convertToHtml(option_localized('content_policy'))->getContent(),
|
'contentPolicy' => $converter->convertToHtml(option_localized('content_policy')),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleUpload(
|
public function handleUpload(
|
||||||
Request $request,
|
Request $request,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher
|
||||||
) {
|
) {
|
||||||
$file = $request->file('file');
|
$file = $request->file('file');
|
||||||
if ($file && !$file->isValid()) {
|
if ($file && !$file->isValid()) {
|
||||||
|
|
@ -220,36 +223,24 @@ class SkinlibController extends Controller
|
||||||
|
|
||||||
$type = $data['type'];
|
$type = $data['type'];
|
||||||
$size = getimagesize($file);
|
$size = getimagesize($file);
|
||||||
|
|
||||||
$maxWidth = option('max_texture_width', 8192);
|
|
||||||
if ($size[0] > $maxWidth) {
|
|
||||||
$message = trans('skinlib.upload.too-wide', [
|
|
||||||
'width' => $size[0],
|
|
||||||
'maxWidth' => $maxWidth,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return json($message, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($size[0] % 64 != 0 || $size[1] % 32 != 0) {
|
|
||||||
$message = trans('skinlib.upload.invalid-size', [
|
|
||||||
'type' => $type === 'cape' ? trans('general.cape') : trans('general.skin'),
|
|
||||||
'width' => $size[0],
|
|
||||||
'height' => $size[1],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return json($message, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$ratio = $size[0] / $size[1];
|
$ratio = $size[0] / $size[1];
|
||||||
if ($type == 'steve' || $type == 'alex') {
|
if ($type == 'steve' || $type == 'alex') {
|
||||||
if ($ratio != 2 && $ratio != 1 || $type === 'alex' && $ratio === 2) {
|
if ($ratio != 2 && $ratio != 1) {
|
||||||
$message = trans('skinlib.upload.invalid-size', [
|
$message = trans('skinlib.upload.invalid-size', [
|
||||||
'type' => trans('general.skin'),
|
'type' => trans('general.skin'),
|
||||||
'width' => $size[0],
|
'width' => $size[0],
|
||||||
'height' => $size[1],
|
'height' => $size[1],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
return json($message, 1);
|
||||||
|
}
|
||||||
|
if ($size[0] % 64 != 0 || $size[1] % 32 != 0) {
|
||||||
|
$message = trans('skinlib.upload.invalid-hd-skin', [
|
||||||
|
'type' => trans('general.skin'),
|
||||||
|
'width' => $size[0],
|
||||||
|
'height' => $size[1],
|
||||||
|
]);
|
||||||
|
|
||||||
return json($message, 1);
|
return json($message, 1);
|
||||||
}
|
}
|
||||||
} elseif ($type == 'cape') {
|
} elseif ($type == 'cape') {
|
||||||
|
|
@ -264,25 +255,17 @@ class SkinlibController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$image = Image::make($file);
|
$hash = hash_file('sha256', $file);
|
||||||
$imagick = $image->getCore();
|
$hash = $filter->apply('uploaded_texture_hash', $hash, [$file]);
|
||||||
$imagick->setOption('png:compression-filter', '0');
|
|
||||||
$imagick->setOption('png:compression-level', '9');
|
|
||||||
$imagick->setOption('png:compression-strategy', '0');
|
|
||||||
$imagick->setOption('png:exclude-chunk', 'all');
|
|
||||||
$imagick->stripImage();
|
|
||||||
$sanitized = $image->encode('png')->getEncoded();
|
|
||||||
|
|
||||||
$hash = hash('sha256', $image->encoded);
|
|
||||||
$hash = $filter->apply('uploaded_texture_hash', $hash, [$image]);
|
|
||||||
|
|
||||||
/** @var User */
|
/** @var User */
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
$duplicated = Texture::where('hash', $hash)
|
$duplicated = Texture::where('hash', $hash)
|
||||||
->where(
|
->where(function ($query) use ($user) {
|
||||||
fn (Builder $query) => $query->where('public', true)->orWhere('uploader', $user->uid)
|
return $query->where('public', true)
|
||||||
)
|
->orWhere('uploader', $user->uid);
|
||||||
|
})
|
||||||
->first();
|
->first();
|
||||||
if ($duplicated) {
|
if ($duplicated) {
|
||||||
// if the texture already uploaded was set to private,
|
// if the texture already uploaded was set to private,
|
||||||
|
|
@ -290,11 +273,11 @@ class SkinlibController extends Controller
|
||||||
return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]);
|
return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileSize = ceil(strlen($sanitized) / 1024);
|
$size = ceil($file->getSize() / 1024);
|
||||||
$isPublic = is_string($data['public'])
|
$isPublic = is_string($data['public'])
|
||||||
? $data['public'] === '1'
|
? $data['public'] === '1'
|
||||||
: $data['public'];
|
: $data['public'];
|
||||||
$cost = $fileSize * (
|
$cost = $size * (
|
||||||
$isPublic
|
$isPublic
|
||||||
? option('score_per_storage')
|
? option('score_per_storage')
|
||||||
: option('private_score_per_storage')
|
: option('private_score_per_storage')
|
||||||
|
|
@ -305,13 +288,13 @@ class SkinlibController extends Controller
|
||||||
return json(trans('skinlib.upload.lack-score'), 1);
|
return json(trans('skinlib.upload.lack-score'), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dispatcher->dispatch('texture.uploading', [$image, $name, $hash]);
|
$dispatcher->dispatch('texture.uploading', [$file, $name, $hash]);
|
||||||
|
|
||||||
$texture = new Texture();
|
$texture = new Texture();
|
||||||
$texture->name = $name;
|
$texture->name = $name;
|
||||||
$texture->type = $type;
|
$texture->type = $type;
|
||||||
$texture->hash = $hash;
|
$texture->hash = $hash;
|
||||||
$texture->size = $fileSize;
|
$texture->size = $size;
|
||||||
$texture->public = $isPublic;
|
$texture->public = $isPublic;
|
||||||
$texture->uploader = $user->uid;
|
$texture->uploader = $user->uid;
|
||||||
$texture->likes = 1;
|
$texture->likes = 1;
|
||||||
|
|
@ -320,14 +303,14 @@ class SkinlibController extends Controller
|
||||||
/** @var FilesystemAdapter */
|
/** @var FilesystemAdapter */
|
||||||
$disk = Storage::disk('textures');
|
$disk = Storage::disk('textures');
|
||||||
if ($disk->missing($hash)) {
|
if ($disk->missing($hash)) {
|
||||||
$disk->put($hash, $sanitized);
|
$file->storePubliclyAs('', $hash, ['disk' => 'textures']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->score -= $cost;
|
$user->score -= $cost;
|
||||||
$user->closet()->attach($texture->tid, ['item_name' => $name]);
|
$user->closet()->attach($texture->tid, ['item_name' => $name]);
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
$dispatcher->dispatch('texture.uploaded', [$texture, $image]);
|
$dispatcher->dispatch('texture.uploaded', [$texture, $file]);
|
||||||
|
|
||||||
return json(trans('skinlib.upload.success', ['name' => $name]), 0, [
|
return json(trans('skinlib.upload.success', ['name' => $name]), 0, [
|
||||||
'tid' => $texture->tid,
|
'tid' => $texture->tid,
|
||||||
|
|
@ -406,7 +389,7 @@ class SkinlibController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Texture $texture,
|
Texture $texture
|
||||||
) {
|
) {
|
||||||
$data = $request->validate(['name' => [
|
$data = $request->validate(['name' => [
|
||||||
'required',
|
'required',
|
||||||
|
|
@ -436,7 +419,7 @@ class SkinlibController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter,
|
||||||
Texture $texture,
|
Texture $texture
|
||||||
) {
|
) {
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'type' => ['required', Rule::in(['steve', 'alex', 'cape'])],
|
'type' => ['required', Rule::in(['steve', 'alex', 'cape'])],
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ use App\Models\Player;
|
||||||
use App\Models\Texture;
|
use App\Models\Texture;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Blessing\Minecraft;
|
use Blessing\Minecraft;
|
||||||
|
use Cache;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Image;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Storage;
|
||||||
use Intervention\Image\Facades\Image;
|
|
||||||
|
|
||||||
class TextureController extends Controller
|
class TextureController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -71,8 +71,7 @@ class TextureController extends Controller
|
||||||
|
|
||||||
$lastModified = $disk->lastModified($hash);
|
$lastModified = $disk->lastModified($hash);
|
||||||
|
|
||||||
// TODO: refactor
|
return Image::make($image)
|
||||||
return \Intervention\Image\ImageManagerStatic::configure(['driver' => 'gd'])->make($image)
|
|
||||||
->response($usePNG ? 'png' : 'webp', 100)
|
->response($usePNG ? 'png' : 'webp', 100)
|
||||||
->setLastModified(Carbon::createFromTimestamp($lastModified));
|
->setLastModified(Carbon::createFromTimestamp($lastModified));
|
||||||
}
|
}
|
||||||
|
|
@ -133,12 +132,8 @@ class TextureController extends Controller
|
||||||
return $this->avatar($minecraft, $request, $texture);
|
return $this->avatar($minecraft, $request, $texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function avatar(Minecraft $minecraft, Request $request, ?Texture $texture)
|
protected function avatar(Minecraft $minecraft, Request $request, Texture $texture = null)
|
||||||
{
|
{
|
||||||
if (!empty($texture) && $texture->type !== 'steve' && $texture->type !== 'alex') {
|
|
||||||
return abort(422);
|
|
||||||
}
|
|
||||||
|
|
||||||
$size = (int) $request->query('size', 100);
|
$size = (int) $request->query('size', 100);
|
||||||
$mode = $request->has('3d') ? '3d' : '2d';
|
$mode = $request->has('3d') ? '3d' : '2d';
|
||||||
$usePNG = $request->has('png') || !(imagetypes() & IMG_WEBP);
|
$usePNG = $request->has('png') || !(imagetypes() & IMG_WEBP);
|
||||||
|
|
@ -146,8 +141,7 @@ class TextureController extends Controller
|
||||||
|
|
||||||
$disk = Storage::disk('textures');
|
$disk = Storage::disk('textures');
|
||||||
if (is_null($texture) || $disk->missing($texture->hash)) {
|
if (is_null($texture) || $disk->missing($texture->hash)) {
|
||||||
// TODO: refactor
|
return Image::make(resource_path("misc/textures/avatar$mode.png"))
|
||||||
return \Intervention\Image\ImageManagerStatic::configure(['driver' => 'gd'])->make(resource_path("misc/textures/avatar$mode.png"))
|
|
||||||
->resize($size, $size)
|
->resize($size, $size)
|
||||||
->response($usePNG ? 'png' : 'webp', 100);
|
->response($usePNG ? 'png' : 'webp', 100);
|
||||||
}
|
}
|
||||||
|
|
@ -167,8 +161,7 @@ class TextureController extends Controller
|
||||||
|
|
||||||
$lastModified = Carbon::createFromTimestamp($disk->lastModified($hash));
|
$lastModified = Carbon::createFromTimestamp($disk->lastModified($hash));
|
||||||
|
|
||||||
// TODO: refactor
|
return Image::make($image)
|
||||||
return \Intervention\Image\ImageManagerStatic::configure(['driver' => 'gd'])->make($image)
|
|
||||||
->resize($size, $size)
|
->resize($size, $size)
|
||||||
->response($usePNG ? 'png' : 'webp', 100)
|
->response($usePNG ? 'png' : 'webp', 100)
|
||||||
->setLastModified($lastModified);
|
->setLastModified($lastModified);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class TranslationsController extends Controller
|
||||||
Request $request,
|
Request $request,
|
||||||
Application $app,
|
Application $app,
|
||||||
JavaScript $js,
|
JavaScript $js,
|
||||||
LanguageLine $line,
|
LanguageLine $line
|
||||||
) {
|
) {
|
||||||
$data = $request->validate(['text' => 'required|string']);
|
$data = $request->validate(['text' => 'required|string']);
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ class TranslationsController extends Controller
|
||||||
public function delete(
|
public function delete(
|
||||||
Application $app,
|
Application $app,
|
||||||
JavaScript $js,
|
JavaScript $js,
|
||||||
LanguageLine $line,
|
LanguageLine $line
|
||||||
) {
|
) {
|
||||||
$line->delete();
|
$line->delete();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
class UpdateController extends Controller
|
class UpdateController extends Controller
|
||||||
{
|
{
|
||||||
public const SPEC = 2;
|
const SPEC = 2;
|
||||||
|
|
||||||
public function showUpdatePage()
|
public function showUpdatePage()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ use App\Events\UserProfileUpdated;
|
||||||
use App\Mail\EmailVerification;
|
use App\Mail\EmailVerification;
|
||||||
use App\Models\Texture;
|
use App\Models\Texture;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Auth;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Blessing\Rejection;
|
use Blessing\Rejection;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
||||||
|
use Mail;
|
||||||
|
use Session;
|
||||||
|
use URL;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -330,9 +330,9 @@ class UserController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!$texture->public
|
!$texture->public &&
|
||||||
&& $user->uid !== $texture->uploader
|
$user->uid !== $texture->uploader &&
|
||||||
&& !$user->isAdmin()
|
!$user->isAdmin()
|
||||||
) {
|
) {
|
||||||
return json(trans('skinlib.show.private'), 1);
|
return json(trans('skinlib.show.private'), 1);
|
||||||
}
|
}
|
||||||
|
|
@ -347,14 +347,4 @@ class UserController extends Controller
|
||||||
return json(trans('skinlib.non-existent'), 1);
|
return json(trans('skinlib.non-existent'), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toggleDarkMode()
|
|
||||||
{
|
|
||||||
/** @var User */
|
|
||||||
$user = auth()->user();
|
|
||||||
$user->is_dark_mode = !$user->is_dark_mode;
|
|
||||||
$user->save();
|
|
||||||
|
|
||||||
return response()->noContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ class UsersManagementController extends Controller
|
||||||
$authUser = $request->user();
|
$authUser = $request->user();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$targetUser->isNot($authUser)
|
$targetUser->isNot($authUser) &&
|
||||||
&& $targetUser->permission >= $authUser->permission
|
$targetUser->permission >= $authUser->permission
|
||||||
) {
|
) {
|
||||||
return json(trans('admin.users.operations.no-permission'), 1)
|
return json(trans('admin.users.operations.no-permission'), 1)
|
||||||
->setStatusCode(403);
|
->setStatusCode(403);
|
||||||
|
|
@ -134,8 +134,8 @@ class UsersManagementController extends Controller
|
||||||
$permission = (int) $data['permission'];
|
$permission = (int) $data['permission'];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$permission === User::ADMIN
|
$permission === User::ADMIN &&
|
||||||
&& $request->user()->permission < User::SUPER_ADMIN
|
$request->user()->permission < User::SUPER_ADMIN
|
||||||
) {
|
) {
|
||||||
return json(trans('admin.users.operations.no-permission'), 1)
|
return json(trans('admin.users.operations.no-permission'), 1)
|
||||||
->setStatusCode(403);
|
->setStatusCode(403);
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,19 @@ class Kernel extends HttpKernel
|
||||||
*
|
*
|
||||||
* These middleware are run during every request to your application.
|
* These middleware are run during every request to your application.
|
||||||
*
|
*
|
||||||
* @var array<int, class-string|string>
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
|
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
|
||||||
Middleware\ConvertEmptyStringsToNull::class,
|
\App\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
Middleware\DetectLanguagePrefer::class,
|
\App\Http\Middleware\DetectLanguagePrefer::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application's route middleware groups.
|
* The application's route middleware groups.
|
||||||
*
|
*
|
||||||
* @var array<string, array<int, class-string|string>>
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middlewareGroups = [
|
protected $middlewareGroups = [
|
||||||
'web' => [
|
'web' => [
|
||||||
|
|
@ -33,39 +32,38 @@ class Kernel extends HttpKernel
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
|
||||||
Middleware\EnforceEverGreen::class,
|
\App\Http\Middleware\EnforceEverGreen::class,
|
||||||
Middleware\RedirectToSetup::class,
|
\App\Http\Middleware\RedirectToSetup::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
'bindings',
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
'bindings',
|
||||||
],
|
],
|
||||||
|
|
||||||
'authorize' => [
|
'authorize' => [
|
||||||
'auth:web',
|
'auth:web',
|
||||||
Middleware\RejectBannedUser::class,
|
\App\Http\Middleware\RejectBannedUser::class,
|
||||||
Middleware\EnsureEmailFilled::class,
|
\App\Http\Middleware\EnsureEmailFilled::class,
|
||||||
Middleware\FireUserAuthenticated::class,
|
\App\Http\Middleware\FireUserAuthenticated::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application's middleware aliases.
|
* The application's route middleware.
|
||||||
*
|
*
|
||||||
* Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
|
* These middleware may be assigned to groups or used individually.
|
||||||
*
|
*
|
||||||
* @var array<string, class-string|string>
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middlewareAliases = [
|
protected $routeMiddleware = [
|
||||||
'auth' => Middleware\Authenticate::class,
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
'guest' => Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
'role' => Middleware\CheckRole::class,
|
'role' => \App\Http\Middleware\CheckRole::class,
|
||||||
'setup' => Middleware\CheckInstallation::class,
|
'setup' => \App\Http\Middleware\CheckInstallation::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => Middleware\CheckUserVerified::class,
|
'verified' => \App\Http\Middleware\CheckUserVerified::class,
|
||||||
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
|
|
||||||
'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ class Authenticate extends Middleware
|
||||||
'msg' => trans('auth.check.anonymous'),
|
'msg' => trans('auth.check.anonymous'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return route('auth.login');
|
return '/auth/login';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,16 @@
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class CheckRole
|
class CheckRole
|
||||||
{
|
{
|
||||||
protected $roles = [
|
protected $roles = [
|
||||||
'banned' => User::BANNED,
|
'banned' => -1,
|
||||||
'normal' => User::NORMAL,
|
'normal' => 0,
|
||||||
'admin' => User::ADMIN,
|
'admin' => 1,
|
||||||
'super-admin' => User::SUPER_ADMIN,
|
'super-admin' => 2,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function handle(Request $request, Closure $next, $role)
|
public function handle(Request $request, Closure $next, $role)
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ class DetectLanguagePrefer
|
||||||
?? $request->cookie('locale')
|
?? $request->cookie('locale')
|
||||||
?? $request->getPreferredLanguage();
|
?? $request->getPreferredLanguage();
|
||||||
if (
|
if (
|
||||||
($info = Arr::get(config('locales'), $locale))
|
($info = Arr::get(config('locales'), $locale)) &&
|
||||||
&& ($alias = Arr::get($info, 'alias'))
|
($alias = Arr::get($info, 'alias'))
|
||||||
) {
|
) {
|
||||||
$locale = $alias;
|
$locale = $alias;
|
||||||
}
|
}
|
||||||
|
|
@ -28,9 +28,7 @@ class DetectLanguagePrefer
|
||||||
|
|
||||||
/** @var Response */
|
/** @var Response */
|
||||||
$response = $next($request);
|
$response = $next($request);
|
||||||
if (!in_array('api', optional($request->route())->middleware() ?? [])) {
|
$response->cookie('locale', $locale, 120);
|
||||||
$response->cookie('locale', $locale, 120);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,12 @@
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Closure;
|
||||||
|
|
||||||
class RejectBannedUser
|
class RejectBannedUser
|
||||||
{
|
{
|
||||||
public function handle(Request $request, \Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if ($request->route()->getName() === 'auth.logout') {
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->user()->permission == User::BANNED) {
|
if ($request->user()->permission == User::BANNED) {
|
||||||
if ($request->expectsJson()) {
|
if ($request->expectsJson()) {
|
||||||
$response = json(trans('auth.check.banned'), -1);
|
$response = json(trans('auth.check.banned'), -1);
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,39 @@
|
||||||
namespace App\Http\View\Composers;
|
namespace App\Http\View\Composers;
|
||||||
|
|
||||||
use App\Services\Translations\JavaScript;
|
use App\Services\Translations\JavaScript;
|
||||||
|
use App\Services\Webpack;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class FootComposer
|
class FootComposer
|
||||||
{
|
{
|
||||||
protected Request $request;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
protected JavaScript $javascript;
|
/** @var Webpack */
|
||||||
|
protected $webpack;
|
||||||
|
|
||||||
protected Dispatcher $dispatcher;
|
/** @var JavaScript */
|
||||||
|
protected $javascript;
|
||||||
|
|
||||||
protected Filter $filter;
|
/** @var Dispatcher */
|
||||||
|
protected $dispatcher;
|
||||||
|
|
||||||
|
/** @var Filter */
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Request $request,
|
Request $request,
|
||||||
|
Webpack $webpack,
|
||||||
JavaScript $javascript,
|
JavaScript $javascript,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
|
$this->webpack = $webpack;
|
||||||
$this->javascript = $javascript;
|
$this->javascript = $javascript;
|
||||||
$this->dispatcher = $dispatcher;
|
$this->dispatcher = $dispatcher;
|
||||||
$this->filter = $filter;
|
$this->filter = $filter;
|
||||||
|
|
@ -39,10 +50,47 @@ class FootComposer
|
||||||
public function injectJavaScript(View $view)
|
public function injectJavaScript(View $view)
|
||||||
{
|
{
|
||||||
$scripts = [];
|
$scripts = [];
|
||||||
|
|
||||||
|
$locale = app()->getLocale();
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => $this->javascript->generate($locale),
|
||||||
|
];
|
||||||
|
if (Str::startsWith(config('app.asset.env'), 'dev')) {
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => $this->webpack->url('style.js'),
|
||||||
|
'async' => true,
|
||||||
|
'defer' => true,
|
||||||
|
];
|
||||||
|
} elseif (!$this->request->is('/')) {
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => 'https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js',
|
||||||
|
'integrity' => 'sha256-yUhvEmYVhZ/GGshIQKArLvySDSh6cdmdcIx0spR3UP4=',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => 'https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js',
|
||||||
|
'integrity' => 'sha256-vFt3l+illeNlwThbDUdoPTqF81M8WNSZZZt3HEjsbSU=',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => 'https://cdn.jsdelivr.net/npm/@blessing-skin/admin-lte@3.0.5/dist/admin-lte.min.js',
|
||||||
|
'integrity' => 'sha256-8RoBtV28TLYWlTMCRwqGv4NQW9bgc4jZphsQV3iLV4g=',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
if ($this->request->is('/')) {
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => $this->webpack->url('home.js'),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$scripts[] = [
|
||||||
|
'src' => $this->webpack->url('app.js'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$scripts = $this->filter->apply('scripts', $scripts);
|
$scripts = $this->filter->apply('scripts', $scripts);
|
||||||
|
|
||||||
$view->with([
|
$view->with([
|
||||||
'i18n' => $this->javascript->generate(app()->getLocale()),
|
|
||||||
'scripts' => $scripts,
|
'scripts' => $scripts,
|
||||||
'inline_js' => option('custom_js'),
|
'inline_js' => option('custom_js'),
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\View\Composers;
|
namespace App\Http\View\Composers;
|
||||||
|
|
||||||
|
use App\Services\Webpack;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -11,17 +12,25 @@ use Illuminate\View\View;
|
||||||
|
|
||||||
class HeadComposer
|
class HeadComposer
|
||||||
{
|
{
|
||||||
protected Dispatcher $dispatcher;
|
/** @var Webpack */
|
||||||
|
protected $webpack;
|
||||||
|
|
||||||
protected Request $request;
|
/** @var Dispatcher */
|
||||||
|
protected $dispatcher;
|
||||||
|
|
||||||
protected Filter $filter;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/** @var Filter */
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
Webpack $webpack,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Request $request,
|
Request $request,
|
||||||
Filter $filter,
|
Filter $filter
|
||||||
) {
|
) {
|
||||||
|
$this->webpack = $webpack;
|
||||||
$this->dispatcher = $dispatcher;
|
$this->dispatcher = $dispatcher;
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
$this->filter = $filter;
|
$this->filter = $filter;
|
||||||
|
|
@ -80,6 +89,37 @@ class HeadComposer
|
||||||
public function injectStyles(View $view)
|
public function injectStyles(View $view)
|
||||||
{
|
{
|
||||||
$links = [];
|
$links = [];
|
||||||
|
$links[] = [
|
||||||
|
'rel' => 'stylesheet',
|
||||||
|
'href' => 'https://cdn.jsdelivr.net/npm/@blessing-skin/admin-lte@3.0.5/dist/admin-lte.min.css',
|
||||||
|
'integrity' => 'sha256-zG+BobiRcnWbKPGtQ++LoogyH9qSHjhBwhbFFP8HbDM=',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
$links[] = [
|
||||||
|
'rel' => 'preload',
|
||||||
|
'as' => 'font',
|
||||||
|
'href' => 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/webfonts/fa-solid-900.woff2',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
$links[] = [
|
||||||
|
'rel' => 'preload',
|
||||||
|
'as' => 'font',
|
||||||
|
'href' => 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/webfonts/fa-regular-400.woff2',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
$links[] = [
|
||||||
|
'rel' => 'stylesheet',
|
||||||
|
'href' => 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css',
|
||||||
|
'integrity' => 'sha256-h20CPZ0QyXlBuAw7A+KluUYx/3pK+c7lYEpqLTlxjYQ=',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
if (!$this->request->is('/') && config('app.asset.env') !== 'development') {
|
||||||
|
$links[] = [
|
||||||
|
'rel' => 'stylesheet',
|
||||||
|
'href' => $this->webpack->url('style.css'),
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
];
|
||||||
|
}
|
||||||
$links = $this->filter->apply('head_links', $links);
|
$links = $this->filter->apply('head_links', $links);
|
||||||
$view->with('links', $links);
|
$view->with('links', $links);
|
||||||
$view->with('inline_css', option('custom_css'));
|
$view->with('inline_css', option('custom_css'));
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ use Illuminate\View\View;
|
||||||
|
|
||||||
class LanguagesMenuComposer
|
class LanguagesMenuComposer
|
||||||
{
|
{
|
||||||
protected Request $request;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
public function __construct(Request $request)
|
public function __construct(Request $request)
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +22,9 @@ class LanguagesMenuComposer
|
||||||
$path = $this->request->path();
|
$path = $this->request->path();
|
||||||
|
|
||||||
$langs = collect(config('locales'))
|
$langs = collect(config('locales'))
|
||||||
->reject(fn ($locale) => Arr::has($locale, 'alias'))
|
->reject(function ($locale) {
|
||||||
|
return Arr::has($locale, 'alias');
|
||||||
|
})
|
||||||
->map(function ($locale, $id) use ($query, $path) {
|
->map(function ($locale, $id) use ($query, $path) {
|
||||||
$query = array_merge($query, ['lang' => $id]);
|
$query = array_merge($query, ['lang' => $id]);
|
||||||
$locale['url'] = url($path.'?'.http_build_query($query));
|
$locale['url'] = url($path.'?'.http_build_query($query));
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Http\View\Composers;
|
namespace App\Http\View\Composers;
|
||||||
|
|
||||||
use App\Events;
|
use App\Events;
|
||||||
use App\Services\Plugin;
|
|
||||||
use App\Services\PluginManager;
|
use App\Services\PluginManager;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -12,9 +11,11 @@ use Illuminate\View\View;
|
||||||
|
|
||||||
class SideMenuComposer
|
class SideMenuComposer
|
||||||
{
|
{
|
||||||
protected Request $request;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
protected Filter $filter;
|
/** @var Filter */
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
public function __construct(Request $request, Filter $filter)
|
public function __construct(Request $request, Filter $filter)
|
||||||
{
|
{
|
||||||
|
|
@ -43,7 +44,9 @@ class SideMenuComposer
|
||||||
$menu = $menu[$type];
|
$menu = $menu[$type];
|
||||||
$menu = $this->filter->apply('side_menu', $menu, [$type]);
|
$menu = $this->filter->apply('side_menu', $menu, [$type]);
|
||||||
|
|
||||||
$view->with('items', array_map(fn ($item) => $this->transform($item), $menu));
|
$view->with('items', array_map(function ($item) {
|
||||||
|
return $this->transform($item);
|
||||||
|
}, $menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform(array $item): array
|
public function transform(array $item): array
|
||||||
|
|
@ -63,10 +66,9 @@ class SideMenuComposer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Arr::has($item, 'children')) {
|
if (Arr::has($item, 'children')) {
|
||||||
$item['children'] = array_map(
|
$item['children'] = array_map(function ($item) {
|
||||||
fn ($item) => $this->transform($item),
|
return $this->transform($item);
|
||||||
$item['children'],
|
}, $item['children']);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$item['classes'] = $classes;
|
$item['classes'] = $classes;
|
||||||
|
|
@ -80,7 +82,9 @@ class SideMenuComposer
|
||||||
if (Arr::get($item, 'id') === 'plugin-configs') {
|
if (Arr::get($item, 'id') === 'plugin-configs') {
|
||||||
$pluginConfigs = resolve(PluginManager::class)
|
$pluginConfigs = resolve(PluginManager::class)
|
||||||
->getEnabledPlugins()
|
->getEnabledPlugins()
|
||||||
->filter(fn (Plugin $plugin) => $plugin->hasConfig())
|
->filter(function ($plugin) {
|
||||||
|
return $plugin->hasConfig();
|
||||||
|
})
|
||||||
->map(function ($plugin) {
|
->map(function ($plugin) {
|
||||||
return [
|
return [
|
||||||
'title' => trans($plugin->title),
|
'title' => trans($plugin->title),
|
||||||
|
|
@ -91,7 +95,7 @@ class SideMenuComposer
|
||||||
|
|
||||||
// Don't display this menu item when no plugin config is available
|
// Don't display this menu item when no plugin config is available
|
||||||
if ($pluginConfigs->isNotEmpty()) {
|
if ($pluginConfigs->isNotEmpty()) {
|
||||||
array_push($item['children'], ...$pluginConfigs->values()->all());
|
$item['children'] = array_merge($item['children'], $pluginConfigs->values()->all());
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ use Illuminate\View\View;
|
||||||
|
|
||||||
class UserMenuComposer
|
class UserMenuComposer
|
||||||
{
|
{
|
||||||
protected Request $request;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
protected Filter $filter;
|
/** @var Filter */
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
public function __construct(Request $request, Filter $filter)
|
public function __construct(Request $request, Filter $filter)
|
||||||
{
|
{
|
||||||
|
|
@ -23,34 +25,8 @@ class UserMenuComposer
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 36], false);
|
$avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 36], false);
|
||||||
$avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]);
|
$avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]);
|
||||||
$avatarPNG = route(
|
$cli = $this->request->is('admin', 'admin/*');
|
||||||
'avatar.texture',
|
|
||||||
['tid' => $user->avatar, 'size' => 36, 'png' => true],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$avatarPNG = $this->filter->apply('user_avatar', $avatarPNG, [$user]);
|
|
||||||
|
|
||||||
$menuItems = [
|
$view->with(compact('user', 'avatar', 'cli'));
|
||||||
['label' => trans('general.user-center'), 'link' => route('user.home')],
|
|
||||||
['label' => trans('general.profile'), 'link' => route('user.profile.view')],
|
|
||||||
];
|
|
||||||
if ($user->isAdmin()) {
|
|
||||||
array_push(
|
|
||||||
$menuItems,
|
|
||||||
['label' => '', 'link' => '#divider'],
|
|
||||||
['label' => trans('general.admin-panel'), 'link' => route('admin.view')],
|
|
||||||
['label' => trans('general.user-manage'), 'link' => route('admin.users.view')],
|
|
||||||
['label' => trans('general.report-manage'), 'link' => route('admin.reports.view')],
|
|
||||||
['label' => 'Web CLI', 'link' => '#launch-cli'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$menuItems = $this->filter->apply('user_menu', $menuItems, [$user]);
|
|
||||||
|
|
||||||
$view->with([
|
|
||||||
'user' => $user,
|
|
||||||
'avatar' => $avatar,
|
|
||||||
'avatar_png' => $avatarPNG,
|
|
||||||
'menu' => $menuItems,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,11 @@ use Illuminate\View\View;
|
||||||
|
|
||||||
class UserPanelComposer
|
class UserPanelComposer
|
||||||
{
|
{
|
||||||
protected Dispatcher $dispatcher;
|
/** @var Dispatcher */
|
||||||
|
protected $dispatcher;
|
||||||
|
|
||||||
protected Filter $filter;
|
/** @var Filter */
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
public function __construct(Dispatcher $dispatcher, Filter $filter)
|
public function __construct(Dispatcher $dispatcher, Filter $filter)
|
||||||
{
|
{
|
||||||
|
|
@ -25,12 +27,6 @@ class UserPanelComposer
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 45], false);
|
$avatarUrl = route('avatar.texture', ['tid' => $user->avatar, 'size' => 45], false);
|
||||||
$avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]);
|
$avatar = $this->filter->apply('user_avatar', $avatarUrl, [$user]);
|
||||||
$avatarPNG = route(
|
|
||||||
'avatar.texture',
|
|
||||||
['tid' => $user->avatar, 'size' => 45, 'png' => true],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$avatarPNG = $this->filter->apply('user_avatar', $avatarPNG, [$user]);
|
|
||||||
|
|
||||||
$badges = [];
|
$badges = [];
|
||||||
if ($user->isAdmin()) {
|
if ($user->isAdmin()) {
|
||||||
|
|
@ -39,11 +35,6 @@ class UserPanelComposer
|
||||||
$this->dispatcher->dispatch(new \App\Events\RenderingBadges($badges));
|
$this->dispatcher->dispatch(new \App\Events\RenderingBadges($badges));
|
||||||
$badges = $this->filter->apply('user_badges', $badges, [$user]);
|
$badges = $this->filter->apply('user_badges', $badges, [$user]);
|
||||||
|
|
||||||
$view->with([
|
$view->with(compact('user', 'avatar', 'badges'));
|
||||||
'user' => $user,
|
|
||||||
'avatar' => $avatar,
|
|
||||||
'avatar_png' => $avatarPNG,
|
|
||||||
'badges' => $badges,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use Symfony\Component\Finder\SplFileInfo;
|
||||||
|
|
||||||
class CleanUpFrontEndLocaleFiles
|
class CleanUpFrontEndLocaleFiles
|
||||||
{
|
{
|
||||||
protected Filesystem $filesystem;
|
/** @var Filesystem */
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
public function __construct(Filesystem $filesystem)
|
public function __construct(Filesystem $filesystem)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
class CopyPluginAssets
|
class CopyPluginAssets
|
||||||
{
|
{
|
||||||
protected Filesystem $filesystem;
|
/** @var Filesystem */
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
public function __construct(Filesystem $filesystem)
|
public function __construct(Filesystem $filesystem)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Event;
|
||||||
|
|
||||||
class NotifyFailedPlugin
|
class NotifyFailedPlugin
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class SetAppLocale
|
class SetAppLocale
|
||||||
{
|
{
|
||||||
protected Request $request;
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
public function __construct(Request $request)
|
public function __construct(Request $request)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ namespace App\Mail;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
use Illuminate\Mail\Mailables\Headers;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class EmailVerification extends Mailable
|
class EmailVerification extends Mailable
|
||||||
|
|
@ -27,13 +26,4 @@ class EmailVerification extends Mailable
|
||||||
->subject(trans('user.verification.mail.title', ['sitename' => $site_name]))
|
->subject(trans('user.verification.mail.title', ['sitename' => $site_name]))
|
||||||
->view('mails.email-verification');
|
->view('mails.email-verification');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function headers(): Headers
|
|
||||||
{
|
|
||||||
return new Headers(
|
|
||||||
text: [
|
|
||||||
'Auto-Submitted' => 'auto-generated',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ namespace App\Mail;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
use Illuminate\Mail\Mailables\Headers;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class ForgotPassword extends Mailable
|
class ForgotPassword extends Mailable
|
||||||
|
|
@ -27,13 +26,4 @@ class ForgotPassword extends Mailable
|
||||||
->subject(trans('auth.forgot.mail.title', ['sitename' => $site_name]))
|
->subject(trans('auth.forgot.mail.title', ['sitename' => $site_name]))
|
||||||
->view('mails.password-reset');
|
->view('mails.password-reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function headers(): Headers
|
|
||||||
{
|
|
||||||
return new Headers(
|
|
||||||
text: [
|
|
||||||
'Auto-Submitted' => 'auto-generated',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Events\PlayerProfileUpdated;
|
use App\Events\PlayerProfileUpdated;
|
||||||
|
use App\Models;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||||
|
|
@ -23,7 +23,6 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||||
*/
|
*/
|
||||||
class Player extends Model
|
class Player extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
|
||||||
use SearchString;
|
use SearchString;
|
||||||
|
|
||||||
public const CREATED_AT = null;
|
public const CREATED_AT = null;
|
||||||
|
|
@ -56,17 +55,17 @@ class Player extends Model
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'uid');
|
return $this->belongsTo(Models\User::class, 'uid');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function skin()
|
public function skin()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Texture::class, 'tid_skin');
|
return $this->belongsTo(Models\Texture::class, 'tid_skin');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cape()
|
public function cape()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Texture::class, 'tid_cape');
|
return $this->belongsTo(Models\Texture::class, 'tid_cape');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getModelAttribute()
|
public function getModelAttribute()
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property int $id
|
|
||||||
* @property string $name
|
|
||||||
* @property string $description
|
|
||||||
*/
|
|
||||||
class Scope extends Model
|
|
||||||
{
|
|
||||||
public $timestamps = false;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'name', 'description',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,6 @@ namespace App\Models;
|
||||||
|
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
|
@ -24,8 +23,6 @@ use Illuminate\Support\Carbon;
|
||||||
*/
|
*/
|
||||||
class Texture extends Model
|
class Texture extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
public $primaryKey = 'tid';
|
public $primaryKey = 'tid';
|
||||||
public const CREATED_AT = 'upload_at';
|
public const CREATED_AT = 'upload_at';
|
||||||
public const UPDATED_AT = null;
|
public const UPDATED_AT = null;
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ namespace App\Models;
|
||||||
|
|
||||||
use App\Models\Concerns\HasPassword;
|
use App\Models\Concerns\HasPassword;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Laravel\Passport\HasApiTokens;
|
use Laravel\Passport\HasApiTokens;
|
||||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||||
|
use Tymon\JWTAuth\Contracts\JWTSubject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property int $uid
|
* @property int $uid
|
||||||
|
|
@ -20,7 +20,6 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||||
* @property int $score
|
* @property int $score
|
||||||
* @property int $permission
|
* @property int $permission
|
||||||
* @property string $ip
|
* @property string $ip
|
||||||
* @property bool $is_dark_mode
|
|
||||||
* @property string $last_sign_at
|
* @property string $last_sign_at
|
||||||
* @property string $register_at
|
* @property string $register_at
|
||||||
* @property bool $verified
|
* @property bool $verified
|
||||||
|
|
@ -28,18 +27,17 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||||
* @property Collection $players
|
* @property Collection $players
|
||||||
* @property Collection $closet
|
* @property Collection $closet
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable implements JWTSubject
|
||||||
{
|
{
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
use HasFactory;
|
|
||||||
use HasPassword;
|
use HasPassword;
|
||||||
use HasApiTokens;
|
use HasApiTokens;
|
||||||
use SearchString;
|
use SearchString;
|
||||||
|
|
||||||
public const BANNED = -1;
|
const BANNED = -1;
|
||||||
public const NORMAL = 0;
|
const NORMAL = 0;
|
||||||
public const ADMIN = 1;
|
const ADMIN = 1;
|
||||||
public const SUPER_ADMIN = 2;
|
const SUPER_ADMIN = 2;
|
||||||
|
|
||||||
protected $primaryKey = 'uid';
|
protected $primaryKey = 'uid';
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
@ -54,7 +52,6 @@ class User extends Authenticatable
|
||||||
'avatar' => 'integer',
|
'avatar' => 'integer',
|
||||||
'permission' => 'integer',
|
'permission' => 'integer',
|
||||||
'verified' => 'bool',
|
'verified' => 'bool',
|
||||||
'is_dark_mode' => 'bool',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = ['password', 'remember_token'];
|
protected $hidden = ['password', 'remember_token'];
|
||||||
|
|
@ -67,7 +64,6 @@ class User extends Authenticatable
|
||||||
'last_sign_at' => ['date' => true],
|
'last_sign_at' => ['date' => true],
|
||||||
'register_at' => ['date' => true],
|
'register_at' => ['date' => true],
|
||||||
'verified' => ['boolean' => true],
|
'verified' => ['boolean' => true],
|
||||||
'is_dark_mode' => ['boolean' => true],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function isAdmin(): bool
|
public function isAdmin(): bool
|
||||||
|
|
@ -112,4 +108,14 @@ class User extends Authenticatable
|
||||||
{
|
{
|
||||||
return $this->uid;
|
return $this->uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getJWTIdentifier()
|
||||||
|
{
|
||||||
|
return $this->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJWTCustomClaims()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ class SiteMessage extends Notification implements ShouldQueue
|
||||||
/**
|
/**
|
||||||
* Get the notification's delivery channels.
|
* Get the notification's delivery channels.
|
||||||
*
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function via($notifiable)
|
public function via($notifiable)
|
||||||
|
|
@ -35,6 +37,8 @@ class SiteMessage extends Notification implements ShouldQueue
|
||||||
/**
|
/**
|
||||||
* Get the array representation of the notification.
|
* Get the array representation of the notification.
|
||||||
*
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function toArray($notifiable)
|
public function toArray($notifiable)
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Observers;
|
|
||||||
|
|
||||||
use App\Models\Scope;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
|
|
||||||
class ScopeObserver
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle the Scope "saved" event.
|
|
||||||
*/
|
|
||||||
public function saved(): void
|
|
||||||
{
|
|
||||||
$this->refreshCachedScopes();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the Scope "deleted" event.
|
|
||||||
*/
|
|
||||||
public function deleted(): void
|
|
||||||
{
|
|
||||||
$this->refreshCachedScopes();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function refreshCachedScopes(): void
|
|
||||||
{
|
|
||||||
Cache::forget('scopes');
|
|
||||||
Cache::rememberForever('scopes', function () {
|
|
||||||
return Scope::pluck('description', 'name')->toArray();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,23 +4,20 @@ namespace App\Providers;
|
||||||
|
|
||||||
use App\Services;
|
use App\Services;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Pagination\Paginator;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function register(): void
|
public function register()
|
||||||
{
|
{
|
||||||
$this->app->singleton('cipher', 'App\Services\Cipher\\'.config('secure.cipher'));
|
$this->app->singleton('cipher', 'App\Services\Cipher\\'.config('secure.cipher'));
|
||||||
$this->app->singleton(Services\Option::class);
|
$this->app->singleton(Services\Option::class);
|
||||||
$this->app->alias(Services\Option::class, 'options');
|
$this->app->alias(Services\Option::class, 'options');
|
||||||
|
$this->app->singleton(Services\Webpack::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(Request $request): void
|
public function boot(Request $request)
|
||||||
{
|
{
|
||||||
Paginator::useBootstrap();
|
|
||||||
|
|
||||||
$this->configureUrlGenerator($request);
|
$this->configureUrlGenerator($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,8 +33,8 @@ class AppServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
// Replace HTTP_HOST with site_url set in options,
|
// Replace HTTP_HOST with site_url set in options,
|
||||||
// to prevent CDN source problems.
|
// to prevent CDN source problems.
|
||||||
if (URL::isValidUrl($rootUrl)) {
|
if ($this->app['url']->isValidUrl($rootUrl)) {
|
||||||
URL::forceRootUrl($rootUrl);
|
$this->app['url']->forceRootUrl($rootUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +50,7 @@ class AppServiceProvider extends ServiceProvider
|
||||||
|| $request->server('HTTP_X_FORWARDED_SSL') === 'on';
|
|| $request->server('HTTP_X_FORWARDED_SSL') === 'on';
|
||||||
|
|
||||||
if (option('force_ssl') || $isRequestSecure) {
|
if (option('force_ssl') || $isRequestSecure) {
|
||||||
URL::forceScheme('https');
|
$this->app['url']->forceScheme('https');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use App\Models\Scope;
|
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Laravel\Passport\Passport;
|
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The model to policy mappings for the application.
|
|
||||||
*
|
|
||||||
* @var array<class-string, class-string>
|
|
||||||
*/
|
|
||||||
protected $policies = [
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any authentication / authorization services.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
|
||||||
{
|
|
||||||
$defaultScopes = [
|
|
||||||
'User.Read' => 'auth.oauth.scope.user.read',
|
|
||||||
'Notification.Read' => 'auth.oauth.scope.notification.read',
|
|
||||||
'Notification.ReadWrite' => 'auth.oauth.scope.notification.readwrite',
|
|
||||||
'Player.Read' => 'auth.oauth.scope.player.read',
|
|
||||||
'Player.ReadWrite' => 'auth.oauth.scope.player.readwrite',
|
|
||||||
'Closet.Read' => 'auth.oauth.scope.closet.read',
|
|
||||||
'Closet.ReadWrtie' => 'auth.oauth.scope.closet.readwrite',
|
|
||||||
'UsersManagement.Read' => 'auth.oauth.scope.users-management.read',
|
|
||||||
'UsersManagement.ReadWrite' => 'auth.oauth.scope.users-management.readwrite',
|
|
||||||
'PlayersManagement.Read' => 'auth.oauth.scope.players-management.read',
|
|
||||||
'PlayersManagement.ReadWrite' => 'auth.oauth.scope.players-management.readwrite',
|
|
||||||
'ClosetManagement.Read' => 'auth.oauth.scope.closet-management.read',
|
|
||||||
'ClosetManagement.ReadWrite' => 'auth.oauth.scope.closet-management.readwrite',
|
|
||||||
'ReportsManagement.Read' => 'auth.oauth.scope.reports-management.read',
|
|
||||||
'ReportsManagement.ReadWrite' => 'auth.oauth.scope.reports-management.readwrite',
|
|
||||||
];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return empty scopes if running unit tests or before installation.
|
|
||||||
* In these cases, migrations aren’t run yet, so DB queries will fail.
|
|
||||||
* OAuth isn’t tested in unit tests, so returning empty scopes should be fine...?
|
|
||||||
* Maybe the best approach is to run migrations before bootstrap in tests,
|
|
||||||
* but this seems impossible for DB_DATABASE=:memory:;
|
|
||||||
* Or change how scopes are registered so they don't depend on the database,
|
|
||||||
* but that may introduce BREAKING CHANGES and plugin incompatibility.
|
|
||||||
* PRs welcome for better solutions!
|
|
||||||
*/
|
|
||||||
$scopes = (app()->runningUnitTests() || !Storage::disk('root')->exists('storage/install.lock')) ? [] : Cache::rememberForever('scopes', function () {
|
|
||||||
return Scope::pluck('description', 'name')->toArray();
|
|
||||||
});
|
|
||||||
|
|
||||||
Passport::tokensCan(array_merge($defaultScopes, $scopes));
|
|
||||||
|
|
||||||
Passport::setDefaultScope(['User.Read']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,17 +3,11 @@
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Listeners;
|
use App\Listeners;
|
||||||
use App\Models\Scope;
|
|
||||||
use App\Observers\ScopeObserver;
|
|
||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
class EventServiceProvider extends ServiceProvider
|
class EventServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
// The event listener mappings for the application.
|
||||||
* The event to listener mappings for the application.
|
|
||||||
*
|
|
||||||
* @var array<class-string, array<int, class-string>>
|
|
||||||
*/
|
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
'App\Events\PluginWasEnabled' => [
|
'App\Events\PluginWasEnabled' => [
|
||||||
Listeners\CopyPluginAssets::class,
|
Listeners\CopyPluginAssets::class,
|
||||||
|
|
@ -45,12 +39,4 @@ class EventServiceProvider extends ServiceProvider
|
||||||
Listeners\SetAppLocale::class,
|
Listeners\SetAppLocale::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any events for your application.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
|
||||||
{
|
|
||||||
Scope::observe(ScopeObserver::class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class PluginServiceProvider extends ServiceProvider
|
class PluginServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function register(): void
|
public function register()
|
||||||
{
|
{
|
||||||
$this->app->singleton(PluginManager::class);
|
$this->app->singleton(PluginManager::class);
|
||||||
$this->app->alias(PluginManager::class, 'plugins');
|
$this->app->alias(PluginManager::class, 'plugins');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(PluginManager $plugins): void
|
public function boot(PluginManager $plugins)
|
||||||
{
|
{
|
||||||
$plugins->boot();
|
$plugins->boot();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ namespace App\Providers;
|
||||||
use App\Events\ConfigureRoutes;
|
use App\Events\ConfigureRoutes;
|
||||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||||
use Illuminate\Routing\Router;
|
use Illuminate\Routing\Router;
|
||||||
use Illuminate\Support\Facades\Route;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Laravel\Passport\Passport;
|
||||||
|
use Route;
|
||||||
|
|
||||||
class RouteServiceProvider extends ServiceProvider
|
class RouteServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
|
@ -19,7 +20,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
/**
|
/**
|
||||||
* Define the routes for the application.
|
* Define the routes for the application.
|
||||||
*/
|
*/
|
||||||
public function map(Router $router): void
|
public function map(Router $router)
|
||||||
{
|
{
|
||||||
$this->mapStaticRoutes($router);
|
$this->mapStaticRoutes($router);
|
||||||
|
|
||||||
|
|
@ -27,9 +28,10 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
$this->mapApiRoutes();
|
$this->mapApiRoutes();
|
||||||
|
|
||||||
|
Passport::routes();
|
||||||
foreach ($router->getRoutes()->getRoutesByName() as $name => $route) {
|
foreach ($router->getRoutes()->getRoutesByName() as $name => $route) {
|
||||||
if (Str::startsWith($name, ['passport.authorizations', 'passport.tokens', 'passport.clients'])) {
|
if (Str::startsWith($name, ['passport.authorizations', 'passport.tokens', 'passport.clients'])) {
|
||||||
$route->middleware(['auth', 'verified']);
|
$route->middleware('verified');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +42,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
* Define the "web" routes for the application.
|
* Define the "web" routes for the application.
|
||||||
* These routes all receive session state, CSRF protection, etc.
|
* These routes all receive session state, CSRF protection, etc.
|
||||||
*/
|
*/
|
||||||
protected function mapWebRoutes(Router $router): void
|
protected function mapWebRoutes(Router $router)
|
||||||
{
|
{
|
||||||
Route::middleware(['web'])
|
Route::middleware(['web'])
|
||||||
->namespace($this->namespace)
|
->namespace($this->namespace)
|
||||||
|
|
@ -51,7 +53,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
* Define the "static" routes for the application.
|
* Define the "static" routes for the application.
|
||||||
* These routes will not load session, etc.
|
* These routes will not load session, etc.
|
||||||
*/
|
*/
|
||||||
protected function mapStaticRoutes(Router $router): void
|
protected function mapStaticRoutes(Router $router)
|
||||||
{
|
{
|
||||||
Route::namespace($this->namespace)
|
Route::namespace($this->namespace)
|
||||||
->group(base_path('routes/static.php'));
|
->group(base_path('routes/static.php'));
|
||||||
|
|
@ -61,7 +63,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
* Define the "api" routes for the application.
|
* Define the "api" routes for the application.
|
||||||
* These routes are typically stateless.
|
* These routes are typically stateless.
|
||||||
*/
|
*/
|
||||||
protected function mapApiRoutes(): void
|
protected function mapApiRoutes()
|
||||||
{
|
{
|
||||||
Route::prefix('api')
|
Route::prefix('api')
|
||||||
->middleware(
|
->middleware(
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Http\View\Composers;
|
use App\Http\View\Composers;
|
||||||
use Illuminate\Support\Facades\View;
|
use App\Services\Webpack;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use View;
|
||||||
|
|
||||||
class ViewServiceProvider extends ServiceProvider
|
class ViewServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function boot(): void
|
public function boot(Webpack $webpack)
|
||||||
{
|
{
|
||||||
View::composer([
|
View::composer([
|
||||||
'home',
|
'home',
|
||||||
|
|
@ -22,7 +24,6 @@ class ViewServiceProvider extends ServiceProvider
|
||||||
'site_name' => option_localized('site_name'),
|
'site_name' => option_localized('site_name'),
|
||||||
'navbar_color' => $color,
|
'navbar_color' => $color,
|
||||||
'color_mode' => in_array($color, $lightColors) ? 'light' : 'dark',
|
'color_mode' => in_array($color, $lightColors) ? 'light' : 'dark',
|
||||||
'dark_mode' => (bool) optional(auth()->user())->is_dark_mode,
|
|
||||||
'locale' => str_replace('_', '-', app()->getLocale()),
|
'locale' => str_replace('_', '-', app()->getLocale()),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
@ -47,11 +48,7 @@ class ViewServiceProvider extends ServiceProvider
|
||||||
View::composer('shared.user-menu', Composers\UserMenuComposer::class);
|
View::composer('shared.user-menu', Composers\UserMenuComposer::class);
|
||||||
|
|
||||||
View::composer('shared.sidebar', function ($view) {
|
View::composer('shared.sidebar', function ($view) {
|
||||||
$isDarkMode = (bool) optional(auth()->user())->is_dark_mode;
|
$view->with('sidebar_color', option('sidebar_color'));
|
||||||
$color = option('sidebar_color');
|
|
||||||
$color = $isDarkMode ? str_replace('light', 'dark', $color) : $color;
|
|
||||||
|
|
||||||
$view->with('sidebar_color', $color);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
View::composer('shared.side-menu', Composers\SideMenuComposer::class);
|
View::composer('shared.side-menu', Composers\SideMenuComposer::class);
|
||||||
|
|
@ -69,14 +66,14 @@ class ViewServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
View::composer('shared.foot', Composers\FootComposer::class);
|
View::composer('shared.foot', Composers\FootComposer::class);
|
||||||
|
|
||||||
View::composer('shared.dark-mode', function ($view) {
|
View::composer(['errors.*', 'setup.*'], function ($view) use ($webpack) {
|
||||||
$view->with([
|
// @codeCoverageIgnoreStart
|
||||||
'dark_mode' => (bool) optional(auth()->user())->is_dark_mode,
|
if (Str::startsWith(config('app.asset.env'), 'dev')) {
|
||||||
]);
|
$view->with(['scripts' => [$webpack->url('spectre.js')]]);
|
||||||
});
|
} else {
|
||||||
|
$view->with('styles', [$webpack->url('spectre.css')]);
|
||||||
View::composer('assets.*', function ($view) {
|
}
|
||||||
$view->with('cdn_base', option('cdn_address', ''));
|
// @codeCoverageIgnoreEnd
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,6 @@ class PlayerName implements Rule
|
||||||
$regexp = '/^[A-Za-z0-9_§\x{4e00}-\x{9fff}]+$/u';
|
$regexp = '/^[A-Za-z0-9_§\x{4e00}-\x{9fff}]+$/u';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'utf8':
|
|
||||||
return mb_check_encoding($value, 'UTF-8') && !preg_match('/\s/', $value);
|
|
||||||
|
|
||||||
case 'custom':
|
case 'custom':
|
||||||
$regexp = option('custom_player_name_regexp') ?: $regexp;
|
$regexp = option('custom_player_name_regexp') ?: $regexp;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ use App\Events;
|
||||||
use App\Notifications;
|
use App\Notifications;
|
||||||
use Blessing\Filter;
|
use Blessing\Filter;
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Event;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\Event;
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Notification;
|
||||||
|
|
||||||
class Hook
|
class Hook
|
||||||
{
|
{
|
||||||
|
|
@ -66,7 +66,9 @@ class Hook
|
||||||
$urls = collect($urls);
|
$urls = collect($urls);
|
||||||
$pages = collect($pages);
|
$pages = collect($pages);
|
||||||
resolve(Filter::class)->add('head_links', function ($links) use ($urls, $pages) {
|
resolve(Filter::class)->add('head_links', function ($links) use ($urls, $pages) {
|
||||||
$matched = $pages->some(fn ($page) => request()->is($page));
|
$matched = $pages->some(function ($page) {
|
||||||
|
return request()->is($page);
|
||||||
|
});
|
||||||
if ($matched) {
|
if ($matched) {
|
||||||
$urls->each(function ($url) use (&$links) {
|
$urls->each(function ($url) use (&$links) {
|
||||||
$links[] = [
|
$links[] = [
|
||||||
|
|
@ -86,7 +88,9 @@ class Hook
|
||||||
$urls = collect($urls);
|
$urls = collect($urls);
|
||||||
$pages = collect($pages);
|
$pages = collect($pages);
|
||||||
resolve(Filter::class)->add('scripts', function ($scripts) use ($urls, $pages) {
|
resolve(Filter::class)->add('scripts', function ($scripts) use ($urls, $pages) {
|
||||||
$matched = $pages->some(fn ($page) => request()->is($page));
|
$matched = $pages->some(function ($page) {
|
||||||
|
return request()->is($page);
|
||||||
|
});
|
||||||
if ($matched) {
|
if ($matched) {
|
||||||
$urls->each(function ($url) use (&$scripts) {
|
$urls->each(function ($url) use (&$scripts) {
|
||||||
$scripts[] = ['src' => $url, 'crossorigin' => 'anonymous'];
|
$scripts[] = ['src' => $url, 'crossorigin' => 'anonymous'];
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use DB;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Filesystem\Filesystem;
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class Option
|
class Option
|
||||||
{
|
{
|
||||||
|
|
@ -20,14 +20,13 @@ class Option
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists(storage_path('install.lock')) || app()->runningUnitTests()) {
|
try {
|
||||||
|
$this->items = DB::table('options')->get()->mapWithKeys(function ($item) {
|
||||||
|
return [$item->option_name => $item->option_value];
|
||||||
|
});
|
||||||
|
} catch (QueryException $e) {
|
||||||
$this->items = collect();
|
$this->items = collect();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->items = DB::table('options')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(fn ($item) => [$item->option_name => $item->option_value]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get($key, $default = null, $raw = false)
|
public function get($key, $default = null, $raw = false)
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use App\Services\Facades\Option;
|
|
||||||
use BadMethodCallException;
|
use BadMethodCallException;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Option;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -21,7 +21,7 @@ class OptionForm
|
||||||
* Pass this value to tell generator to
|
* Pass this value to tell generator to
|
||||||
* load text from language files automatically.
|
* load text from language files automatically.
|
||||||
*/
|
*/
|
||||||
public const AUTO_DETECT = 0x97AB1;
|
const AUTO_DETECT = 0x97ab1;
|
||||||
|
|
||||||
protected $id;
|
protected $id;
|
||||||
protected $title;
|
protected $title;
|
||||||
|
|
@ -38,7 +38,7 @@ class OptionForm
|
||||||
|
|
||||||
protected $hookBefore;
|
protected $hookBefore;
|
||||||
protected $hookAfter;
|
protected $hookAfter;
|
||||||
protected $alwaysCallback;
|
protected $alwaysCallback = null;
|
||||||
|
|
||||||
protected $renderWithoutTable = false;
|
protected $renderWithoutTable = false;
|
||||||
protected $renderInputTagsOnly = false;
|
protected $renderInputTagsOnly = false;
|
||||||
|
|
@ -59,7 +59,7 @@ class OptionForm
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws BadMethodCallException
|
* @throws \BadMethodCallException
|
||||||
*/
|
*/
|
||||||
public function __call(string $method, array $params): OptionFormItem
|
public function __call(string $method, array $params): OptionFormItem
|
||||||
{
|
{
|
||||||
|
|
@ -105,6 +105,7 @@ class OptionForm
|
||||||
* Add a piece of data to the option form.
|
* Add a piece of data to the option form.
|
||||||
*
|
*
|
||||||
* @param string|array $key
|
* @param string|array $key
|
||||||
|
* @param mixed $value
|
||||||
*/
|
*/
|
||||||
public function with($key, $value = null): self
|
public function with($key, $value = null): self
|
||||||
{
|
{
|
||||||
|
|
@ -203,7 +204,7 @@ class OptionForm
|
||||||
/**
|
/**
|
||||||
* Handle the HTTP post request and update modified options.
|
* Handle the HTTP post request and update modified options.
|
||||||
*/
|
*/
|
||||||
public function handle(?callable $callback = null): self
|
public function handle(callable $callback = null): self
|
||||||
{
|
{
|
||||||
$request = request();
|
$request = request();
|
||||||
$allPostData = $request->all();
|
$allPostData = $request->all();
|
||||||
|
|
@ -328,7 +329,7 @@ class OptionForm
|
||||||
$this->assignValues();
|
$this->assignValues();
|
||||||
|
|
||||||
return view('forms.form')
|
return view('forms.form')
|
||||||
->with(get_object_vars($this))
|
->with(array_merge(get_object_vars($this)))
|
||||||
->render();
|
->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,7 +352,7 @@ class OptionFormItem
|
||||||
|
|
||||||
public $format;
|
public $format;
|
||||||
|
|
||||||
public $value;
|
public $value = null;
|
||||||
|
|
||||||
public $disabled;
|
public $disabled;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,25 @@ use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Plugin
|
class Plugin
|
||||||
{
|
{
|
||||||
public const README_FILES = [
|
const README_FILES = [
|
||||||
'README.md',
|
'README.md',
|
||||||
'readme.md',
|
'readme.md',
|
||||||
'README.MD',
|
'README.MD',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** The full path of this plugin. */
|
/**
|
||||||
protected string $path;
|
* The full path of this plugin.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $path;
|
||||||
|
|
||||||
/** package.json of the package. */
|
/**
|
||||||
protected array $manifest;
|
* package.json of the package.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $manifest;
|
||||||
|
|
||||||
protected $enabled = false;
|
protected $enabled = false;
|
||||||
|
|
||||||
|
|
@ -53,10 +61,9 @@ class Plugin
|
||||||
|
|
||||||
public function getReadme()
|
public function getReadme()
|
||||||
{
|
{
|
||||||
return Arr::first(
|
return Arr::first(self::README_FILES, function ($filename) {
|
||||||
self::README_FILES,
|
return file_exists($this->path.'/'.$filename);
|
||||||
fn ($filename) => file_exists($this->path.'/'.$filename)
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasConfig(): bool
|
public function hasConfig(): bool
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,35 @@ use Illuminate\Support\Str;
|
||||||
|
|
||||||
class PluginManager
|
class PluginManager
|
||||||
{
|
{
|
||||||
protected bool $booted = false;
|
/** @var bool */
|
||||||
|
protected $booted = false;
|
||||||
|
|
||||||
protected Application $app;
|
/** @var Application */
|
||||||
|
protected $app;
|
||||||
|
|
||||||
protected Option $option;
|
/** @var Option */
|
||||||
|
protected $option;
|
||||||
|
|
||||||
protected Dispatcher $dispatcher;
|
/** @var Dispatcher */
|
||||||
|
protected $dispatcher;
|
||||||
|
|
||||||
protected Filesystem $filesystem;
|
/** @var Filesystem */
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
protected ClassLoader $loader;
|
/** @var ClassLoader */
|
||||||
|
protected $loader;
|
||||||
|
|
||||||
protected ?Collection $plugins;
|
/** @var Collection|null */
|
||||||
|
protected $plugins;
|
||||||
|
|
||||||
protected Collection $enabled;
|
/** @var Collection */
|
||||||
|
protected $enabled;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Application $app,
|
Application $app,
|
||||||
Option $option,
|
Option $option,
|
||||||
Dispatcher $dispatcher,
|
Dispatcher $dispatcher,
|
||||||
Filesystem $filesystem,
|
Filesystem $filesystem
|
||||||
) {
|
) {
|
||||||
$this->app = $app;
|
$this->app = $app;
|
||||||
$this->option = $option;
|
$this->option = $option;
|
||||||
|
|
@ -48,20 +56,28 @@ class PluginManager
|
||||||
|
|
||||||
public function all(): Collection
|
public function all(): Collection
|
||||||
{
|
{
|
||||||
if (isset($this->plugins)) {
|
if (filled($this->plugins)) {
|
||||||
return $this->plugins;
|
return $this->plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->enabled = collect(json_decode($this->option->get('plugins_enabled', '[]'), true))
|
$this->enabled = collect(json_decode($this->option->get('plugins_enabled', '[]'), true))
|
||||||
->reject(fn ($item) => is_string($item))
|
->reject(function ($item) {
|
||||||
->mapWithKeys(fn ($item) => [$item['name'] => ['version' => $item['version']]]);
|
return is_string($item);
|
||||||
|
})
|
||||||
|
->mapWithKeys(function ($item) {
|
||||||
|
return [$item['name'] => ['version' => $item['version']]];
|
||||||
|
});
|
||||||
$plugins = collect();
|
$plugins = collect();
|
||||||
$versionChanged = [];
|
$versionChanged = [];
|
||||||
|
|
||||||
$this->getPluginsDirs()
|
$this->getPluginsDirs()
|
||||||
->flatMap(fn ($dir) => $this->filesystem->directories($dir))
|
->flatMap(function ($directory) {
|
||||||
|
return $this->filesystem->directories($directory);
|
||||||
|
})
|
||||||
->unique()
|
->unique()
|
||||||
->filter(fn ($dir) => $this->filesystem->exists($dir.DIRECTORY_SEPARATOR.'package.json'))
|
->filter(function ($directory) {
|
||||||
|
return $this->filesystem->exists($directory.DIRECTORY_SEPARATOR.'package.json');
|
||||||
|
})
|
||||||
->each(function ($directory) use (&$plugins, &$versionChanged) {
|
->each(function ($directory) use (&$plugins, &$versionChanged) {
|
||||||
$manifest = json_decode(
|
$manifest = json_decode(
|
||||||
$this->filesystem->get($directory.DIRECTORY_SEPARATOR.'package.json'),
|
$this->filesystem->get($directory.DIRECTORY_SEPARATOR.'package.json'),
|
||||||
|
|
@ -110,12 +126,18 @@ class PluginManager
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->all()->each(fn ($plugin) => $this->loadViewsAndTranslations($plugin));
|
$this->all()->each(function ($plugin) {
|
||||||
|
$this->loadViewsAndTranslations($plugin);
|
||||||
|
});
|
||||||
|
|
||||||
$enabled = $this->getEnabledPlugins();
|
$enabled = $this->getEnabledPlugins();
|
||||||
$enabled->each(fn ($plugin) => $this->registerPlugin($plugin));
|
$enabled->each(function ($plugin) {
|
||||||
|
$this->registerPlugin($plugin);
|
||||||
|
});
|
||||||
$this->loader->register();
|
$this->loader->register();
|
||||||
$enabled->each(fn ($plugin) => $this->bootPlugin($plugin));
|
$enabled->each(function ($plugin) {
|
||||||
|
$this->bootPlugin($plugin);
|
||||||
|
});
|
||||||
$this->registerLifecycleHooks();
|
$this->registerLifecycleHooks();
|
||||||
|
|
||||||
$this->booted = true;
|
$this->booted = true;
|
||||||
|
|
@ -302,7 +324,9 @@ class PluginManager
|
||||||
|
|
||||||
public function getEnabledPlugins(): Collection
|
public function getEnabledPlugins(): Collection
|
||||||
{
|
{
|
||||||
return $this->all()->filter(fn ($plugin) => $plugin->isEnabled());
|
return $this->all()->filter(function ($plugin) {
|
||||||
|
return $plugin->isEnabled();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -310,13 +334,9 @@ class PluginManager
|
||||||
*/
|
*/
|
||||||
protected function saveEnabled()
|
protected function saveEnabled()
|
||||||
{
|
{
|
||||||
$this->option->set(
|
$this->option->set('plugins_enabled', $this->enabled->map(function ($info, $name) {
|
||||||
'plugins_enabled',
|
return array_merge(compact('name'), $info);
|
||||||
$this->enabled
|
})->values()->toJson());
|
||||||
->map(fn ($info, $name) => array_merge(['name' => $name], $info))
|
|
||||||
->values()
|
|
||||||
->toJson()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnsatisfied(Plugin $plugin)
|
public function getUnsatisfied(Plugin $plugin)
|
||||||
|
|
@ -366,7 +386,7 @@ class PluginManager
|
||||||
*/
|
*/
|
||||||
public function formatUnresolved(
|
public function formatUnresolved(
|
||||||
Collection $unsatisfied,
|
Collection $unsatisfied,
|
||||||
Collection $conflicts,
|
Collection $conflicts
|
||||||
): array {
|
): array {
|
||||||
$unsatisfied = $unsatisfied->map(function ($detail, $name) {
|
$unsatisfied = $unsatisfied->map(function ($detail, $name) {
|
||||||
if ($name === 'blessing-skin-server') {
|
if ($name === 'blessing-skin-server') {
|
||||||
|
|
@ -399,7 +419,9 @@ class PluginManager
|
||||||
$config = config('plugins.directory');
|
$config = config('plugins.directory');
|
||||||
if ($config) {
|
if ($config) {
|
||||||
return collect(preg_split('/,\s*/', $config))
|
return collect(preg_split('/,\s*/', $config))
|
||||||
->map(fn ($directory) => realpath($directory) ?: $directory);
|
->map(function ($directory) {
|
||||||
|
return realpath($directory) ?: $directory;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return collect([base_path('plugins')]);
|
return collect([base_path('plugins')]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,21 @@ use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
class JavaScript
|
class JavaScript
|
||||||
{
|
{
|
||||||
protected Filesystem $filesystem;
|
/** @var Filesystem */
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
protected Repository $cache;
|
/** @var Repository */
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
protected PluginManager $plugins;
|
/** @var PluginManager */
|
||||||
|
protected $plugins;
|
||||||
|
|
||||||
protected $prefix = 'front-end-trans-';
|
protected $prefix = 'front-end-trans-';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Filesystem $filesystem,
|
Filesystem $filesystem,
|
||||||
Repository $cache,
|
Repository $cache,
|
||||||
PluginManager $plugins,
|
PluginManager $plugins
|
||||||
) {
|
) {
|
||||||
$this->filesystem = $filesystem;
|
$this->filesystem = $filesystem;
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
|
@ -31,10 +34,16 @@ class JavaScript
|
||||||
{
|
{
|
||||||
$plugins = $this->plugins->getEnabledPlugins();
|
$plugins = $this->plugins->getEnabledPlugins();
|
||||||
$sourceFiles = $plugins
|
$sourceFiles = $plugins
|
||||||
->map(fn (Plugin $plugin) => $plugin->getPath()."/lang/$locale/front-end.yml")
|
->map(function (Plugin $plugin) use ($locale) {
|
||||||
->filter(fn ($path) => $this->filesystem->exists($path));
|
return $plugin->getPath()."/lang/$locale/front-end.yml";
|
||||||
|
})
|
||||||
|
->filter(function ($path) {
|
||||||
|
return $this->filesystem->exists($path);
|
||||||
|
});
|
||||||
$sourceFiles->push(resource_path("lang/$locale/front-end.yml"));
|
$sourceFiles->push(resource_path("lang/$locale/front-end.yml"));
|
||||||
$sourceModified = $sourceFiles->max(fn ($path) => $this->filesystem->lastModified($path));
|
$sourceModified = $sourceFiles->max(function ($path) {
|
||||||
|
return $this->filesystem->lastModified($path);
|
||||||
|
});
|
||||||
|
|
||||||
$compiled = public_path("lang/$locale.js");
|
$compiled = public_path("lang/$locale.js");
|
||||||
$compiledModified = (int) $this->cache->get($this->prefix.$locale, 0);
|
$compiledModified = (int) $this->cache->get($this->prefix.$locale, 0);
|
||||||
|
|
@ -42,7 +51,10 @@ class JavaScript
|
||||||
if ($sourceModified > $compiledModified || !$this->filesystem->exists($compiled)) {
|
if ($sourceModified > $compiledModified || !$this->filesystem->exists($compiled)) {
|
||||||
$translations = trans('front-end');
|
$translations = trans('front-end');
|
||||||
foreach ($plugins as $plugin) {
|
foreach ($plugins as $plugin) {
|
||||||
$translations[$plugin->name] = trans($plugin->namespace.'::front-end');
|
$translations = array_merge(
|
||||||
|
$translations,
|
||||||
|
[$plugin->name => trans($plugin->namespace.'::front-end')]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = 'blessing.i18n = '.json_encode($translations, JSON_UNESCAPED_UNICODE);
|
$content = 'blessing.i18n = '.json_encode($translations, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,14 @@ use Spatie\TranslationLoader\TranslationLoaderManager;
|
||||||
|
|
||||||
class Loader extends TranslationLoaderManager
|
class Loader extends TranslationLoaderManager
|
||||||
{
|
{
|
||||||
protected function loadPaths(array $paths, $locale, $group)
|
protected function loadPath($path, $locale, $group)
|
||||||
{
|
{
|
||||||
return collect($paths)
|
$translations = parent::loadPath($path, $locale, $group);
|
||||||
->reduce(function ($output, $path) use ($locale, $group) {
|
|
||||||
if ($this->files->exists($full = "{$path}/{$locale}/{$group}.yml")) {
|
|
||||||
$output = resolve(Yaml::class)->parse($full);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $output;
|
$full = "{$path}/{$locale}/{$group}.yml";
|
||||||
}, []);
|
|
||||||
|
return count($translations) === 0 && $this->files->exists($full)
|
||||||
|
? resolve(Yaml::class)->parse($full)
|
||||||
|
: [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use Symfony\Component\Yaml\Yaml as YamlParser;
|
||||||
|
|
||||||
class Yaml
|
class Yaml
|
||||||
{
|
{
|
||||||
protected Repository $cache;
|
/** @var Repository */
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
protected $prefix = 'yaml-trans-';
|
protected $prefix = 'yaml-trans-';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,11 @@ use ZipArchive;
|
||||||
|
|
||||||
class Unzip
|
class Unzip
|
||||||
{
|
{
|
||||||
protected Filesystem $filesystem;
|
/** @var Filesystem */
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
protected ZipArchive $zipper;
|
/** @var ZipArchive */
|
||||||
|
protected $zipper;
|
||||||
|
|
||||||
public function __construct(Filesystem $filesystem, ZipArchive $zipper)
|
public function __construct(Filesystem $filesystem, ZipArchive $zipper)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
53
app/Services/Webpack.php
Normal file
53
app/Services/Webpack.php
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
use Illuminate\Routing\UrlGenerator;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Webpack
|
||||||
|
{
|
||||||
|
protected $manifest = [];
|
||||||
|
|
||||||
|
/** @var Option */
|
||||||
|
protected $options;
|
||||||
|
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Filesystem $filesystem,
|
||||||
|
Option $options,
|
||||||
|
UrlGenerator $urlGenerator
|
||||||
|
) {
|
||||||
|
$path = public_path('app/manifest.json');
|
||||||
|
if ($filesystem->exists($path)) {
|
||||||
|
$this->manifest = json_decode($filesystem->get($path), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->options = $options;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get(string $path)
|
||||||
|
{
|
||||||
|
return Arr::get($this->manifest, $path, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function url(string $path): string
|
||||||
|
{
|
||||||
|
if (Str::startsWith(config('app.asset.env'), 'dev')) {
|
||||||
|
$root = config('app.asset.url').':8080';
|
||||||
|
|
||||||
|
return $this->urlGenerator->assetFrom($root, $path);
|
||||||
|
} else {
|
||||||
|
$path = $this->$path;
|
||||||
|
$cdn = $this->options->get('cdn_address');
|
||||||
|
|
||||||
|
return $this->urlGenerator->assetFrom($cdn, "/app/$path");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -52,11 +52,21 @@ if (!function_exists('option')) {
|
||||||
* Get / set the specified option value.
|
* Get / set the specified option value.
|
||||||
*
|
*
|
||||||
* If an array is passed as the key, we will assume you want to set an array of values.
|
* If an array is passed as the key, we will assume you want to set an array of values.
|
||||||
|
*
|
||||||
|
* @param array|string $key
|
||||||
|
* @param mixed $default
|
||||||
|
* @param bool $raw return raw value without convertion
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
function option(string|array $key, mixed $default = null, bool $raw = false)
|
function option($key = null, $default = null, $raw = false)
|
||||||
{
|
{
|
||||||
$options = app('options');
|
$options = app('options');
|
||||||
|
|
||||||
|
if (is_null($key)) {
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($key)) {
|
if (is_array($key)) {
|
||||||
$options->set($key);
|
$options->set($key);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,27 @@ ini_set('display_errors', true);
|
||||||
file_put_contents($envPath, preg_replace('/APP_KEY\s*=\s*/', 'APP_KEY='.$key."\n\n", $envFile));
|
file_put_contents($envPath, preg_replace('/APP_KEY\s*=\s*/', 'APP_KEY='.$key."\n\n", $envFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
$requiredVersion = '8.1.0';
|
$requiredFunctions = ['symlink', 'readlink', 'putenv', 'realpath'];
|
||||||
|
$disabledFunctions = preg_split('/,\s*/', ini_get('disable_functions'));
|
||||||
|
foreach ($requiredFunctions as $fn) {
|
||||||
|
if (in_array($fn, $disabledFunctions)) {
|
||||||
|
die_with_utf8_encoding(
|
||||||
|
'[Error] Please don\'t disable built-in function "'.$fn.'", which is specified in "php.ini" file.<br>'.
|
||||||
|
"[错误] 请不要在 php.ini 中禁用 $fn 函数。".
|
||||||
|
'<strong>我们不建议使用您使用宝塔等面板软件,因为容易引起兼容性问题。</strong>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty(ini_get('open_basedir'))) {
|
||||||
|
die_with_utf8_encoding(
|
||||||
|
'[Error] Please disable "open_basedir" option by editing "php.ini" file.<br>'.
|
||||||
|
'[错误] 请修改 php.ini 以关闭 "open_basedir" 选项。'.
|
||||||
|
'<strong>我们不建议使用您使用宝塔等面板软件,因为容易引起兼容性问题。</strong>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requiredVersion = '7.2.5';
|
||||||
preg_match('/(\d+\.\d+\.\d+)/', PHP_VERSION, $matches);
|
preg_match('/(\d+\.\d+\.\d+)/', PHP_VERSION, $matches);
|
||||||
$version = $matches[1];
|
$version = $matches[1];
|
||||||
if (version_compare($version, $requiredVersion, '<')) {
|
if (version_compare($version, $requiredVersion, '<')) {
|
||||||
|
|
@ -51,7 +71,6 @@ ini_set('display_errors', true);
|
||||||
'json',
|
'json',
|
||||||
'fileinfo',
|
'fileinfo',
|
||||||
'zip',
|
'zip',
|
||||||
'imagick',
|
|
||||||
],
|
],
|
||||||
'write_permission' => [
|
'write_permission' => [
|
||||||
'bootstrap/cache',
|
'bootstrap/cache',
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@
|
||||||
"description": "A web application brings your custom skins back in offline Minecraft servers.",
|
"description": "A web application brings your custom skins back in offline Minecraft servers.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1",
|
"php": ">=7.2.5",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-gd": "*",
|
"ext-gd": "*",
|
||||||
"ext-imagick": "*",
|
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
|
|
@ -16,43 +15,46 @@
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"blessing/filter": "^1.0",
|
"blessing/filter": "^1.0",
|
||||||
"blessing/rejection": "^1.0",
|
"blessing/rejection": "^1.0",
|
||||||
"blessing/texture-renderer": "^0.2",
|
"blessing/texture-renderer": "^0.1.1",
|
||||||
"composer/ca-bundle": "^1.2",
|
"composer/ca-bundle": "^1.2",
|
||||||
"composer/semver": "^3.2",
|
"composer/semver": "^1.5",
|
||||||
"doctrine/dbal": "^3.0",
|
"doctrine/dbal": "^2.10",
|
||||||
"doctrine/inflector": "^2.0",
|
"doctrine/inflector": "^1.3",
|
||||||
"spatie/laravel-ignition": "^2.0",
|
"facade/ignition": "^2.0",
|
||||||
"gregwar/captcha": "1.*",
|
"gregwar/captcha": "1.*",
|
||||||
"guzzlehttp/guzzle": "^7.0",
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
"intervention/image": "^2.7",
|
"intervention/image": "^2.5",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^7.0",
|
||||||
"laravel/passport": "^11.0",
|
"laravel/passport": "^9.2",
|
||||||
"lorisleiva/laravel-search-string": "^1.0",
|
"lorisleiva/laravel-search-string": "^0.1.6",
|
||||||
"nesbot/carbon": "^2.0",
|
"nesbot/carbon": "^2.0",
|
||||||
"nunomaduro/collision": "^7.0",
|
"nunomaduro/collision": "^4.1",
|
||||||
"rcrowe/twigbridge": "^0.14",
|
"rcrowe/twigbridge": "^0.11.3",
|
||||||
"spatie/laravel-translation-loader": "^2.7",
|
"spatie/laravel-translation-loader": "^2.6",
|
||||||
"symfony/process": "^6.0",
|
"symfony/process": "^5.0",
|
||||||
"symfony/yaml": "^5.0",
|
"symfony/yaml": "^5.0",
|
||||||
"twig/twig": "^3.0",
|
"twig/twig": "^2.11",
|
||||||
"vectorface/whip": "^0.4.0"
|
"tymon/jwt-auth": "dev-develop",
|
||||||
|
"vectorface/whip": "^0.3.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"barryvdh/laravel-debugbar": "^3.5",
|
"barryvdh/laravel-debugbar": "^3.2",
|
||||||
"barryvdh/laravel-ide-helper": "^2.10",
|
"fzaninotto/faker": "~1.9",
|
||||||
"fakerphp/faker": "^1.13",
|
"laravel/browser-kit-testing": "^6.0",
|
||||||
"friendsofphp/php-cs-fixer": "^3.13",
|
"laravel/tinker": "^2.2",
|
||||||
"laravel/browser-kit-testing": "^7.0",
|
"mockery/mockery": "1.3.*",
|
||||||
"laravel/tinker": "^2.4",
|
"phpdocumentor/reflection-docblock": "^5.1",
|
||||||
"mockery/mockery": "^1.4",
|
"phpunit/phpunit": "^8.5",
|
||||||
"phpunit/phpunit": "^10.0",
|
"symfony/css-selector": "^5.0",
|
||||||
"symfony/css-selector": "^6.2",
|
"symfony/dom-crawler": "^5.0"
|
||||||
"symfony/dom-crawler": "^6.2"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"app/Models",
|
||||||
|
"database"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "app/",
|
"App\\": "app/"
|
||||||
"Database\\Factories\\": "database/factories/"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"app/helpers.php"
|
"app/helpers.php"
|
||||||
|
|
@ -71,7 +73,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
|
||||||
"preferred-install": "dist",
|
"preferred-install": "dist",
|
||||||
"sort-packages": true
|
"sort-packages": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
20799
composer.lock
generated
20799
composer.lock
generated
File diff suppressed because it is too large
Load Diff
118
config/app.php
118
config/app.php
|
|
@ -1,8 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -12,8 +9,7 @@ return [
|
||||||
| Version of Blessing Skin Server.
|
| Version of Blessing Skin Server.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
'version' => '5.2.0',
|
||||||
'version' => '6.0.2',
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -23,24 +19,12 @@ return [
|
||||||
| Where to get information of new versions.
|
| Where to get information of new versions.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'update_source' => env(
|
'update_source' => env(
|
||||||
'UPDATE_SOURCE',
|
'UPDATE_SOURCE',
|
||||||
'https://dev.azure.com/blessing-skin/51010f6d-9f99-40f1-a262-0a67f788df32/_apis/git/'.
|
'https://dev.azure.com/blessing-skin/51010f6d-9f99-40f1-a262-0a67f788df32/_apis/git/'.
|
||||||
'repositories/a9ff8df7-6dc3-4ff8-bb22-4871d3a43936/Items?path=%2Fupdate.json'
|
'repositories/a9ff8df7-6dc3-4ff8-bb22-4871d3a43936/Items?path=%2Fupdate.json'
|
||||||
),
|
),
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application Name
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This value is the name of your application. This value is used when the
|
|
||||||
| framework needs to place the application's name in a notification or
|
|
||||||
| any other location as required by the application or its packages.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'name' => env('APP_NAME', 'blessing_skin'),
|
'name' => env('APP_NAME', 'blessing_skin'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -82,6 +66,19 @@ return [
|
||||||
|
|
||||||
'url' => env('APP_URL', 'http://localhost'),
|
'url' => env('APP_URL', 'http://localhost'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Assets
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is related to front-end assets. The asset URL is only available for
|
||||||
|
| development, not for production.
|
||||||
|
*/
|
||||||
|
'asset' => [
|
||||||
|
'env' => env('ASSET_ENV', 'production'),
|
||||||
|
'url' => env('ASSET_URL', 'http://localhost'),
|
||||||
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application Timezone
|
| Application Timezone
|
||||||
|
|
@ -149,24 +146,6 @@ return [
|
||||||
|
|
||||||
'cipher' => 'AES-256-CBC',
|
'cipher' => 'AES-256-CBC',
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Maintenance Mode Driver
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| These configuration options determine the driver used to determine and
|
|
||||||
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
|
||||||
| allow maintenance mode to be controlled across multiple machines.
|
|
||||||
|
|
|
||||||
| Supported drivers: "file", "cache"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'maintenance' => [
|
|
||||||
'driver' => 'file',
|
|
||||||
// 'store' => 'redis',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Autoloaded Service Providers
|
| Autoloaded Service Providers
|
||||||
|
|
@ -178,21 +157,39 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'providers' => ServiceProvider::defaultProviders()->merge([
|
'providers' => [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Package Service Providers...
|
* Laravel Framework Service Providers...
|
||||||
*/
|
*/
|
||||||
|
Illuminate\Auth\AuthServiceProvider::class,
|
||||||
|
Illuminate\Bus\BusServiceProvider::class,
|
||||||
|
Illuminate\Cache\CacheServiceProvider::class,
|
||||||
|
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
|
||||||
|
Illuminate\Cookie\CookieServiceProvider::class,
|
||||||
|
Illuminate\Database\DatabaseServiceProvider::class,
|
||||||
|
Illuminate\Encryption\EncryptionServiceProvider::class,
|
||||||
|
Illuminate\Filesystem\FilesystemServiceProvider::class,
|
||||||
|
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
|
||||||
|
Illuminate\Hashing\HashServiceProvider::class,
|
||||||
|
Illuminate\Mail\MailServiceProvider::class,
|
||||||
|
Illuminate\Notifications\NotificationServiceProvider::class,
|
||||||
|
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||||
|
Illuminate\Queue\QueueServiceProvider::class,
|
||||||
|
Illuminate\Redis\RedisServiceProvider::class,
|
||||||
|
Illuminate\Session\SessionServiceProvider::class,
|
||||||
|
Illuminate\Validation\ValidationServiceProvider::class,
|
||||||
|
Illuminate\View\ViewServiceProvider::class,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Application Service Providers...
|
* Application Service Providers...
|
||||||
*/
|
*/
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\AuthServiceProvider::class,
|
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\PluginServiceProvider::class,
|
App\Providers\PluginServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
App\Providers\ViewServiceProvider::class,
|
App\Providers\ViewServiceProvider::class,
|
||||||
])->toArray(),
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -205,7 +202,44 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'aliases' => Facade::defaultAliases()->merge([
|
'aliases' => [
|
||||||
'Option' => App\Services\Facades\Option::class,
|
|
||||||
])->toArray(),
|
'App' => Illuminate\Support\Facades\App::class,
|
||||||
|
'Artisan' => Illuminate\Support\Facades\Artisan::class,
|
||||||
|
'Auth' => Illuminate\Support\Facades\Auth::class,
|
||||||
|
'Blade' => Illuminate\Support\Facades\Blade::class,
|
||||||
|
'Cache' => Illuminate\Support\Facades\Cache::class,
|
||||||
|
'Config' => Illuminate\Support\Facades\Config::class,
|
||||||
|
'Cookie' => Illuminate\Support\Facades\Cookie::class,
|
||||||
|
'Crypt' => Illuminate\Support\Facades\Crypt::class,
|
||||||
|
'DB' => Illuminate\Support\Facades\DB::class,
|
||||||
|
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
|
||||||
|
'Event' => Illuminate\Support\Facades\Event::class,
|
||||||
|
'File' => Illuminate\Support\Facades\File::class,
|
||||||
|
'Gate' => Illuminate\Support\Facades\Gate::class,
|
||||||
|
'Hash' => Illuminate\Support\Facades\Hash::class,
|
||||||
|
'Http' => Illuminate\Support\Facades\Http::class,
|
||||||
|
'Lang' => Illuminate\Support\Facades\Lang::class,
|
||||||
|
'Log' => Illuminate\Support\Facades\Log::class,
|
||||||
|
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||||
|
'Notification' => Illuminate\Support\Facades\Notification::class,
|
||||||
|
'Password' => Illuminate\Support\Facades\Password::class,
|
||||||
|
'Queue' => Illuminate\Support\Facades\Queue::class,
|
||||||
|
'Redirect' => Illuminate\Support\Facades\Redirect::class,
|
||||||
|
'Request' => Illuminate\Support\Facades\Request::class,
|
||||||
|
'Response' => Illuminate\Support\Facades\Response::class,
|
||||||
|
'Route' => Illuminate\Support\Facades\Route::class,
|
||||||
|
'Schema' => Illuminate\Support\Facades\Schema::class,
|
||||||
|
'Session' => Illuminate\Support\Facades\Session::class,
|
||||||
|
'Storage' => Illuminate\Support\Facades\Storage::class,
|
||||||
|
'URL' => Illuminate\Support\Facades\URL::class,
|
||||||
|
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||||
|
'View' => Illuminate\Support\Facades\View::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Blessing Skin
|
||||||
|
*/
|
||||||
|
'Option' => App\Services\Facades\Option::class,
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Authentication Defaults
|
| Authentication Defaults
|
||||||
|
|
@ -102,4 +103,5 @@ return [
|
||||||
'expire' => 60,
|
'expire' => 60,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Default Broadcaster
|
| Default Broadcaster
|
||||||
|
|
@ -10,7 +11,7 @@ return [
|
||||||
| framework when an event needs to be broadcast. You may set this to
|
| framework when an event needs to be broadcast. You may set this to
|
||||||
| any of the connections defined in the "connections" array below.
|
| any of the connections defined in the "connections" array below.
|
||||||
|
|
|
|
||||||
| Supported: "pusher", "ably", "redis", "log", "null"
|
| Supported: "pusher", "redis", "log", "null"
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'connections' => [
|
'connections' => [
|
||||||
|
|
||||||
'pusher' => [
|
'pusher' => [
|
||||||
'driver' => 'pusher',
|
'driver' => 'pusher',
|
||||||
'key' => env('PUSHER_APP_KEY'),
|
'key' => env('PUSHER_APP_KEY'),
|
||||||
|
|
@ -35,20 +37,8 @@ return [
|
||||||
'app_id' => env('PUSHER_APP_ID'),
|
'app_id' => env('PUSHER_APP_ID'),
|
||||||
'options' => [
|
'options' => [
|
||||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
'useTLS' => true,
|
||||||
'port' => env('PUSHER_PORT', 443),
|
|
||||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
|
||||||
'encrypted' => true,
|
|
||||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
|
||||||
],
|
],
|
||||||
'client_options' => [
|
|
||||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
'ably' => [
|
|
||||||
'driver' => 'ably',
|
|
||||||
'key' => env('ABLY_KEY'),
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'redis' => [
|
'redis' => [
|
||||||
|
|
@ -63,5 +53,7 @@ return [
|
||||||
'null' => [
|
'null' => [
|
||||||
'driver' => 'null',
|
'driver' => 'null',
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Default Cache Store
|
| Default Cache Store
|
||||||
|
|
@ -12,6 +13,9 @@ return [
|
||||||
| using this caching library. This connection is used when another is
|
| using this caching library. This connection is used when another is
|
||||||
| not explicitly specified when executing a given caching function.
|
| not explicitly specified when executing a given caching function.
|
||||||
|
|
|
|
||||||
|
| Supported: "apc", "array", "database", "file",
|
||||||
|
| "memcached", "redis", "dynamodb"
|
||||||
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('CACHE_DRIVER', 'file'),
|
'default' => env('CACHE_DRIVER', 'file'),
|
||||||
|
|
@ -25,12 +29,10 @@ return [
|
||||||
| well as their drivers. You may even define multiple stores for the
|
| well as their drivers. You may even define multiple stores for the
|
||||||
| same cache driver to group types of items stored in your caches.
|
| same cache driver to group types of items stored in your caches.
|
||||||
|
|
|
|
||||||
| Supported drivers: "apc", "array", "database", "file",
|
|
||||||
| "memcached", "redis", "dynamodb", "octane", "null"
|
|
||||||
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'stores' => [
|
'stores' => [
|
||||||
|
|
||||||
'apc' => [
|
'apc' => [
|
||||||
'driver' => 'apc',
|
'driver' => 'apc',
|
||||||
],
|
],
|
||||||
|
|
@ -44,13 +46,11 @@ return [
|
||||||
'driver' => 'database',
|
'driver' => 'database',
|
||||||
'table' => 'cache',
|
'table' => 'cache',
|
||||||
'connection' => null,
|
'connection' => null,
|
||||||
'lock_connection' => null,
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'file' => [
|
'file' => [
|
||||||
'driver' => 'file',
|
'driver' => 'file',
|
||||||
'path' => storage_path('framework/cache/data'),
|
'path' => storage_path('framework/cache/data'),
|
||||||
'lock_path' => storage_path('framework/cache/data'),
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'memcached' => [
|
'memcached' => [
|
||||||
|
|
@ -75,7 +75,6 @@ return [
|
||||||
'redis' => [
|
'redis' => [
|
||||||
'driver' => 'redis',
|
'driver' => 'redis',
|
||||||
'connection' => 'cache',
|
'connection' => 'cache',
|
||||||
'lock_connection' => 'default',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'dynamodb' => [
|
'dynamodb' => [
|
||||||
|
|
@ -87,9 +86,6 @@ return [
|
||||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||||
],
|
],
|
||||||
|
|
||||||
'octane' => [
|
|
||||||
'driver' => 'octane',
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -97,11 +93,12 @@ return [
|
||||||
| Cache Key Prefix
|
| Cache Key Prefix
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| When utilizing the APC, database, memcached, Redis, or DynamoDB cache
|
| When utilizing a RAM based store such as APC or Memcached, there might
|
||||||
| stores there might be other applications using the same cache. For
|
| be other applications utilizing the same cache. So, we'll specify a
|
||||||
| that reason, you may prefix every cache key to avoid collisions.
|
| value to get prefixed to all our keys so we can avoid collisions.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'blessing_skin'), '_').'_cache_'),
|
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'blessing_skin'), '_').'_cache'),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Default Database Connection Name
|
| Default Database Connection Name
|
||||||
|
|
@ -33,6 +34,7 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'connections' => [
|
'connections' => [
|
||||||
|
|
||||||
'sqlite' => [
|
'sqlite' => [
|
||||||
'driver' => 'sqlite',
|
'driver' => 'sqlite',
|
||||||
'url' => env('DATABASE_URL'),
|
'url' => env('DATABASE_URL'),
|
||||||
|
|
@ -54,7 +56,7 @@ return [
|
||||||
'collation' => 'utf8mb4_unicode_ci',
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
'prefix' => env('DB_PREFIX', ''),
|
'prefix' => env('DB_PREFIX', ''),
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
'strict' => true,
|
'strict' => false,
|
||||||
'engine' => null,
|
'engine' => null,
|
||||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
|
@ -72,7 +74,7 @@ return [
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
'prefix' => env('DB_PREFIX', ''),
|
'prefix' => env('DB_PREFIX', ''),
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
'search_path' => 'public',
|
'schema' => 'public',
|
||||||
'sslmode' => 'prefer',
|
'sslmode' => 'prefer',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
@ -87,9 +89,8 @@ return [
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
'prefix' => env('DB_PREFIX', ''),
|
'prefix' => env('DB_PREFIX', ''),
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
|
||||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -117,6 +118,7 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'redis' => [
|
'redis' => [
|
||||||
|
|
||||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||||
|
|
||||||
'options' => [
|
'options' => [
|
||||||
|
|
@ -127,8 +129,7 @@ return [
|
||||||
'default' => [
|
'default' => [
|
||||||
'url' => env('REDIS_URL'),
|
'url' => env('REDIS_URL'),
|
||||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
'username' => env('REDIS_USERNAME'),
|
'password' => env('REDIS_PASSWORD', null),
|
||||||
'password' => env('REDIS_PASSWORD'),
|
|
||||||
'port' => env('REDIS_PORT', '6379'),
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
'database' => env('REDIS_DB', '0'),
|
'database' => env('REDIS_DB', '0'),
|
||||||
],
|
],
|
||||||
|
|
@ -136,10 +137,11 @@ return [
|
||||||
'cache' => [
|
'cache' => [
|
||||||
'url' => env('REDIS_URL'),
|
'url' => env('REDIS_URL'),
|
||||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
'username' => env('REDIS_USERNAME'),
|
'password' => env('REDIS_PASSWORD', null),
|
||||||
'password' => env('REDIS_PASSWORD'),
|
|
||||||
'port' => env('REDIS_PORT', '6379'),
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
'database' => env('REDIS_CACHE_DB', '1'),
|
'database' => env('REDIS_CACHE_DB', '1'),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Debugbar Settings
|
| Debugbar Settings
|
||||||
|
|
@ -15,8 +16,7 @@ return [
|
||||||
|
|
||||||
'enabled' => env('DEBUGBAR_ENABLED', null),
|
'enabled' => env('DEBUGBAR_ENABLED', null),
|
||||||
'except' => [
|
'except' => [
|
||||||
'telescope*',
|
//
|
||||||
'horizon*',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -32,57 +32,13 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'storage' => [
|
'storage' => [
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'driver' => 'file', // redis, file, pdo, socket, custom
|
'driver' => 'file', // redis, file, pdo, custom
|
||||||
'path' => storage_path('debugbar'), // For file driver
|
'path' => storage_path('debugbar'), // For file driver
|
||||||
'connection' => null, // Leave null for default connection (Redis/PDO)
|
'connection' => null, // Leave null for default connection (Redis/PDO)
|
||||||
'provider' => '', // Instance of StorageInterface for custom driver
|
'provider' => '', // Instance of StorageInterface for custom driver
|
||||||
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
|
|
||||||
'port' => 2304, // Port to use with the "socket" driver
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Editor
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Choose your preferred editor to use when clicking file name.
|
|
||||||
|
|
|
||||||
| Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote",
|
|
||||||
| "vscode-insiders-remote", "vscodium", "textmate", "emacs",
|
|
||||||
| "sublime", "atom", "nova", "macvim", "idea", "netbeans",
|
|
||||||
| "xdebug", "espresso"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'editor' => env('DEBUGBAR_EDITOR', 'phpstorm'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Remote Path Mapping
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| If you are using a remote dev server, like Laravel Homestead, Docker, or
|
|
||||||
| even a remote VPS, it will be necessary to specify your path mapping.
|
|
||||||
|
|
|
||||||
| Leaving one, or both of these, empty or null will not trigger the remote
|
|
||||||
| URL changes and Debugbar will treat your editor links as local files.
|
|
||||||
|
|
|
||||||
| "remote_sites_path" is an absolute base path for your sites or projects
|
|
||||||
| in Homestead, Vagrant, Docker, or another remote development server.
|
|
||||||
|
|
|
||||||
| Example value: "/home/vagrant/Code"
|
|
||||||
|
|
|
||||||
| "local_sites_path" is an absolute base path for your sites or projects
|
|
||||||
| on your local computer where your IDE or code editor is running on.
|
|
||||||
|
|
|
||||||
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH', ''),
|
|
||||||
'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', ''),
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Vendors
|
| Vendors
|
||||||
|
|
@ -91,7 +47,7 @@ return [
|
||||||
| Vendor files are included by default, but can be set to false.
|
| Vendor files are included by default, but can be set to false.
|
||||||
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
|
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
|
||||||
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
|
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
|
||||||
| and for js: jquery and highlight.js
|
| and for js: jquery and and highlight.js
|
||||||
| So if you want syntax highlighting, set it to true.
|
| So if you want syntax highlighting, set it to true.
|
||||||
| jQuery is set to not conflict with existing jQuery scripts.
|
| jQuery is set to not conflict with existing jQuery scripts.
|
||||||
|
|
|
|
||||||
|
|
@ -108,9 +64,6 @@ return [
|
||||||
| you can use this option to disable sending the data through the headers.
|
| you can use this option to disable sending the data through the headers.
|
||||||
|
|
|
|
||||||
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
||||||
|
|
|
||||||
| Note for your request to be identified as ajax requests they must either send the header
|
|
||||||
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'capture_ajax' => true,
|
'capture_ajax' => true,
|
||||||
|
|
@ -148,29 +101,27 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'collectors' => [
|
'collectors' => [
|
||||||
'phpinfo' => true, // Php version
|
'phpinfo' => true, // Php version
|
||||||
'messages' => true, // Messages
|
'messages' => true, // Messages
|
||||||
'time' => true, // Time Datalogger
|
'time' => true, // Time Datalogger
|
||||||
'memory' => true, // Memory usage
|
'memory' => true, // Memory usage
|
||||||
'exceptions' => true, // Exception displayer
|
'exceptions' => true, // Exception displayer
|
||||||
'log' => true, // Logs from Monolog (merged in messages if enabled)
|
'log' => true, // Logs from Monolog (merged in messages if enabled)
|
||||||
'db' => true, // Show database (PDO) queries and bindings
|
'db' => true, // Show database (PDO) queries and bindings
|
||||||
'views' => true, // Views with their data
|
'views' => true, // Views with their data
|
||||||
'route' => true, // Current route information
|
'route' => true, // Current route information
|
||||||
'auth' => false, // Display Laravel authentication status
|
'auth' => true, // Display Laravel authentication status
|
||||||
'gate' => true, // Display Laravel Gate checks
|
'gate' => false, // Display Laravel Gate checks
|
||||||
'session' => true, // Display session data
|
'session' => true, // Display session data
|
||||||
'symfony_request' => true, // Only one can be enabled..
|
'symfony_request' => true, // Only one can be enabled..
|
||||||
'mail' => true, // Catch mail messages
|
'mail' => false, // Catch mail messages
|
||||||
'laravel' => false, // Laravel version and environment
|
'laravel' => false, // Laravel version and environment
|
||||||
'events' => false, // All events fired
|
'events' => true, // All events fired
|
||||||
'default_request' => false, // Regular or special Symfony request logger
|
'default_request' => false, // Regular or special Symfony request logger
|
||||||
'logs' => false, // Add the latest log messages
|
'logs' => false, // Add the latest log messages
|
||||||
'files' => false, // Show the included files
|
'files' => false, // Show the included files
|
||||||
'config' => false, // Display config settings
|
'config' => false, // Display config settings
|
||||||
'cache' => false, // Display cache events
|
'cache' => false, // Display cache events
|
||||||
'models' => true, // Display models
|
|
||||||
'livewire' => true, // Display Livewire (when available)
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -187,26 +138,20 @@ return [
|
||||||
'show_name' => true, // Also show the users name/email in the debugbar
|
'show_name' => true, // Also show the users name/email in the debugbar
|
||||||
],
|
],
|
||||||
'db' => [
|
'db' => [
|
||||||
'with_params' => true, // Render SQL with the parameters substituted
|
'with_params' => true, // Render SQL with the parameters substituted
|
||||||
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
|
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
|
||||||
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
|
'timeline' => false, // Add the queries to the timeline
|
||||||
'timeline' => false, // Add the queries to the timeline
|
|
||||||
'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
|
|
||||||
'explain' => [ // Show EXPLAIN output on queries
|
'explain' => [ // Show EXPLAIN output on queries
|
||||||
'enabled' => false,
|
'enabled' => false,
|
||||||
'types' => ['SELECT'], // Deprecated setting, is always only SELECT
|
'types' => ['SELECT'], // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+
|
||||||
],
|
],
|
||||||
'hints' => false, // Show hints for common mistakes
|
'hints' => true, // Show hints for common mistakes
|
||||||
'show_copy' => false, // Show copy button next to the query,
|
|
||||||
'slow_threshold' => false, // Only track queries that last longer than this time in ms
|
|
||||||
],
|
],
|
||||||
'mail' => [
|
'mail' => [
|
||||||
'full_log' => false,
|
'full_log' => false,
|
||||||
],
|
],
|
||||||
'views' => [
|
'views' => [
|
||||||
'timeline' => false, // Add the views to the timeline (Experimental)
|
'data' => false, //Note: Can slow down the application, because the data can be quite large..
|
||||||
'data' => false, // Note: Can slow down the application, because the data can be quite large..
|
|
||||||
'exclude_paths' => [], // Add the paths which you don't want to appear in the views
|
|
||||||
],
|
],
|
||||||
'route' => [
|
'route' => [
|
||||||
'label' => true, // show complete route on bar
|
'label' => true, // show complete route on bar
|
||||||
|
|
@ -253,24 +198,4 @@ return [
|
||||||
| To override default domain, specify it as a non-empty value.
|
| To override default domain, specify it as a non-empty value.
|
||||||
*/
|
*/
|
||||||
'route_domain' => null,
|
'route_domain' => null,
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| DebugBar theme
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Switches between light and dark theme. If set to auto it will respect system preferences
|
|
||||||
| Possible values: auto, light, dark
|
|
||||||
*/
|
|
||||||
'theme' => env('DEBUGBAR_THEME', 'auto'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Backtrace stack limit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
|
|
||||||
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
|
|
||||||
*/
|
|
||||||
'debug_backtrace_limit' => 50,
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user