This commit is contained in:
LostInLinearPast 2025-10-27 21:23:20 +08:00
commit dcd3e0a386
276 changed files with 77160 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf

35
.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
HELP.md
target/
.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
out/

19
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.10/apache-maven-3.9.10-bin.zip

259
mvnw vendored Normal file
View File

@ -0,0 +1,259 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Optional ENV vars
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support.
native_path() { printf %s\\n "$1"; }
case "$(uname)" in
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
if [ -n "${JAVA_HOME-}" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi
fi
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

149
mvnw.cmd vendored Normal file
View File

@ -0,0 +1,149 @@
<# : batch portion
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.2
@REM
@REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
if ($env:MAVEN_USER_HOME) {
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
}
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

121
pom.xml Normal file
View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.linearpast</groupId>
<artifactId>MinecraftManager</artifactId>
<version>1.0.1</version>
<name>MinecraftManager</name>
<description>MinecraftManager</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>3.4.0</version> <!-- 使用最新稳定版本 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>io.github.MrGraversen</groupId>
<artifactId>minecraft-rcon</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,13 @@
package com.linearpast.minecraftmanager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MinecraftManagerApplication {
public static void main(String[] args) {
SpringApplication.run(MinecraftManagerApplication.class, args);
}
}

View File

@ -0,0 +1,26 @@
package com.linearpast.minecraftmanager.controller;
import com.linearpast.minecraftmanager.service.impl.EmailServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class EmailController {
@Autowired
private EmailServiceImpl emailServiceImpl;
@GetMapping("/api/confirm")
public void confirm(@RequestParam String token, HttpServletResponse response) throws IOException {
if(!emailServiceImpl.validateToken(token)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
emailServiceImpl.markTokenAsUsed(token);
response.sendRedirect("/player/emailSuccess");
}
}

View File

@ -0,0 +1,186 @@
package com.linearpast.minecraftmanager.controller;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.service.inter.OperatorsService;
import com.linearpast.minecraftmanager.service.inter.PlayerAnswersService;
import com.linearpast.minecraftmanager.service.inter.PlayersService;
import com.linearpast.minecraftmanager.service.impl.EmailServiceImpl;
import com.linearpast.minecraftmanager.utils.Result;
import com.linearpast.minecraftmanager.utils.config.ConfigLoader;
import com.linearpast.minecraftmanager.utils.http.HttpApiUtils;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller
public class MainController {
@GetMapping("/")
public String index() {
return "redirect:/player/login";
}
@Controller
@RequestMapping("/player")
public static class PlayerAccountController{
@Autowired
private PlayersService playersService;
@Autowired
private EmailServiceImpl emailServiceImpl;
@Autowired
private PlayerAnswersService playerAnswersService;
@PostMapping("/login")
public String login(
@RequestParam(name = "mcName") String mcName,
@RequestParam(name = "qq") String qq,
HttpSession session,
RedirectAttributes redirectAttributes
) {
String uuid = HttpApiUtils.minecraftAccountQuery(mcName);
boolean matches = qq.matches("^\\d+$");
if(uuid == null || !matches) {
redirectAttributes.addAttribute("error", "不存在该玩家或qq号");
return "redirect:/player/login";
}
Players player = playersService.getPlayer(mcName);
Players playerIsApply = playersService.getPlayerIsApply(mcName, qq);
if(player != null && !qq.equals(player.getQq())) {
redirectAttributes.addAttribute("error", "玩家" + mcName + "已经被qq用户" + player.getQq() + "申请过白名单");
return "redirect:/player/login";
}
try {
if(!playerIsApply.getConfirmationEmail().getActive()){
playersService.forceDeletePlayer(List.of(playerIsApply.getId()));
emailServiceImpl.deleteConfirmationEmail(playerIsApply.getConfirmationEmail().getId());
redirectAttributes.addAttribute("error", "未验证邮件,已清空数据,请重新登陆");
return "redirect:/player/login";
}
}catch (Exception ignored) {}
if(playerIsApply != null){
session.setAttribute("apply", playerIsApply.getStatus());
if(playerIsApply.getStatus() == (byte) 1 || playerIsApply.getStatus() == (byte) 3){
Integer score = playersService.getPlayerScoreById(playerIsApply.getId());
if(score != null) {
session.setAttribute("score", score);
}
}
}
session.setAttribute("qq", qq);
session.setAttribute("mcName", mcName);
session.setAttribute("isLoggedIn", true);
session.setAttribute("uuid", uuid);
return "redirect:/player/home";
}
@GetMapping("/home")
public String home(Model model, HttpSession session) {
String qq = (String) session.getAttribute("qq");
String base64 = HttpApiUtils.qqAvatarQuery(qq);
if(base64 != null) model.addAttribute("avatar", base64);
return "player/apply";
}
@GetMapping
public String index(){
return "redirect:/player/login";
}
@GetMapping("/login")
public String adminLoginIndex(@RequestParam(name = "error", required = false) String error, Model model){
model.addAttribute("error", error);
return "player/login";
}
@GetMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/player/login";
}
@GetMapping("/emailSuccess")
public String emailSuccess(){
return "player/email-success";
}
}
@Controller
@RequestMapping("/admin")
public static class AdminAccountController{
@Autowired
private OperatorsService operatorsService;
@Autowired
private PlayersService playersService;
@PostMapping("/login")
public String adminLogin(
@RequestParam(name = "username") String username,
@RequestParam(name = "password") String password,
HttpSession session,
RedirectAttributes redirectAttributes
){
Operators login = operatorsService.login(username, password);
if(login != null){
session.setAttribute("adminAccount", login);
session.setAttribute("isLoggedIn", true);
return "redirect:/admin/home";
}
redirectAttributes.addAttribute("error", "账号密码错误");
return "redirect:/admin/login";
}
@GetMapping("/welcome")
public String welcome(Model model){
int passCount = playersService.getPlayersCountByStatus((byte) 1);
int unmarkCount = playersService.getPlayersCountByStatus((byte) 2);
int denyCount = playersService.getPlayersCountByStatus((byte) 3);
model.addAttribute("email", ConfigLoader.config.get("spring.mail.username"));
model.addAttribute("passCount", passCount);
model.addAttribute("unmarkCount", unmarkCount);
model.addAttribute("denyCount", denyCount);
return "admin/welcome-page";
}
@GetMapping("/home")
public String home(){
return "admin/index";
}
@GetMapping("/add")
public String add(){
return "admin/add-operator";
}
@GetMapping
public String index(){
return "redirect:/admin/login";
}
@GetMapping("/login")
public String adminLoginIndex(@RequestParam(name = "error", required = false) String error, Model model){
model.addAttribute("error", error);
return "admin/login";
}
@ResponseBody
@GetMapping("/logout")
public Result<?> logout(HttpSession session){
session.invalidate();
return Result.success();
}
@GetMapping("/application")
public String application(){
return "admin/apply-manager";
}
@GetMapping("/questions")
public String question(){
return "admin/question-manager";
}
@GetMapping("/answers")
public String answers(){
return "admin/answer-manager";
}
}
}

View File

@ -0,0 +1,33 @@
package com.linearpast.minecraftmanager.controller;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.service.inter.OperatorsService;
import com.linearpast.minecraftmanager.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/operators")
public class OperatorController {
@Autowired
private OperatorsService operatorsService;
@PostMapping("/save")
public Result<?> save(@RequestBody Operators operators) {
if(!StringUtils.hasText(operators.getNickname()) ||
!StringUtils.hasText(operators.getPassword()) ||
!StringUtils.hasText(operators.getUsername()) ||
!StringUtils.hasText(operators.getRoleName())) {
return Result.error("错误");
}
if(operators.getUsername().length() <= 3) return Result.error("用户名应该大于3字符");
if(operators.getPassword().length() < 8 || operators.getPassword().matches("([0-9]{8,})|([a-zA-Z]){8,}"))
return Result.error("密码应同时包含数字和字母且至少8个字符");
Operators save = operatorsService.save(operators);
return save == null ? Result.error("服务器错误") : Result.success();
}
}

View File

@ -0,0 +1,107 @@
package com.linearpast.minecraftmanager.controller;
import com.linearpast.minecraftmanager.entity.PlayerAnswers;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.entity.dto.ManagerAnswerDTO;
import com.linearpast.minecraftmanager.entity.dto.MarkingScoreDTO;
import com.linearpast.minecraftmanager.entity.dto.SearchAnswerDTO;
import com.linearpast.minecraftmanager.entity.view.PlayerInfoView;
import com.linearpast.minecraftmanager.service.inter.PlayerAnswersService;
import com.linearpast.minecraftmanager.service.inter.PlayersService;
import com.linearpast.minecraftmanager.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/playerAnswer")
public class PlayerAnswerController {
@Autowired
private PlayersService playersService;
@Autowired
private PlayerAnswersService playerAnswersService;
@PostMapping("/markingAnswer")
public Result<?> marking(@RequestBody MarkingScoreDTO markingScoreDTO) {
Integer playerId = markingScoreDTO.getPlayerId();
if(playerId == null) return Result.error("请重新获取数据");
List<PlayerAnswers> playerAnswers = playerAnswersService.getPlayerAnswers(new Players() {{
setId(playerId);
}});
Map<Integer, Integer> scoreMap = new HashMap<>();
for (MarkingScoreDTO.AnswerScore answerScore : markingScoreDTO.getAnswerScore()) {
scoreMap.put(answerScore.getQuestionId(), answerScore.getScore());
}
for (PlayerAnswers playerAnswer : playerAnswers) {
Integer score = scoreMap.get(playerAnswer.getId().getQuestionId());
if(score == null) {
playerAnswer.setScore(null);
continue;
}
playerAnswer.setScore(Math.min(playerAnswer.getQuestions().getScore(), score));
}
List<PlayerAnswers> answers = playerAnswersService.saveAllPlayerAnswers(playerAnswers);
return answers == null ? Result.error("服务器错误") : Result.success();
}
@PostMapping("/getAll")
public Result<?> getAll(@RequestBody SearchAnswerDTO searchAnswerDTO) {
Page<PlayerInfoView> players = playersService.getPlayers(
searchAnswerDTO.getPlayerName(),
searchAnswerDTO.getQq(), null,
searchAnswerDTO.getStatus(),
searchAnswerDTO.getMinValue(),
searchAnswerDTO.getMaxValue(),
PageRequest.of(searchAnswerDTO.getPage() - 1, searchAnswerDTO.getSize())
);
List<ManagerAnswerDTO> result = new ArrayList<>();
List<Integer> playerIds = players.getContent().stream().map(PlayerInfoView::getId).toList();
Map<Integer, List<PlayerAnswers>> answersMap = playerAnswersService.getAllPlayerAnswers(playerIds)
.stream().collect(Collectors.groupingBy(playerAnswers -> playerAnswers.getPlayers().getId()));
for (PlayerInfoView player : players.getContent()) {
List<PlayerAnswers> playerAnswers = answersMap.getOrDefault(player.getId(), List.of());
ManagerAnswerDTO answerDTO = getManagerAnswerDTO(player, playerAnswers);
result.add(answerDTO);
}
return Result.successPage(result, players.getTotalElements());
}
private ManagerAnswerDTO getManagerAnswerDTO(PlayerInfoView player, List<PlayerAnswers> playerAnswers) {
boolean readStatus = true;
Map<Integer, List<PlayerAnswers>> answersMap = new HashMap<>();
int fullScore = 0;
for (PlayerAnswers playerAnswer : playerAnswers) {
int type = playerAnswer.getQuestions().getType();
answersMap.computeIfAbsent(type, k -> new ArrayList<>()).add(playerAnswer);
if(playerAnswer.getScore() == null && type == 3){
readStatus = false;
}
fullScore += playerAnswer.getQuestions().getScore();
}
return new ManagerAnswerDTO(
player.getId(),
player.getPlayerName(),
player.getQq(),
player.getStatus(),
readStatus,
player.getTotalScore(),
fullScore,
answersMap.getOrDefault(1, null),
answersMap.getOrDefault(2, null),
answersMap.getOrDefault(3, null),
player.getEmailActive()
);
}
}

View File

@ -0,0 +1,330 @@
package com.linearpast.minecraftmanager.controller;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.linearpast.minecraftmanager.entity.*;
import com.linearpast.minecraftmanager.entity.dto.*;
import com.linearpast.minecraftmanager.entity.embeddable.PlayerAnswersId;
import com.linearpast.minecraftmanager.entity.view.PlayerInfoView;
import com.linearpast.minecraftmanager.service.inter.PlayerAnswersService;
import com.linearpast.minecraftmanager.service.inter.PlayersService;
import com.linearpast.minecraftmanager.service.inter.QuestionsService;
import com.linearpast.minecraftmanager.service.inter.RegionService;
import com.linearpast.minecraftmanager.service.impl.EmailServiceImpl;
import com.linearpast.minecraftmanager.utils.Result;
import com.linearpast.minecraftmanager.utils.http.HttpApiUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@RestController
@RequestMapping("/api/player")
public class PlayerController {
@Autowired
private PlayersService playersService;
@Autowired
private RegionService regionService;
@Autowired
private EmailServiceImpl emailServiceImpl;
@PostMapping("/getApply")
public Result<?> getApplyPage(
@RequestParam(required = false) String playerName,
@RequestParam(required = false) String qq,
@RequestParam(required = false) String uuid,
@RequestParam(required = false) Byte status,
@RequestParam(required = false) Integer minValue,
@RequestParam(required = false) Integer maxValue,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size
){
Page<PlayerInfoView> playerScores = playersService.getPlayers(
playerName, qq, uuid, status, minValue, maxValue, PageRequest.of(page - 1, size)
);
return Result.successPage(playerScores.getContent(), playerScores.getTotalElements());
}
@DeleteMapping("/delete/{id}")
public Result<?> delete(@PathVariable Integer id){
return playersService.deletePlayer(id) ? Result.success() : Result.error("删除失败不存在玩家或Rcon连接错误");
}
@DeleteMapping("/forceDelete")
public Result<?> forceDelete(@RequestBody List<Integer> ids){
try {
playersService.forceDeletePlayer(ids);
return Result.success();
}catch (Exception ignored){}
return Result.error("删除失败");
}
@PostMapping("/changeStatus")
public Result<?> updateStatus(@RequestBody PlayerStatusDTO playerStatusDTO, HttpSession session){
Operators operators = (Operators) session.getAttribute("adminAccount");
int code = playersService.updatePlayerStatus(playerStatusDTO.getId(), playerStatusDTO.getStatus(), operators);
return code < 1 ? Result.error("操作失败") : Result.success();
}
@DeleteMapping("/batchDelete")
public Result<?> batchDelete(@RequestBody List<Integer> ids){
int code = playersService.deletePlayers(ids);
return code > 0 ? Result.success().msg("操作成功:" + code + "/" + ids.size() + "条数据") :
Result.error("删除失败不存在玩家或Rcon连接错误");
}
@PostMapping("/batchChangeStatus")
public Result<?> batchPass(@RequestBody BatchStatusUpdateDTO dto, HttpSession session){
Operators operators = (Operators) session.getAttribute("adminAccount");
int code = playersService.updatePlayersStatus(dto.getIds(), dto.getStatus(), operators);
return code < 1 ? Result.error("操作失败") : Result.success().msg("操作成功:" + code + "/" + dto.getIds().size() + "条数据");
}
@PostMapping("/save")
public Result<?> save(@RequestBody PlayerSaveDTO players, HttpSession session){
try {
Operators account = (Operators) session.getAttribute("adminAccount");
if(account == null) return Result.error("无权限");
players.setPid(account.getId());
if(players.getId() == null){
Players player = playersService.getPlayer(players.getPlayerName());
if(player != null) return Result.error("玩家"+ player.getPlayerName() +"已存在");
String uuid = HttpApiUtils.minecraftAccountQuery(players.getPlayerName());
if(uuid == null){
return Result.error("非正版账号");
}
Region region = regionService.findRegion(players.getCode(), null, null).get(0);
if(players.getCode() != null){
if(region.getCode() == null) return Result.error("邮政编码错误,不存在该地址");
}
ConfirmationEmail email = new ConfirmationEmail();
email.setActive(true);
ConfirmationEmail confirmationEmail = emailServiceImpl.saveConfirmationEmail(email);
Players newPlayer = new Players();
newPlayer.setPlayerName(players.getPlayerName());
newPlayer.setQq(players.getQq());
newPlayer.setUuid(uuid);
newPlayer.setStatus(players.getStatus());
newPlayer.setDescription(players.getDescription());
newPlayer.setCreateTime(LocalDateTime.parse(players.getCreateTime(),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
);
newPlayer.setRegion(region);
newPlayer.setOperators(account);
newPlayer.setConfirmationEmail(confirmationEmail);
Players result = playersService.savePlayer(newPlayer);
if(result == null) return Result.error("服务器错误");
}else {
Players player = playersService.getPlayerById(players.getId());
if(player == null) return Result.error("玩家不存在");
Players playerByName = playersService.getPlayer(players.getPlayerName());
if(playerByName != null && !Objects.equals(playerByName.getId(), player.getId()))
return Result.error("玩家" + playerByName.getPlayerName() + "已存在");
if(!Objects.equals(player.getRegion().getCode(), players.getCode())){
Region newRegion = regionService.findRegion(players.getCode(), null, null).get(0);
if(players.getCode() != null){
if(newRegion.getCode() == null) return Result.error("邮政编码错误,不存在该地址");
}
player.setRegion(newRegion);
}
String uuid = HttpApiUtils.minecraftAccountQuery(players.getPlayerName());
if(uuid == null){
return Result.error("非正版账号");
}
player.setPlayerName(players.getPlayerName());
player.setQq(players.getQq());
player.setUuid(uuid);
player.setStatus(players.getStatus());
player.setCreateTime(LocalDateTime.parse(players.getCreateTime(),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
);
player.setDescription(players.getDescription());
player.setOperators(account);
Players result = playersService.savePlayer(player);
if(result == null) return Result.error("服务器错误");
}
return Result.success();
}catch (Exception ignored){}
return Result.error("操作失败");
}
@RestController
@RequestMapping("/api/answer")
public static class PlayerAnswerController{
@Autowired
private QuestionsService questionsService;
@Autowired
private PlayersService playersService;
@Autowired
private PlayerAnswersService playerAnswersService;
@Autowired
private EmailServiceImpl emailServiceImpl;
@PostMapping("/getQuestion")
public Result<?> getQuestion(@RequestBody SimpleQuestionDTO questionDTO, HttpSession session){
if(questionDTO.getCode() == null) return Result.error("请选择地址");
if(!StringUtils.hasText(questionDTO.getDescription())) return Result.error("请输入你的来由");
//更新session
session.setAttribute("code", questionDTO.getCode());
session.setAttribute("description", questionDTO.getDescription());
//判断白名单是否已存在该玩家
String playerName = (String)session.getAttribute("mcName");
Players existPlayer = playersService.getPlayer(playerName);
if(existPlayer != null) return Result.error("玩家" + playerName + "已使用qq" + existPlayer.getQq() + "申请过白名单");
//获取所有题目并将数据进行转变以方便前端渲染
List<Questions> allQuestions = questionsService.getAllQuestions();
Map<Integer, List<Questions>> typeGroups = new HashMap<>();
if(allQuestions != null){
//一次遍历将所有题目按类型分到Map
for (Questions question : allQuestions) {
int type = question.getType();
if(type == 1){
String options = question.getOptions();
JsonArray asJsonArray = JsonParser.parseString(options).getAsJsonArray();
JsonArray result = asJsonArray.get(0).getAsJsonArray();
question.setOptions(result.toString());
} else if(type == 2){
String options = question.getOptions();
String processed = options.replaceAll("\\$\\{.*?}", "\\${}");
String[] parts = processed.split("(?<=\\$\\{})|(?=\\$\\{})");
JsonArray result = new Gson().toJsonTree(Arrays.asList(parts)).getAsJsonArray();
question.setOptions(result.toString());
}
typeGroups.computeIfAbsent(type, k -> new ArrayList<>()).add(question);
}
}
//数据存储发送到前端
QuestionListDTO questionListDTO = new QuestionListDTO();
questionListDTO.setOptionQuestions(typeGroups.getOrDefault(1, null));
questionListDTO.setBlankQuestions(typeGroups.getOrDefault(2, null));
questionListDTO.setTextQuestions(typeGroups.getOrDefault(3, null));
return Result.success(questionListDTO);
}
@PostMapping("/putQuestion")
public Result<?> putQuestion(@RequestBody List<PlayerAnswerDTO> answerDTOS, HttpSession session, HttpServletRequest request){
if(answerDTOS != null && !answerDTOS.isEmpty()){
//获取session来添加一个players到数据库
String playerName = (String) session.getAttribute("mcName");
String qq = (String) session.getAttribute("qq");
Long code = (Long) session.getAttribute("code");
String uuid = (String) session.getAttribute("uuid");
String description = (String) session.getAttribute("description");
if(code == null) return Result.error("请重新登陆");
Players player = new Players();
player.setPlayerName(playerName);
player.setQq(qq);
player.setUuid(uuid);
player.setDescription(description);
player.setRegion(new Region(){{setCode(code);}});
player.setCreateTime(LocalDateTime.now());
player.setStatus((byte)2);
Players playerIsApply = playersService.getPlayerIsApply(playerName, qq);
Players players;
if(playerIsApply == null) players = playersService.savePlayer(player);
else players = null;
if(players == null) return Result.error("你已经申请过白名单");
try {
//获取所有问题比对答案计算分数保存答案
List<Questions> allQuestions = questionsService.getAllQuestions();
List<PlayerAnswers> answers = new ArrayList<>();
for (PlayerAnswerDTO answerDTO : answerDTOS) {
Questions questions = allQuestions.stream().filter(q -> q.getId() == answerDTO.getId()).findFirst().orElse(null);
if(questions != null){
PlayerAnswers playerAnswers = new PlayerAnswers();
playerAnswers.setPlayers(players);
playerAnswers.setQuestions(questions);
playerAnswers.setAnswer(answerDTO.getAnswer());
PlayerAnswersId playerAnswersId = new PlayerAnswersId();
playerAnswersId.setPlayerId(players.getId());
playerAnswersId.setQuestionId(questions.getId());
playerAnswers.setId(playerAnswersId);
String answer = answerDTO.getAnswer();
if(answerDTO.getType() == 1){
JsonArray playerAnswer = JsonParser.parseString(answer).getAsJsonArray();
JsonArray options = JsonParser.parseString(questions.getOptions()).getAsJsonArray();
JsonArray correctAnswer = options.get(1).getAsJsonArray();
if(correctAnswer.size() != playerAnswer.size()){
playerAnswers.setScore(0);
}else {
playerAnswers.setScore(questions.getScore());
for (int i = 0; i < correctAnswer.size(); i++) {
if(correctAnswer.get(i).getAsBoolean() != playerAnswer.get(i).getAsBoolean()){
playerAnswers.setScore(0);
break;
}
}
}
}else if (answerDTO.getType() == 2){
List<String> resultList = new ArrayList<>();
JsonArray asJsonArray = JsonParser.parseString(answer).getAsJsonArray();
for (JsonElement element : asJsonArray) {
resultList.add(element.getAsString());
}
String regex = "\\$\\{(.+?)}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(questions.getOptions());
List<String> result = new ArrayList<>();
while (matcher.find()) {
result.add(matcher.group(1));
}
if(resultList.equals(result)){
playerAnswers.setScore(questions.getScore());
}else {
playerAnswers.setScore(0);
}
}
answers.add(playerAnswers);
}
}
List<PlayerAnswers> result = playerAnswersService.saveAllPlayerAnswers(answers);
String token = emailServiceImpl.generateToken(players);
String serverName = request.getServerName();
if(serverName.equals("localhost")) serverName = "127.0.0.1";
String host = String.format("%s://%s:%d", request.getScheme(), serverName, request.getServerPort());
String email = players.getQq() + "@qq.com";
String mcName = players.getPlayerName();
//邮件发送
CompletableFuture.runAsync(() -> {
try {
emailServiceImpl.sendConfirmationEmail(mcName, email, token, host);
} catch (Exception e) {
playerAnswersService.deleteAllPlayerAnswers(players);
playersService.deletePlayer(players.getId());
}
});
//更新session
session.setAttribute("apply", players.getStatus());
if(result != null) return Result.success().msg("请在30分钟内检查邮箱并确认\n未确认将清除申请\n验证前请勿重登本网站\n若未发送邮件请联系管理");
}catch (Exception ignored){
playerAnswersService.deleteAllPlayerAnswers(players);
playersService.deletePlayer(players.getId());
}
}
return Result.error("数据错误");
}
}
}

View File

@ -0,0 +1,79 @@
package com.linearpast.minecraftmanager.controller;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.linearpast.minecraftmanager.entity.Questions;
import com.linearpast.minecraftmanager.entity.dto.QuestionSaveDTO;
import com.linearpast.minecraftmanager.service.inter.QuestionsService;
import com.linearpast.minecraftmanager.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/questions")
public class QuestionController {
@Autowired
private QuestionsService questionsService;
@PostMapping("/save")
public Result<?> saveQuestion(@RequestBody QuestionSaveDTO questionSaveDTO) {
if (questionSaveDTO != null) {
Questions questions = new Questions();
if(questionSaveDTO.getType() == (byte) 1){
JsonArray inputArray = new JsonArray();
JsonArray correct = new JsonArray();
JsonArray asJsonArray = JsonParser.parseString(questionSaveDTO.getOptionsData()).getAsJsonArray();
if(asJsonArray.size() < 2) return Result.error("至少应有两个选项");
boolean hasCorrect = false;
for (JsonElement jsonElement : asJsonArray) {
JsonObject asJsonObject = jsonElement.getAsJsonObject();
boolean check = asJsonObject.get("check").getAsBoolean();
hasCorrect = check || hasCorrect;
correct.add(check);
inputArray.add(asJsonObject.get("input").getAsString());
}
if(!hasCorrect) return Result.error("应至少有一个答案");
JsonArray resultArray = new JsonArray();
resultArray.add(inputArray);
resultArray.add(correct);
questions.setOptions(resultArray.toString());
} else if (questionSaveDTO.getType() == (byte) 2) {
questions.setOptions(questionSaveDTO.getBlankContent());
}
if(questionSaveDTO.getId() != null) questions.setId(questionSaveDTO.getId());
questions.setTitle(questionSaveDTO.getTitle());
questions.setScore(questionSaveDTO.getScore());
questions.setType(questionSaveDTO.getType());
Questions result = questionsService.saveQuestions(questions);
return result == null ? Result.error("服务器错误") : Result.success();
}
return Result.error("错误请求");
}
@PostMapping("/getAll")
public Result<?> getAllQuestions(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size
) {
Page<Questions> questions = questionsService.getQuestions(PageRequest.of(page - 1, size));
return Result.successPage(questions.getContent(), questions.getTotalElements());
}
@DeleteMapping("/delete/{id}")
public Result<?> delete(@PathVariable Integer id){
questionsService.deleteQuestionsById(id);
return Result.success();
}
@DeleteMapping("/batchDelete")
public Result<?> batchDelete(@RequestBody List<Integer> ids){
questionsService.deleteQuestions(ids);
return Result.success();
}
}

View File

@ -0,0 +1,31 @@
package com.linearpast.minecraftmanager.controller;
import com.linearpast.minecraftmanager.entity.Region;
import com.linearpast.minecraftmanager.entity.dto.RegionFindDTO;
import com.linearpast.minecraftmanager.service.inter.RegionService;
import com.linearpast.minecraftmanager.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/region")
public class RegionController {
@Autowired
private RegionService regionService;
@PostMapping("/findRegion")
public Result<?> findRegion(@RequestBody RegionFindDTO regionFindDTO) {
List<Region> region = regionService.findRegion(
regionFindDTO.getCode(),
regionFindDTO.getParentCode(),
regionFindDTO.getLevel()
);
return Result.success(region);
}
}

View File

@ -0,0 +1,24 @@
package com.linearpast.minecraftmanager.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Entity
@Table(name = "confirmation_email")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ConfirmationEmail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String token;
private Boolean used;
@Column(name = "expired_time")
private LocalDateTime expiredTime;
private Boolean active;
}

View File

@ -0,0 +1,23 @@
package com.linearpast.minecraftmanager.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "operators")
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Operators {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Byte permissionLevel;
private String roleName;
private String username;
private String password;
private String nickname;
}

View File

@ -0,0 +1,31 @@
package com.linearpast.minecraftmanager.entity;
import com.linearpast.minecraftmanager.entity.embeddable.PlayerAnswersId;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "player_answers")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PlayerAnswers {
@EmbeddedId
private PlayerAnswersId id;
@ManyToOne
@MapsId("playerId")
@JoinColumn(name = "player_id")
private Players players;
@ManyToOne
@MapsId("questionId")
@JoinColumn(name = "question_id")
private Questions questions;
@Lob
private String answer;
private Integer score;
}

View File

@ -0,0 +1,38 @@
package com.linearpast.minecraftmanager.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "players")
public class Players {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne
@JoinColumn(name = "operator_id")
private Operators operators;
private String playerName;
private String uuid;
private Byte status;
private String qq;
@Column(name = "create_time")
private LocalDateTime createTime;
private String description;
@OneToOne
@JoinColumn(name = "email")
private ConfirmationEmail confirmationEmail;
@ManyToOne
@JoinColumn(name = "region_code")
private Region region;
}

View File

@ -0,0 +1,23 @@
package com.linearpast.minecraftmanager.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "questions")
public class Questions {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private Byte type;
@Lob
private String options;
private Integer score;
}

View File

@ -0,0 +1,25 @@
package com.linearpast.minecraftmanager.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@Table(name = "region")
@AllArgsConstructor
@NoArgsConstructor
public class Region {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long code;
private String name;
private String fullName;
@Column(name = "parent_code")
private Long parentCode;
private Byte level;
}

View File

@ -0,0 +1,13 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class BatchStatusUpdateDTO {
private List<Integer> ids;
private Byte status;
}

View File

@ -0,0 +1,25 @@
package com.linearpast.minecraftmanager.entity.dto;
import com.linearpast.minecraftmanager.entity.PlayerAnswers;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ManagerAnswerDTO {
private Integer id;
private String playerName;
private String qq;
private Byte status;
private Boolean readStatus;
private Integer score;
private Integer fullScore;
private List<PlayerAnswers> optionAnswers;
private List<PlayerAnswers> blankAnswers;
private List<PlayerAnswers> textAnswers;
private Boolean active;
}

View File

@ -0,0 +1,20 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class MarkingScoreDTO {
private Integer playerId;
private List<AnswerScore> answerScore;
@Data
@NoArgsConstructor
public static class AnswerScore{
private Integer questionId;
private Integer score;
}
}

View File

@ -0,0 +1,12 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class PlayerAnswerDTO {
private Integer id;
private String answer;
private Integer type;
}

View File

@ -0,0 +1,18 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class PlayerSaveDTO {
private Integer id;
private String playerName;
private String qq;
private String description;
private Byte status;
private Integer totalScore;
private String createTime;
private Long code;
private Integer pid;
}

View File

@ -0,0 +1,11 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class PlayerStatusDTO {
private Integer id;
private Byte status;
}

View File

@ -0,0 +1,15 @@
package com.linearpast.minecraftmanager.entity.dto;
import com.linearpast.minecraftmanager.entity.Questions;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class QuestionListDTO {
private List<Questions> optionQuestions;
private List<Questions> blankQuestions;
private List<Questions> textQuestions;
}

View File

@ -0,0 +1,15 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class QuestionSaveDTO {
private Byte type;
private Integer score;
private String title;
private String optionsData;
private String blankContent;
private Integer id;
}

View File

@ -0,0 +1,12 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class RegionFindDTO {
private Long code;
private Long parentCode;
private Byte level;
}

View File

@ -0,0 +1,16 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class SearchAnswerDTO {
private String playerName;
private String qq;
private Byte status;
private Integer minValue;
private Integer maxValue;
private Integer page = 1;
private Integer size = 10;
}

View File

@ -0,0 +1,11 @@
package com.linearpast.minecraftmanager.entity.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class SimpleQuestionDTO {
private Long code;
private String description;
}

View File

@ -0,0 +1,21 @@
package com.linearpast.minecraftmanager.entity.embeddable;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PlayerAnswersId implements Serializable {
@Column(name = "player_id")
private int playerId;
@Column(name = "question_id")
private int questionId;
}

View File

@ -0,0 +1,51 @@
package com.linearpast.minecraftmanager.entity.view;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.Immutable;
import java.time.LocalDateTime;
@Entity
@Immutable
@Data
@Table(name = "player_info_view")
public class PlayerInfoView {
@Id
@Column(name = "player_id")
private Integer id;
private String description;
private String uuid;
private Byte status;
private String qq;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "region_code")
private Long regionCode;
@Column(name = "operator_id")
private Integer operatorId;
@Column(name = "player_name")
private String playerName;
@Column(name = "region_full_name")
private String regionFullName;
@Column(name = "operator_username")
private String operatorUsername;
@Column(name = "operator_nickname")
private String operatorNickname;
@Column(name = "total_score")
private Integer totalScore;
@Column(name = "email_active")
private Boolean emailActive;
}

View File

@ -0,0 +1,21 @@
package com.linearpast.minecraftmanager.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UnauthorizedException.class)
public String handlerUnauthorized(UnauthorizedException e){
if(e.getMessage().startsWith("redirect:")){
return e.getMessage();
}
return "error/404.html";
}
@ExceptionHandler(SystemControllerException.class)
public String handlerSystemError(SystemControllerException e){
return "error/500.html";
}
}

View File

@ -0,0 +1,11 @@
package com.linearpast.minecraftmanager.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class SystemControllerException extends RuntimeException{
public SystemControllerException(String message) {
super(message);
}
}

View File

@ -0,0 +1,11 @@
package com.linearpast.minecraftmanager.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException{
public UnauthorizedException(String message){
super(message);
}
}

View File

@ -0,0 +1,25 @@
package com.linearpast.minecraftmanager.interceptor;
import com.linearpast.minecraftmanager.exception.UnauthorizedException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class AdminInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpSession session = request.getSession();
if(
session == null
|| session.getAttribute("isLoggedIn") == null
|| !((boolean) session.getAttribute("isLoggedIn"))
|| session.getAttribute("adminAccount") == null){
throw new UnauthorizedException("redirect:/admin/login?error=please login first");
}
return true;
}
}

View File

@ -0,0 +1,21 @@
package com.linearpast.minecraftmanager.interceptor;
import com.linearpast.minecraftmanager.exception.UnauthorizedException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class PlayerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpSession session = request.getSession();
if(session == null || session.getAttribute("mcName") == null){
throw new UnauthorizedException("redirect:/player/login?error=please login first");
}
return true;
}
}

View File

@ -0,0 +1,37 @@
package com.linearpast.minecraftmanager.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AdminInterceptor adminInterceptor;
@Autowired
private PlayerInterceptor playerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminInterceptor)
.addPathPatterns(
"/admin/**",
"/api/**"
).excludePathPatterns(
"/admin/login/**",
"/api/answer/**",
"/api/confirm",
"/api/region/findRegion"
);
registry.addInterceptor(playerInterceptor)
.addPathPatterns(
"/player/**",
"/api/answer/**"
).excludePathPatterns(
"/player/login/**",
"/player/emailSuccess"
);
}
}

View File

@ -0,0 +1,12 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.ConfirmationEmail;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface ConfirmationEmailRepository extends JpaRepository<ConfirmationEmail, Integer> {
Optional<ConfirmationEmail> findByToken(String token);
}

View File

@ -0,0 +1,10 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.Operators;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface OperatorsRepository extends JpaRepository<Operators, Integer> {
Operators findByUsernameAndPassword(String username, String password);
}

View File

@ -0,0 +1,18 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.PlayerAnswers;
import com.linearpast.minecraftmanager.entity.embeddable.PlayerAnswersId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PlayerAnswersRepository extends JpaRepository<PlayerAnswers, PlayerAnswersId> {
List<PlayerAnswers> findAllByPlayers_Id(Integer playerId);
@Query("SELECT pa FROM PlayerAnswers pa WHERE pa.players.id IN :playerIds")
List<PlayerAnswers> findByPlayerIds(@Param("playerIds") List<Integer> ids);
}

View File

@ -0,0 +1,44 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.entity.Players;
import jakarta.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface PlayersRepository extends JpaRepository<Players, Integer>, JpaSpecificationExecutor<Players> {
Players findByPlayerName(String playerName);
@Transactional
@Modifying
@Query("UPDATE Players p SET p.status = :status WHERE p.id = :id")
int updateStatusById(@Param("id") Integer id, @Param("status") Byte status);
@Transactional
@Modifying
@Query("UPDATE Players p SET p.operators = :operators WHERE p.id = :id")
void updateOperatorsById(@Param("id") Integer id, @Param("operators") Operators operators);
@Modifying
@Transactional
@Query("UPDATE Players p SET p.status = :status, " +
"p.operators = :operators " +
"WHERE p.id IN :ids")
int bulkUpdateStatus(
@Param("ids") List<Integer> ids,
@Param("status") Byte status,
@Param("operators") Operators operators
);
Players findPlayersByPlayerNameAndQq(String playerName, String qq);
Optional<Players> findPlayersByConfirmationEmail_Token(String token);
int countByStatus(Byte status);
}

View File

@ -0,0 +1,9 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.Questions;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface QuestionsRepository extends JpaRepository<Questions, Integer> {
}

View File

@ -0,0 +1,29 @@
package com.linearpast.minecraftmanager.repository;
import com.linearpast.minecraftmanager.entity.Region;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface RegionRepository extends JpaRepository<Region, Long>, JpaSpecificationExecutor<Region> {
class RegionSpecifications {
public static Specification<Region> withDynamicQuery(
Long code, Long parentCode, Byte level) {
return (Root<Region> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
Predicate predicate = cb.conjunction();
if(code != null) predicate = cb.and(predicate, cb.equal(root.get("code"), code));
if(parentCode != null) predicate = cb.and(predicate, cb.equal(root.get("parentCode"), parentCode));
if(level != null) predicate = cb.and(predicate, cb.equal(root.get("level"), level));
return predicate;
};
}
}
}

View File

@ -0,0 +1,39 @@
package com.linearpast.minecraftmanager.repository.view;
import com.linearpast.minecraftmanager.entity.view.PlayerInfoView;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
@Repository
public interface PlayerInfoViewRepository extends JpaRepository<PlayerInfoView, Integer> , JpaSpecificationExecutor<PlayerInfoView> {
PlayerInfoView findById(int id);
class PlayerInfoViewSpecifications {
public static Specification<PlayerInfoView> withDynamicQuery(
String playerName, String qq, String uuid, Byte status, Integer minValue, Integer maxValue) {
return (Root<PlayerInfoView> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
Predicate predicate = cb.conjunction();
if (StringUtils.hasText(playerName)) predicate = cb.and(predicate, cb.like(root.get("playerName"), "%" + playerName + "%"));
if (StringUtils.hasText(qq)) predicate = cb.and(predicate, cb.like(root.get("qq"), "%" + qq + "%"));
if (status != null) predicate = cb.and(predicate, cb.equal(root.get("status"), status));
if (StringUtils.hasText(uuid)) predicate = cb.and(predicate, cb.like(root.get("uuid"), "%" + uuid + "%"));
if (minValue != null && maxValue != null) {
predicate = cb.and(predicate, cb.between(root.get("totalScore"), minValue, maxValue));
}else if(minValue != null){
predicate = cb.and(predicate, cb.ge(root.get("totalScore"), minValue));
}else if(maxValue != null){
predicate = cb.and(predicate, cb.le(root.get("totalScore"), maxValue));
}
return predicate;
};
}
}
}

View File

@ -0,0 +1,20 @@
package com.linearpast.minecraftmanager.service;
import com.linearpast.minecraftmanager.utils.config.SelfConfig;
import com.linearpast.minecraftmanager.utils.rcon.MinecraftRconUtils;
import io.graversen.minecraft.rcon.service.ConnectOptions;
import io.graversen.minecraft.rcon.service.RconDetails;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.time.Duration;
@Service
public class MinecraftRconService {
@Bean
public MinecraftRconUtils rconService(SelfConfig selfConfig) {
RconDetails details = new RconDetails(selfConfig.host, selfConfig.port, selfConfig.password);
ConnectOptions connectOptions = new ConnectOptions(3, Duration.ofSeconds(3L), Duration.ofSeconds(selfConfig.heartTime));
return new MinecraftRconUtils(details, connectOptions);
}
}

View File

@ -0,0 +1,125 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.ConfirmationEmail;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.repository.ConfirmationEmailRepository;
import com.linearpast.minecraftmanager.service.inter.EmailService;
import com.linearpast.minecraftmanager.utils.config.ConfigLoader;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private ConfirmationEmailRepository confirmationEmailRepository;
@Autowired
private PlayerAnswersServiceImpl playerAnswersServiceImpl;
@Autowired
private PlayersServiceImpl playersServiceImpl;
public void sendConfirmationEmail(String mcName, String toEmail, String token, String host) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
// 设置邮件基本信息
helper.setFrom(ConfigLoader.config.get("spring.mail.username")); // 发件人你的QQ邮箱
helper.setTo(toEmail); // 收件人
helper.setSubject("邮箱验证"); // 邮件主题
// 构建HTML邮件内容包含确认链接
String htmlContent = buildHtmlContent(mcName, token, host);
helper.setText(htmlContent, true); // true表示内容是HTML
// 发送邮件
mailSender.send(message);
}
private String buildHtmlContent(String mcName, String token, String host) {
String baseUrl = host + "/api/confirm";
String confirmUrl = baseUrl + "?token=" + token; // 带token的确认链接
// 自定义HTML模板可根据操作类型调整内容
return "<html>"
+ "<head><style>.button{margin-top: 20px;margin-bottom: 20px;padding:10px 20px;background-color:#007bff;color:white;text-decoration:none;border-radius:5px;}</style></head>"
+ "<body>"
+ "<p>您正在进行玩家" + mcName + "的白名单申请操作,请点击按钮确定</p><br><br>"
+ "<a href=\"" + confirmUrl + "\" class=\"button\">点击验证</a>"
+ "<br><br><p>若您未执行此操作,请忽略此邮件。</p>"
+ "<p>链接有效期为30分钟过期后需重新操作。</p>"
+ "</body>"
+ "</html>";
}
public String generateToken(Players players) {
// 生成唯一token使用UUID
String token = UUID.randomUUID().toString();
ConfirmationEmail confirmationToken = players.getConfirmationEmail();
if(confirmationToken == null) confirmationToken = new ConfirmationEmail();
confirmationToken.setToken(token);
confirmationToken.setExpiredTime(LocalDateTime.now().plusMinutes(30));
confirmationToken.setUsed(false);
confirmationToken.setActive(false);
ConfirmationEmail confirmationEmail = this.saveConfirmationEmail(confirmationToken);
players.setConfirmationEmail(confirmationEmail);
playersServiceImpl.savePlayer(players);
return confirmationEmail.getToken();
}
public boolean validateToken(String token) {
Optional<Players> optionalToken = playersServiceImpl.getPlayerByToken(token);
if (optionalToken.isEmpty()) {
return false; // token不存在
}
Players players = optionalToken.get();
ConfirmationEmail confirmationToken = players.getConfirmationEmail();
if (confirmationToken.getUsed()) {
return confirmationToken.getActive(); // token已使用
}
if (confirmationToken.getExpiredTime().isBefore(LocalDateTime.now())) {
playerAnswersServiceImpl.deleteAllPlayerAnswers(players);
playersServiceImpl.deletePlayer(players.getId());
this.deleteConfirmationEmail(confirmationToken.getId());
return false; // token已过期
}
return true; // token有效
}
public void markTokenAsUsed(String token) {
Optional<ConfirmationEmail> optionalToken = this.findConfirmationEmailByToken(token);
optionalToken.ifPresent(tokenEntity -> {
if(tokenEntity.getUsed() && tokenEntity.getActive()) return;
tokenEntity.setUsed(true);
tokenEntity.setActive(true);
this.saveConfirmationEmail(tokenEntity);
});
}
@Override
public ConfirmationEmail saveConfirmationEmail(ConfirmationEmail confirmationEmail) {
return confirmationEmailRepository.save(confirmationEmail);
}
@Override
public Optional<ConfirmationEmail> findConfirmationEmailByToken(String token) {
return confirmationEmailRepository.findByToken(token);
}
@Override
public void deleteConfirmationEmail(Integer id) {
confirmationEmailRepository.deleteById(id);
}
}

View File

@ -0,0 +1,24 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.repository.OperatorsRepository;
import com.linearpast.minecraftmanager.service.inter.OperatorsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OperatorsServiceImpl implements OperatorsService {
@Autowired
private OperatorsRepository operatorsRepository;
@Override
public Operators login(String username, String password) {
return operatorsRepository.findByUsernameAndPassword(username, password);
}
@Override
public Operators save(Operators operators) {
return operatorsRepository.save(operators);
}
}

View File

@ -0,0 +1,37 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.PlayerAnswers;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.repository.PlayerAnswersRepository;
import com.linearpast.minecraftmanager.service.inter.PlayerAnswersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PlayerAnswersServiceImpl implements PlayerAnswersService {
@Autowired
private PlayerAnswersRepository playerAnswersRepository;
@Override
public List<PlayerAnswers> saveAllPlayerAnswers(List<PlayerAnswers> playerAnswers) {
return playerAnswersRepository.saveAll(playerAnswers);
}
@Override
public void deleteAllPlayerAnswers(Players players) {
List<PlayerAnswers> allByPlayersId = playerAnswersRepository.findAllByPlayers_Id(players.getId());
playerAnswersRepository.deleteAll(allByPlayersId);
}
@Override
public List<PlayerAnswers> getPlayerAnswers(Players players) {
return playerAnswersRepository.findAllByPlayers_Id(players.getId());
}
@Override
public List<PlayerAnswers> getAllPlayerAnswers(List<Integer> ids) {
return playerAnswersRepository.findByPlayerIds(ids);
}
}

View File

@ -0,0 +1,292 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.entity.view.PlayerInfoView;
import com.linearpast.minecraftmanager.repository.PlayersRepository;
import com.linearpast.minecraftmanager.repository.view.PlayerInfoViewRepository;
import com.linearpast.minecraftmanager.service.inter.PlayersService;
import com.linearpast.minecraftmanager.utils.WhitelistTarget;
import com.linearpast.minecraftmanager.utils.config.ConfigLoader;
import com.linearpast.minecraftmanager.utils.config.SelfConfig;
import com.linearpast.minecraftmanager.utils.rcon.LoginWhitelistCommand;
import com.linearpast.minecraftmanager.utils.rcon.MinecraftRconUtils;
import com.linearpast.minecraftmanager.utils.rcon.SelfWhiteListCommand;
import io.graversen.minecraft.rcon.MinecraftRcon;
import io.graversen.minecraft.rcon.RconResponse;
import io.graversen.minecraft.rcon.commands.WhiteListCommand;
import io.graversen.minecraft.rcon.service.ConnectOptions;
import io.graversen.minecraft.rcon.service.RconDetails;
import io.graversen.minecraft.rcon.util.Target;
import io.graversen.minecraft.rcon.util.WhiteListModes;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Service
public class PlayersServiceImpl implements PlayersService {
@Autowired
private PlayersRepository playersRepository;
@Autowired
private PlayerInfoViewRepository playerInfoViewRepository;
@Autowired
private MinecraftRconUtils rconService;
@Autowired
private JavaMailSenderImpl mailSender;
@Autowired
private SelfConfig selfConfig;
@Override
public Page<PlayerInfoView> getPlayers(
String playerName,
String qq,
String uuid,
Byte status,
Integer minScore,
Integer maxScore,
Pageable pageable
) {
Specification<PlayerInfoView> spec = PlayerInfoViewRepository.PlayerInfoViewSpecifications
.withDynamicQuery(playerName, qq, uuid, status, minScore, maxScore);
return playerInfoViewRepository.findAll(spec, pageable);
}
@Override
public boolean deletePlayer(Integer id) {
Players byId = playersRepository.findById(id).orElse(null);
if(byId == null) return false;
rconService.connect();
MinecraftRcon minecraftRcon = rconService.minecraftRcon().orElse(null);
if(minecraftRcon == null) return false;
RconResponse response = minecraftRcon.sendSync(new SelfWhiteListCommand(Target.player(byId.getPlayerName()), WhiteListModes.REMOVE));
if(response.getResponseId() != 0) return false;
this.asyncSendEmail(byId, (byte)0, true);
playersRepository.deleteById(id);
return true;
}
@Override
public void forceDeletePlayer(List<Integer> ids) {
playersRepository.deleteAllById(ids);
}
@Override
@Transactional
public int updatePlayerStatus(Integer id, Byte status, Operators operators) {
Players byId = playersRepository.findById(id).orElse(null);
if (byId == null) return 0;
rconService.connect();
RconResponse response;
MinecraftRcon minecraftRcon = rconService.minecraftRcon().orElse(null);
if(minecraftRcon == null) return 0;
if (status == 1) {
response = minecraftRcon.sendSync(new LoginWhitelistCommand(WhitelistTarget.player(byId), WhiteListModes.ADD));
} else {
response = minecraftRcon.sendSync(new SelfWhiteListCommand(Target.player(byId.getPlayerName()), WhiteListModes.REMOVE));
}
if (response.getResponseId() == 0) {
asyncSendEmail(byId, status, false);
playersRepository.updateOperatorsById(id, operators);
return playersRepository.updateStatusById(id, status);
}
return 0;
}
@Override
public Players getPlayer(String playerName) {
return playersRepository.findByPlayerName(playerName);
}
@Override
public Players getPlayerById(Integer id) {
return playersRepository.findById(id).orElse(null);
}
@Override
public Players savePlayer(Players player) {
rconService.connect();
MinecraftRcon minecraftRcon = rconService.minecraftRcon().orElse(null);
if(player.getId() == null){
if(player.getStatus() == 1) {
if(minecraftRcon == null) return null;
RconResponse response = minecraftRcon.sendSync(new LoginWhitelistCommand(WhitelistTarget.player(player), WhiteListModes.ADD));
if(response.getResponseId() != 0) return null;
asyncSendEmail(player, player.getStatus(), false);
}
}else {
Players byId = playersRepository.findById(player.getId()).orElse(null);
if(byId == null) return null;
if(!byId.getStatus().equals(player.getStatus()) && (player.getStatus() == 1 || byId.getStatus() == 1)) {
if(minecraftRcon == null) return null;
RconResponse response;
if(player.getStatus() == 1) {
response = minecraftRcon.sendSync(new LoginWhitelistCommand(WhitelistTarget.player(player), WhiteListModes.ADD));
}else {
response = minecraftRcon.sendSync(new SelfWhiteListCommand(Target.player(player.getPlayerName()), WhiteListModes.REMOVE));
}
if(response.getResponseId() != 0) return null;
asyncSendEmail(player, player.getStatus(), false);
}
}
return playersRepository.save(player);
}
@Override
public Players getPlayerIsApply(String playerName, String qq) {
return playersRepository.findPlayersByPlayerNameAndQq(playerName, qq);
}
@Override
public int deletePlayers(List<Integer> ids) {
List<Players> allById = playersRepository.findAllById(ids);
if(allById.isEmpty()) return 0;
rconService.connect();
MinecraftRcon minecraftRcon = rconService.minecraftRcon().orElse(null);
if(minecraftRcon == null) return 0;
List<Integer> successIds = new ArrayList<>();
allById.forEach(players -> {
RconResponse response = minecraftRcon.sendSync(new SelfWhiteListCommand(Target.player(players.getPlayerName()), WhiteListModes.REMOVE));
if (response.getResponseId() == 0) {
successIds.add(players.getId());
asyncSendEmail(players, (byte) 0, true);
}
});
playersRepository.deleteAllById(successIds);
return successIds.size();
}
@Override
public Optional<Players> getPlayerByToken(String token) {
return playersRepository.findPlayersByConfirmationEmail_Token(token);
}
@Override
public int updatePlayersStatus(List<Integer> ids, Byte status, Operators operators) {
List<Players> allById = playersRepository.findAllById(ids);
if(allById.isEmpty()) return 0;
rconService.connect();
MinecraftRcon minecraftRcon = rconService.minecraftRcon().orElse(null);
if(minecraftRcon == null) return 0;
List<Integer> successIds = new ArrayList<>();
if (status == 1) {
allById.forEach(players -> {
RconResponse response = minecraftRcon.sendSync(new LoginWhitelistCommand(WhitelistTarget.player(players), WhiteListModes.ADD));
if (response.getResponseId() == 0) {
successIds.add(players.getId());
asyncSendEmail(players, status, false);
}
});
} else {
allById.forEach(players -> {
RconResponse response = minecraftRcon.sendSync(new SelfWhiteListCommand(Target.player(players.getPlayerName()), WhiteListModes.REMOVE));
if (response.getResponseId() == 0) {
successIds.add(players.getId());
asyncSendEmail(players, status, false);
}
});
}
return playersRepository.bulkUpdateStatus(successIds, status, operators);
}
@Override
public Integer getPlayersCountByStatus(Byte status) {
return playersRepository.countByStatus(status);
}
@Override
public Integer getPlayerScoreById(Integer id) {
PlayerInfoView playerInfoView = playerInfoViewRepository.findById(id).orElse(null);
if(playerInfoView == null) return null;
return playerInfoView.getTotalScore();
}
private void asyncSendEmail(Players player, Byte status, boolean delete) {
CompletableFuture.runAsync(() -> {
try {this.sendDealEmail(player.getQq(), status, player.getPlayerName(), delete);
} catch (Exception ignored) {}
});
}
private void sendDealEmail(String qq, Byte status, String playerName, boolean delete) throws MessagingException {
if(!selfConfig.emailEnable) return;
String statusText = status == 1 ? "通过" : "拒绝";
if(delete) statusText = "重置";
String mainColor = status == 1 ? "#4CAF50" : "#F44336"; // 通过为绿色拒绝为红色
String icon = status == 1 ? "" : "";
// 使用 StringBuilder 高效拼接 HTML
String html = "<!DOCTYPE html>" +
"<html lang='zh-CN'>" +
"<head>" +
" <meta charset='UTF-8'>" +
" <meta name='viewport' content='width=device-width, initial-scale=1.0'>" +
" <title>白名单通知</title>" +
" <style>" +
" body { font-family: 'Microsoft YaHei', sans-serif; background: #f5f5f5; padding: 20px; }" +
" .card { max-width: 600px; margin: 50px auto; background: white; border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); overflow: hidden; }" +
" .header { background: " + mainColor + "; color: white; padding: 30px; text-align: center; }" +
" .icon { font-size: 4rem; margin-bottom: 15px; }" +
" .content { padding: 30px; line-height: 1.8; font-size: 16px; }" +
" .notice { background: #f9f9f9; border-left: 4px solid " + mainColor + "; padding: 15px; margin: 20px 0; }" +
" .player-name { font-weight: bold; color: " + mainColor + "; }" +
" </style>" +
"</head>" +
"<body>" +
" <div class='card'>" +
" <div class='header'>" +
" <div class='icon'>" + icon + "</div>" +
" <h1>您的申请已" + statusText + "</h1>" +
" </div>" +
" <div class='content'>" +
" <p>亲爱的 <span class='player-name'>" + playerName + "</span></p>" +
(!delete
? " <p>您提交的服务器白名单申请已审核完毕。</p>"
: " <p>管理员已将您的申请记录移除。</p>") +
" <div class='notice'>" +
" <p>▶ 申请状态:<strong>" + statusText + "</strong></p>" +
" <p>▶ 处理时间:" + new java.util.Date() + "</p>" +
" </div>" +
" <p>" +
(status == 1
? "您现在可以进入服务器游玩,如有问题请联系管理员。"
: "") +
"</p>" +
" <hr>" +
" <p><small>本通知由系统自动发送,请勿回复</small></p>" +
" </div>" +
" </div>" +
"</body>" +
"</html>";
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
// 设置邮件基本信息
helper.setFrom(ConfigLoader.config.get("spring.mail.username")); // 发件人你的QQ邮箱
helper.setTo(qq + "@qq.com"); // 收件人
helper.setSubject("白名单处理通知"); // 邮件主题
// 构建HTML邮件内容包含确认链接
helper.setText(html, true); // true表示内容是HTML
// 发送邮件
mailSender.send(message);
}
}

View File

@ -0,0 +1,42 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.Questions;
import com.linearpast.minecraftmanager.repository.QuestionsRepository;
import com.linearpast.minecraftmanager.service.inter.QuestionsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class QuestionsServiceImpl implements QuestionsService {
@Autowired
private QuestionsRepository questionsRepository;
@Override
public Questions saveQuestions(Questions questions) {
return questionsRepository.save(questions);
}
@Override
public Page<Questions> getQuestions(Pageable pageable) {
return questionsRepository.findAll(pageable);
}
@Override
public void deleteQuestionsById(Integer id) {
questionsRepository.deleteById(id);
}
@Override
public void deleteQuestions(List<Integer> ids) {
questionsRepository.deleteAllById(ids);
}
@Override
public List<Questions> getAllQuestions() {
return questionsRepository.findAll();
}
}

View File

@ -0,0 +1,25 @@
package com.linearpast.minecraftmanager.service.impl;
import com.linearpast.minecraftmanager.entity.Region;
import com.linearpast.minecraftmanager.repository.RegionRepository;
import com.linearpast.minecraftmanager.service.inter.RegionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RegionServiceImpl implements RegionService {
@Autowired
private RegionRepository regionRepository;
@Override
public List<Region> findRegion(Long code, Long parentCode, Byte level) {
Specification<Region> spec = RegionRepository.RegionSpecifications
.withDynamicQuery(code, parentCode, level);
return regionRepository.findAll(spec);
}
}

View File

@ -0,0 +1,11 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.ConfirmationEmail;
import java.util.Optional;
public interface EmailService {
ConfirmationEmail saveConfirmationEmail(ConfirmationEmail confirmationEmail);
Optional<ConfirmationEmail> findConfirmationEmailByToken(String token);
void deleteConfirmationEmail(Integer id);
}

View File

@ -0,0 +1,9 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.Operators;
public interface OperatorsService {
Operators login(String username, String password);
Operators save(Operators operators);
}

View File

@ -0,0 +1,13 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.PlayerAnswers;
import com.linearpast.minecraftmanager.entity.Players;
import java.util.List;
public interface PlayerAnswersService {
List<PlayerAnswers> saveAllPlayerAnswers(List<PlayerAnswers> playerAnswers);
void deleteAllPlayerAnswers(Players players);
List<PlayerAnswers> getPlayerAnswers(Players players);
List<PlayerAnswers> getAllPlayerAnswers(List<Integer> ids);
}

View File

@ -0,0 +1,35 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.Operators;
import com.linearpast.minecraftmanager.entity.Players;
import com.linearpast.minecraftmanager.entity.view.PlayerInfoView;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;
public interface PlayersService {
Page<PlayerInfoView> getPlayers(
String playerName,
String qq,
String uuid,
Byte status,
Integer minScore,
Integer maxScore,
Pageable pageable
);
boolean deletePlayer(Integer id);
void forceDeletePlayer(List<Integer> ids);
int updatePlayerStatus(Integer id, Byte status, Operators operators);
Players getPlayer(String playerName);
Players getPlayerById(Integer id);
Players savePlayer(Players player);
Players getPlayerIsApply(String playerName, String qq);
int deletePlayers(List<Integer> ids) ;
Optional<Players> getPlayerByToken(String token);
int updatePlayersStatus(List<Integer> ids, Byte status, Operators operators);
Integer getPlayersCountByStatus(Byte status);
Integer getPlayerScoreById(Integer id);
}

View File

@ -0,0 +1,15 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.Questions;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface QuestionsService {
Questions saveQuestions(Questions questions);
Page<Questions> getQuestions(Pageable pageable);
void deleteQuestionsById(Integer id);
void deleteQuestions(List<Integer> ids);
List<Questions> getAllQuestions();
}

View File

@ -0,0 +1,9 @@
package com.linearpast.minecraftmanager.service.inter;
import com.linearpast.minecraftmanager.entity.Region;
import java.util.List;
public interface RegionService {
List<Region> findRegion(Long code, Long parentCode, Byte level);
}

View File

@ -0,0 +1,92 @@
package com.linearpast.minecraftmanager.utils;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
@Getter
@Setter
public class Result<T> {
private Integer code;
private String msg;
private Long count;
private T data;
private Result() {}
//
public static <T> Result<T> success() {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("操作成功");
return result;
}
public static <T> Result<T> success(Integer code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("操作成功");
result.setData(data);
return result;
}
public static <T> Result<T> successPage(T data, Long total) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("查询成功");
result.setData(data);
result.setCount(total);
return result;
}
public static Result<Object> error(String msg) {
return error(500, msg);
}
public static Result<Object> error(Integer code, String msg) {
Result<Object> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
// 链式方法
public Result<T> data(T data) {
this.data = data;
return this;
}
public Result<T> msg(String msg) {
this.msg = msg;
return this;
}
public Result<T> count(Long count) {
this.count = count;
return this;
}
public Result<T> code(Integer code) {
this.code = code;
return this;
}
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>(4);
map.put("code", code);
map.put("msg", msg);
map.put("count", count);
map.put("data", data);
return map;
}
}

View File

@ -0,0 +1,9 @@
package com.linearpast.minecraftmanager.utils;
import com.linearpast.minecraftmanager.entity.Players;
public record WhitelistTarget(String name, String uuid) {
public static WhitelistTarget player(Players players) {
return new WhitelistTarget(players.getPlayerName(), players.getUuid());
}
}

View File

@ -0,0 +1,31 @@
package com.linearpast.minecraftmanager.utils.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import java.util.HashMap;
import java.util.Map;
public class ConfigLoader implements EnvironmentPostProcessor {
public static final Map<String, String> config = new HashMap<>();
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
try {
PropertySource<?> source = environment.getPropertySources().stream().filter(propertySource ->
propertySource.getName().contains("application.yml")
).findFirst().orElseThrow();
if(source instanceof MapPropertySource mapPropertySource) {
for (String key : mapPropertySource.getPropertyNames()) {
config.put(key, mapPropertySource.getProperty(key).toString());
System.out.println(key + "=" + mapPropertySource.getProperty(key));
}
}
}catch (Exception e){
System.err.println("Failed to load config: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,45 @@
package com.linearpast.minecraftmanager.utils.config;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Getter
public class SelfConfig {
public static String command;
public static String testCommand;
public static String addCommand;
//rcon
@Value("${minecraft.rcon.host}")
public String host;
@Value("${minecraft.rcon.port}")
public int port;
@Value("${minecraft.rcon.password}")
public String password;
@Value("${minecraft.rcon.heart-time}")
public long heartTime;
@Value("${email.enable}")
public boolean emailEnable;
@Value("${minecraft.rcon.wlcmd}")
public void whiteListCommand(String command) {
SelfConfig.command = command;
};
@Value("${minecraft.rcon.test-cmd}")
public void testCommand(String command) {
SelfConfig.testCommand = command;
}
@Value("${minecraft.rcon.add-cmd}")
public void addCommand(String command) {
SelfConfig.addCommand = command;
}
}

View File

@ -0,0 +1,51 @@
package com.linearpast.minecraftmanager.utils.http;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class HttpApiUtils {
public static String minecraftAccountQuery(String mcName){
String host = "https://api.minecraftservices.com";
String path = "/minecraft/profile/lookup/name/" + mcName;
String method = "GET";
Map<String, String> querys = new HashMap<>();
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
try {
HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
String string = EntityUtils.toString(response.getEntity());
System.out.println(string);
JsonObject jsonObject = JsonParser.parseString(string).getAsJsonObject();
if(Optional.ofNullable(jsonObject).isPresent() && jsonObject.has("id")){
StringBuilder id = new StringBuilder(jsonObject.get("id").getAsString()).insert(8, "-").insert(13, "-").insert(18, "-").insert(23, "-");
return id.toString();
}
}catch (Exception ignored){}
return null;
}
public static String qqAvatarQuery(String qq){
String host = "https://q.qlogo.cn";
String path = "/headimg_dl";
String method = "GET";
Map<String, String> querys = new HashMap<>();
querys.put("dst_uin", qq);
querys.put("img_type", "jpg");
querys.put("spec", "640");
Map<String, String> headers = new HashMap<>();
try {
HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
byte[] pic = EntityUtils.toByteArray(response.getEntity());
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(pic);
}catch (Exception ignored){}
return null;
}
}

View File

@ -0,0 +1,312 @@
package com.linearpast.minecraftmanager.utils.http;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HttpUtils {
/**
* get
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @return
* @throws Exception
*/
public static HttpResponse doGet(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpGet request = new HttpGet(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
return httpClient.execute(request);
}
/**
* post form
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param bodys
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
Map<String, String> bodys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (bodys != null) {
List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
for (String key : bodys.keySet()) {
nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
}
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
request.setEntity(formEntity);
}
return httpClient.execute(request);
}
/**
* Post String
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
String body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (StringUtils.isNotBlank(body)) {
request.setEntity(new StringEntity(body, "utf-8"));
}
return httpClient.execute(request);
}
/**
* Post stream
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPost(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
byte[] body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPost request = new HttpPost(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (body != null) {
request.setEntity(new ByteArrayEntity(body));
}
return httpClient.execute(request);
}
/**
* Put String
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPut(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
String body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPut request = new HttpPut(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (StringUtils.isNotBlank(body)) {
request.setEntity(new StringEntity(body, "utf-8"));
}
return httpClient.execute(request);
}
/**
* Put stream
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @param body
* @return
* @throws Exception
*/
public static HttpResponse doPut(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys,
byte[] body)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpPut request = new HttpPut(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
if (body != null) {
request.setEntity(new ByteArrayEntity(body));
}
return httpClient.execute(request);
}
/**
* Delete
*
* @param host
* @param path
* @param method
* @param headers
* @param querys
* @return
* @throws Exception
*/
public static HttpResponse doDelete(String host, String path, String method,
Map<String, String> headers,
Map<String, String> querys)
throws Exception {
HttpClient httpClient = wrapClient(host);
HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
return httpClient.execute(request);
}
private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
StringBuilder sbUrl = new StringBuilder();
sbUrl.append(host);
if (!StringUtils.isBlank(path)) {
sbUrl.append(path);
}
if (null != querys) {
StringBuilder sbQuery = new StringBuilder();
for (Map.Entry<String, String> query : querys.entrySet()) {
if (0 < sbQuery.length()) {
sbQuery.append("&");
}
if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
sbQuery.append(query.getValue());
}
if (!StringUtils.isBlank(query.getKey())) {
sbQuery.append(query.getKey());
if (!StringUtils.isBlank(query.getValue())) {
sbQuery.append("=");
sbQuery.append(URLEncoder.encode(query.getValue(), StandardCharsets.UTF_8));
}
}
}
if (0 < sbQuery.length()) {
sbUrl.append("?").append(sbQuery);
}
}
return sbUrl.toString();
}
private static HttpClient wrapClient(String host) {
HttpClient httpClient = new DefaultHttpClient();
if (host.startsWith("https://")) {
sslClient(httpClient);
}
return httpClient;
}
private static void sslClient(HttpClient httpClient) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] xcs, String str) {
}
public void checkServerTrusted(X509Certificate[] xcs, String str) {
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = httpClient.getConnectionManager();
SchemeRegistry registry = ccm.getSchemeRegistry();
registry.register(new Scheme("https", ssf, 443));
} catch (KeyManagementException ex) {
throw new RuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -0,0 +1,65 @@
package com.linearpast.minecraftmanager.utils.rcon;
import io.graversen.minecraft.rcon.MinecraftClient;
import io.graversen.minecraft.rcon.RconConnectException;
import io.graversen.minecraft.rcon.service.ConnectOptions;
import io.graversen.minecraft.rcon.service.RconDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;
public class ConnectTask implements Callable<MinecraftClient> {
private static final Logger log = LoggerFactory.getLogger(ConnectTask.class);
private final ConnectOptions connectOptions;
private final RconDetails rconDetails;
ConnectTask(ConnectOptions connectOptions, RconDetails rconDetails) {
this.connectOptions = connectOptions;
this.rconDetails = rconDetails;
log.debug("{}", connectOptions);
}
public MinecraftClient call() throws Exception {
int currentAttempt = 0;
while(true) {
if (currentAttempt < this.connectOptions.getMaxRetries() && !Thread.currentThread().isInterrupted()) {
++currentAttempt;
log.debug("Connection attempt {}", currentAttempt);
MinecraftClient var8;
try {
var8 = MinecraftClient.connect(this.rconDetails.getHostname(), this.rconDetails.getPassword(), this.rconDetails.getPort());
} catch (Exception var6) {
Exception e = var6;
log.error("Connection attempt failed", e);
continue;
} finally {
if (currentAttempt < this.connectOptions.getMaxRetries()) {
this.sleep();
} else {
log.warn("Ran out of retries after {} total attempts", currentAttempt);
}
}
return var8;
}
throw new RconConnectException("Unable to connect to Minecraft server after %d retries", new Object[]{currentAttempt - 1});
}
}
private void sleep() {
try {
log.debug("Pausing for {} ms", this.connectOptions.getTimeBetweenRetries().toMillis());
Thread.sleep(this.connectOptions.getTimeBetweenRetries().toMillis());
} catch (InterruptedException var2) {
InterruptedException e = var2;
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}

View File

@ -0,0 +1,28 @@
package com.linearpast.minecraftmanager.utils.rcon;
import com.linearpast.minecraftmanager.utils.WhitelistTarget;
import com.linearpast.minecraftmanager.utils.config.SelfConfig;
import io.graversen.minecraft.rcon.commands.base.ICommand;
import io.graversen.minecraft.rcon.util.WhiteListModes;
import lombok.Getter;
import org.apache.commons.text.StringSubstitutor;
import java.util.Map;
import java.util.Objects;
public record LoginWhitelistCommand(WhitelistTarget whitelistTarget, WhiteListModes whiteListMode) implements ICommand {
public LoginWhitelistCommand(WhitelistTarget whitelistTarget, WhiteListModes whiteListMode) {
this.whitelistTarget = whitelistTarget;
this.whiteListMode = Objects.requireNonNull(whiteListMode);
}
public String command() {
return switch (this.whiteListMode()) {
case ADD -> StringSubstitutor.replace(SelfConfig.addCommand + " ${name} ${uuid}", Map.of(
"name", this.whitelistTarget().name(),
"uuid", this.whitelistTarget().uuid())
);
case REMOVE, LIST, OFF, ON, RELOAD -> "";
};
}
}

View File

@ -0,0 +1,134 @@
package com.linearpast.minecraftmanager.utils.rcon;
import com.linearpast.minecraftmanager.utils.config.SelfConfig;
import io.graversen.minecraft.rcon.IMinecraftClient;
import io.graversen.minecraft.rcon.MinecraftClient;
import io.graversen.minecraft.rcon.MinecraftRcon;
import java.io.IOException;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.*;
import io.graversen.minecraft.rcon.service.ConnectOptions;
import io.graversen.minecraft.rcon.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MinecraftRconUtils {
private static final Logger log = LoggerFactory.getLogger(MinecraftRconUtils.class);
private final ConnectTask task;
private final RconDetails rconDetails;
private final ScheduledExecutorService executorService;
private volatile IMinecraftClient minecraftClient;
private volatile MinecraftRcon minecraftRcon;
private volatile boolean isConnected;
private volatile CountDownLatch connectionLatch;
public MinecraftRconUtils(RconDetails rconDetails, ConnectOptions connectOptions) {
this.rconDetails = rconDetails;
this.executorService = Executors.newScheduledThreadPool(2);
this.task = new ConnectTask(connectOptions, rconDetails);
startConnectionWatcher(connectOptions.getConnectionWatcherInterval().toSeconds());
}
public void disconnect(){
isConnected = false;
try {minecraftClient.close();
}catch (Exception ignored){}
setMinecraftClient(null);
}
public void connect(){
boolean connected = isConnected(Duration.ofSeconds(1));
if(connected) return;
doConnect();
}
public boolean isConnected(Duration timeout) {
if(!isConnected) return false;
if(minecraftClient == null) return false;
if(minecraftRcon == null) return false;
try {
return rconTest(minecraftClient, timeout);
}catch(Exception e) {
return false;
}
}
private boolean rconTest(IMinecraftClient minecraftClient, Duration timeout){
try {
minecraftClient.sendRawSilently(SelfConfig.testCommand).get(timeout.toSeconds(), TimeUnit.SECONDS);
return true;
} catch (ExecutionException | TimeoutException | InterruptedException var3) {
log.error("Lost connection to {}", this.rconDetails.getHostname());
try {minecraftClient.close();
} catch (IOException ignored) {}
return false;
}
}
public Optional<MinecraftRcon> minecraftRcon() {
return Optional.ofNullable(this.minecraftRcon);
}
public void doConnect() {
doConnect(5);
}
public void doConnect(int timeout) {
try {
if(this.connectionLatch != null){
this.connectionLatch.await(timeout, TimeUnit.SECONDS);
this.connectionLatch = new CountDownLatch(1);
}
Future<MinecraftClient> submit = this.executorService.submit(task);
this.minecraftClient = submit.get(timeout, TimeUnit.SECONDS);
this.minecraftRcon = new MinecraftRcon(this.minecraftClient);
this.isConnected = true;
if(this.connectionLatch != null){
this.connectionLatch.countDown();
}
} catch (Exception var2) {
Exception e = var2;
disconnect();
if (this.minecraftClient != null){
this.connectionLatch.countDown();
}
log.error("Connection fail to {}", this.rconDetails.getHostname(), var2);
}
}
private void startConnectionWatcher(long intervalSeconds) {
this.executorService.scheduleWithFixedDelay(new TestConnect(this.rconDetails), 0, intervalSeconds, TimeUnit.SECONDS);
}
public void setMinecraftClient(MinecraftClient minecraftClient) {
this.minecraftClient = minecraftClient;
if(this.minecraftClient != null) this.minecraftRcon = new MinecraftRcon(this.minecraftClient);
else this.minecraftRcon = null;
}
public void setConnected(boolean connected) {
this.isConnected = connected;
}
private class TestConnect implements Runnable {
private final RconDetails rconDetails;
TestConnect(RconDetails rconDetails) {
this.rconDetails = rconDetails;
}
@Override
public void run() {
try {
if(isConnected(Duration.ofSeconds(1))) return;
minecraftClient = MinecraftClient.connect(this.rconDetails.getHostname(), this.rconDetails.getPassword(), this.rconDetails.getPort());
setMinecraftClient((MinecraftClient) minecraftClient);
setConnected(true);
}catch (Exception var2) {
disconnect();
log.error("Connection fail to {}", this.rconDetails.getHostname(), var2);
}
}
}
}

View File

@ -0,0 +1,30 @@
package com.linearpast.minecraftmanager.utils.rcon;
import com.linearpast.minecraftmanager.utils.config.SelfConfig;
import io.graversen.minecraft.rcon.commands.base.BaseTargetedCommand;
import io.graversen.minecraft.rcon.util.Target;
import io.graversen.minecraft.rcon.util.WhiteListModes;
import lombok.Getter;
import org.apache.commons.text.StringSubstitutor;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Objects;
@Getter
public class SelfWhiteListCommand extends BaseTargetedCommand {
private final WhiteListModes whiteListMode;
public SelfWhiteListCommand(Target target, WhiteListModes whiteListMode) {
super(target);
this.whiteListMode = Objects.requireNonNull(whiteListMode);
}
public String command() {
return switch (this.getWhiteListMode()) {
case ADD, REMOVE ->
StringSubstitutor.replace(SelfConfig.command + " ${mode} ${target}", Map.of("mode", this.getWhiteListMode().getModeName(), "target", this.getTarget()));
case LIST, OFF, ON, RELOAD -> SelfConfig.command + " " + this.getWhiteListMode().getModeName();
};
}
}

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.linearpast.minecraftmanager.MinecraftManagerApplication

View File

@ -0,0 +1 @@
org.springframework.boot.env.EnvironmentPostProcessor=com.linearpast.minecraftmanager.utils.config.ConfigLoader

View File

@ -0,0 +1,45 @@
server:
port: 8484
servlet:
session:
timeout: 8h
spring:
application:
name: MinecraftManager
datasource:
url: jdbc:mysql://127.0.0.1:3306/minecraft_manager_ltd?useSSL=false
username: admin
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
mail:
properties:
mail:
smtp:
auth: true
ssl:
enable: true
username: admin@163.com
password: 123456789
port: 465
host: smtp.163.com
# ========== self config ==========
minecraft:
rcon:
host: 127.0.0.1
port: 25575
password: 123456
wlcmd: whitelist
heart-time: 600
test-cmd: ping
add-cmd: login whitelist
email:
enable: false

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,144 @@
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
src: url(../font/pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
src: url(../font/pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
src: url(../font/pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
src: url(../font/pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
src: url(../font/pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
src: url(../font/pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 500;
src: url(../font/pxiByp8kv8JHgFVrLGT9Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 500;
src: url(../font/pxiByp8kv8JHgFVrLGT9Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 500;
src: url(../font/pxiByp8kv8JHgFVrLGT9Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
src: url(../font/pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
src: url(../font/pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
src: url(../font/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
src: url(../font/pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
src: url(../font/pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
src: url(../font/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* devanagari */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
src: url(../font/pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2) format('woff2');
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
src: url(../font/pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 800;
src: url(../font/pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,168 @@
/* cyrillic-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFWJ0bbck.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFUZ0bbck.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFWZ0bbck.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFVp0bbck.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFWp0bbck.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFW50bbck.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(../font/mem8YaGs126MiZpBA-UFVZ0b.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOX-hpOqc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOVuhpOqc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOXuhpOqc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOUehpOqc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOXehpOqc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOXOhpOqc.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url(../font/mem5YaGs126MiZpBA-UNirkOUuhp.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOX-hpOqc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOVuhpOqc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOXuhpOqc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOUehpOqc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOXehpOqc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOXOhpOqc.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url(../font/mem5YaGs126MiZpBA-UN7rgOUuhp.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,162 @@
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 200;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalrub46O59ZMaA.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 200;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalrub46F59ZMaA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 200;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalrub46L59Y.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqKbI6O59ZMaA.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqKbI6F59ZMaA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqKbI6L59Y.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(../font/SLXGc1nY6HkvalIkTpu0xg.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(../font/SLXGc1nY6HkvalIvTpu0xg.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(../font/SLXGc1nY6HkvalIhTps.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalr-ao6O59ZMaA.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalr-ao6F59ZMaA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalr-ao6L59Y.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalqaa46O59ZMaA.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalqaa46F59ZMaA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../font/SLXLc1nY6Hkvalqaa46L59Y.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* arabic */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 900;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqiaY6O59ZMaA.woff2) format('woff2');
unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC;
}
/* latin-ext */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 900;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqiaY6F59ZMaA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Cairo';
font-style: normal;
font-weight: 900;
font-display: swap;
src: url(../font/SLXLc1nY6HkvalqiaY6L59Y.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,160 @@
/* cyrillic-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(../font/JTUSjIg1_i6t8kCHKm459WRhyzbi.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(../font/JTUSjIg1_i6t8kCHKm459W1hyzbi.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(../font/JTUSjIg1_i6t8kCHKm459WZhyzbi.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(../font/JTUSjIg1_i6t8kCHKm459Wdhyzbi.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(../font/JTUSjIg1_i6t8kCHKm459Wlhyw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(../font/JTURjIg1_i6t8kCHKm45_ZpC3gTD_u50.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(../font/JTURjIg1_i6t8kCHKm45_ZpC3g3D_u50.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(../font/JTURjIg1_i6t8kCHKm45_ZpC3gbD_u50.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(../font/JTURjIg1_i6t8kCHKm45_ZpC3gfD_u50.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(../font/JTURjIg1_i6t8kCHKm45_ZpC3gnD_g.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(../font/JTURjIg1_i6t8kCHKm45_bZF3gTD_u50.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(../font/JTURjIg1_i6t8kCHKm45_bZF3g3D_u50.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(../font/JTURjIg1_i6t8kCHKm45_bZF3gbD_u50.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(../font/JTURjIg1_i6t8kCHKm45_bZF3gfD_u50.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(../font/JTURjIg1_i6t8kCHKm45_bZF3gnD_g.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url(../font/JTURjIg1_i6t8kCHKm45_dJE3gTD_u50.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url(../font/JTURjIg1_i6t8kCHKm45_dJE3g3D_u50.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url(../font/JTURjIg1_i6t8kCHKm45_dJE3gbD_u50.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url(../font/JTURjIg1_i6t8kCHKm45_dJE3gfD_u50.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url(../font/JTURjIg1_i6t8kCHKm45_dJE3gnD_g.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,168 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(../font/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(../font/KFOlCnqEu92Fr1MmEU9fBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(../font/KFOlCnqEu92Fr1MmWUlfBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,120 @@
/* cyrillic-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(../font/XRXV3I6Li01BKofIOOaBXso.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(../font/XRXV3I6Li01BKofIMeaBXso.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(../font/XRXV3I6Li01BKofIOuaBXso.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(../font/XRXV3I6Li01BKofIO-aBXso.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(../font/XRXV3I6Li01BKofINeaB.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: url(../font/XRXW3I6Li01BKofA6sKUbOvISTs.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: url(../font/XRXW3I6Li01BKofA6sKUZevISTs.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: url(../font/XRXW3I6Li01BKofA6sKUbuvISTs.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: url(../font/XRXW3I6Li01BKofA6sKUb-vISTs.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: url(../font/XRXW3I6Li01BKofA6sKUYevI.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(../font/XRXW3I6Li01BKofAjsOUbOvISTs.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(../font/XRXW3I6Li01BKofAjsOUZevISTs.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(../font/XRXW3I6Li01BKofAjsOUbuvISTs.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(../font/XRXW3I6Li01BKofAjsOUb-vISTs.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(../font/XRXW3I6Li01BKofAjsOUYevI.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,409 @@
/*
Flaticon icon font: Flaticon
Creation date: 25/04/2017 09:15
*/
@font-face {
font-family: "Flaticon";
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon/Flaticon.eot");
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon/Flaticon.eot?#iefix") format("embedded-opentype"),
url("../font/Flaticon.woff") format("woff"),
url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon/Flaticon.ttf") format("truetype"),
url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon/Flaticon.svg#Flaticon") format("svg");
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "Flaticon";
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon/Flaticon.svg#Flaticon") format("svg");
}
}
[class^="flaticon-"]:before, [class*=" flaticon-"]:before,
[class^="flaticon-"]:after, [class*=" flaticon-"]:after {
font-family: Flaticon;
font-style: normal;
}
.flaticon-381-add:before { content: "\f100"; }
.flaticon-381-add-1:before { content: "\f101"; }
.flaticon-381-add-2:before { content: "\f102"; }
.flaticon-381-add-3:before { content: "\f103"; }
.flaticon-381-alarm-clock:before { content: "\f104"; }
.flaticon-381-alarm-clock-1:before { content: "\f105"; }
.flaticon-381-album:before { content: "\f106"; }
.flaticon-381-album-1:before { content: "\f107"; }
.flaticon-381-album-2:before { content: "\f108"; }
.flaticon-381-album-3:before { content: "\f109"; }
.flaticon-381-app:before { content: "\f10a"; }
.flaticon-381-archive:before { content: "\f10b"; }
.flaticon-381-back:before { content: "\f10c"; }
.flaticon-381-back-1:before { content: "\f10d"; }
.flaticon-381-back-2:before { content: "\f10e"; }
.flaticon-381-background:before { content: "\f10f"; }
.flaticon-381-background-1:before { content: "\f110"; }
.flaticon-381-battery:before { content: "\f111"; }
.flaticon-381-battery-1:before { content: "\f112"; }
.flaticon-381-battery-2:before { content: "\f113"; }
.flaticon-381-battery-3:before { content: "\f114"; }
.flaticon-381-battery-4:before { content: "\f115"; }
.flaticon-381-battery-5:before { content: "\f116"; }
.flaticon-381-battery-6:before { content: "\f117"; }
.flaticon-381-battery-7:before { content: "\f118"; }
.flaticon-381-battery-8:before { content: "\f119"; }
.flaticon-381-battery-9:before { content: "\f11a"; }
.flaticon-381-binoculars:before { content: "\f11b"; }
.flaticon-381-blueprint:before { content: "\f11c"; }
.flaticon-381-bluetooth:before { content: "\f11d"; }
.flaticon-381-bluetooth-1:before { content: "\f11e"; }
.flaticon-381-book:before { content: "\f11f"; }
.flaticon-381-bookmark:before { content: "\f120"; }
.flaticon-381-bookmark-1:before { content: "\f121"; }
.flaticon-381-box:before { content: "\f122"; }
.flaticon-381-box-1:before { content: "\f123"; }
.flaticon-381-box-2:before { content: "\f124"; }
.flaticon-381-briefcase:before { content: "\f125"; }
.flaticon-381-broken-heart:before { content: "\f126"; }
.flaticon-381-broken-link:before { content: "\f127"; }
.flaticon-381-calculator:before { content: "\f128"; }
.flaticon-381-calculator-1:before { content: "\f129"; }
.flaticon-381-calendar:before { content: "\f12a"; }
.flaticon-381-calendar-1:before { content: "\f12b"; }
.flaticon-381-calendar-2:before { content: "\f12c"; }
.flaticon-381-calendar-3:before { content: "\f12d"; }
.flaticon-381-calendar-4:before { content: "\f12e"; }
.flaticon-381-calendar-5:before { content: "\f12f"; }
.flaticon-381-calendar-6:before { content: "\f130"; }
.flaticon-381-calendar-7:before { content: "\f131"; }
.flaticon-381-clock:before { content: "\f132"; }
.flaticon-381-clock-1:before { content: "\f133"; }
.flaticon-381-clock-2:before { content: "\f134"; }
.flaticon-381-close:before { content: "\f135"; }
.flaticon-381-cloud:before { content: "\f136"; }
.flaticon-381-cloud-computing:before { content: "\f137"; }
.flaticon-381-command:before { content: "\f138"; }
.flaticon-381-compact-disc:before { content: "\f139"; }
.flaticon-381-compact-disc-1:before { content: "\f13a"; }
.flaticon-381-compact-disc-2:before { content: "\f13b"; }
.flaticon-381-compass:before { content: "\f13c"; }
.flaticon-381-compass-1:before { content: "\f13d"; }
.flaticon-381-compass-2:before { content: "\f13e"; }
.flaticon-381-controls:before { content: "\f13f"; }
.flaticon-381-controls-1:before { content: "\f140"; }
.flaticon-381-controls-2:before { content: "\f141"; }
.flaticon-381-controls-3:before { content: "\f142"; }
.flaticon-381-controls-4:before { content: "\f143"; }
.flaticon-381-controls-5:before { content: "\f144"; }
.flaticon-381-controls-6:before { content: "\f145"; }
.flaticon-381-controls-7:before { content: "\f146"; }
.flaticon-381-controls-8:before { content: "\f147"; }
.flaticon-381-controls-9:before { content: "\f148"; }
.flaticon-381-database:before { content: "\f149"; }
.flaticon-381-database-1:before { content: "\f14a"; }
.flaticon-381-database-2:before { content: "\f14b"; }
.flaticon-381-diamond:before { content: "\f14c"; }
.flaticon-381-diploma:before { content: "\f14d"; }
.flaticon-381-dislike:before { content: "\f14e"; }
.flaticon-381-divide:before { content: "\f14f"; }
.flaticon-381-division:before { content: "\f150"; }
.flaticon-381-division-1:before { content: "\f151"; }
.flaticon-381-download:before { content: "\f152"; }
.flaticon-381-earth-globe:before { content: "\f153"; }
.flaticon-381-earth-globe-1:before { content: "\f154"; }
.flaticon-381-edit:before { content: "\f155"; }
.flaticon-381-edit-1:before { content: "\f156"; }
.flaticon-381-eject:before { content: "\f157"; }
.flaticon-381-eject-1:before { content: "\f158"; }
.flaticon-381-enter:before { content: "\f159"; }
.flaticon-381-equal:before { content: "\f15a"; }
.flaticon-381-equal-1:before { content: "\f15b"; }
.flaticon-381-equal-2:before { content: "\f15c"; }
.flaticon-381-error:before { content: "\f15d"; }
.flaticon-381-exit:before { content: "\f15e"; }
.flaticon-381-exit-1:before { content: "\f15f"; }
.flaticon-381-exit-2:before { content: "\f160"; }
.flaticon-381-fast-forward:before { content: "\f161"; }
.flaticon-381-fast-forward-1:before { content: "\f162"; }
.flaticon-381-file:before { content: "\f163"; }
.flaticon-381-file-1:before { content: "\f164"; }
.flaticon-381-file-2:before { content: "\f165"; }
.flaticon-381-film-strip:before { content: "\f166"; }
.flaticon-381-film-strip-1:before { content: "\f167"; }
.flaticon-381-fingerprint:before { content: "\f168"; }
.flaticon-381-flag:before { content: "\f169"; }
.flaticon-381-flag-1:before { content: "\f16a"; }
.flaticon-381-flag-2:before { content: "\f16b"; }
.flaticon-381-flag-3:before { content: "\f16c"; }
.flaticon-381-flag-4:before { content: "\f16d"; }
.flaticon-381-focus:before { content: "\f16e"; }
.flaticon-381-folder:before { content: "\f16f"; }
.flaticon-381-folder-1:before { content: "\f170"; }
.flaticon-381-folder-10:before { content: "\f171"; }
.flaticon-381-folder-11:before { content: "\f172"; }
.flaticon-381-folder-12:before { content: "\f173"; }
.flaticon-381-folder-13:before { content: "\f174"; }
.flaticon-381-folder-14:before { content: "\f175"; }
.flaticon-381-folder-15:before { content: "\f176"; }
.flaticon-381-folder-16:before { content: "\f177"; }
.flaticon-381-folder-17:before { content: "\f178"; }
.flaticon-381-folder-18:before { content: "\f179"; }
.flaticon-381-folder-19:before { content: "\f17a"; }
.flaticon-381-folder-2:before { content: "\f17b"; }
.flaticon-381-folder-3:before { content: "\f17c"; }
.flaticon-381-folder-4:before { content: "\f17d"; }
.flaticon-381-folder-5:before { content: "\f17e"; }
.flaticon-381-folder-6:before { content: "\f17f"; }
.flaticon-381-folder-7:before { content: "\f180"; }
.flaticon-381-folder-8:before { content: "\f181"; }
.flaticon-381-folder-9:before { content: "\f182"; }
.flaticon-381-forbidden:before { content: "\f183"; }
.flaticon-381-funnel:before { content: "\f184"; }
.flaticon-381-gift:before { content: "\f185"; }
.flaticon-381-heart:before { content: "\f186"; }
.flaticon-381-heart-1:before { content: "\f187"; }
.flaticon-381-help:before { content: "\f188"; }
.flaticon-381-help-1:before { content: "\f189"; }
.flaticon-381-hide:before { content: "\f18a"; }
.flaticon-381-high-volume:before { content: "\f18b"; }
.flaticon-381-home:before { content: "\f18c"; }
.flaticon-381-home-1:before { content: "\f18d"; }
.flaticon-381-home-2:before { content: "\f18e"; }
.flaticon-381-home-3:before { content: "\f18f"; }
.flaticon-381-hourglass:before { content: "\f190"; }
.flaticon-381-hourglass-1:before { content: "\f191"; }
.flaticon-381-hourglass-2:before { content: "\f192"; }
.flaticon-381-id-card:before { content: "\f193"; }
.flaticon-381-id-card-1:before { content: "\f194"; }
.flaticon-381-id-card-2:before { content: "\f195"; }
.flaticon-381-id-card-3:before { content: "\f196"; }
.flaticon-381-id-card-4:before { content: "\f197"; }
.flaticon-381-id-card-5:before { content: "\f198"; }
.flaticon-381-idea:before { content: "\f199"; }
.flaticon-381-incoming-call:before { content: "\f19a"; }
.flaticon-381-infinity:before { content: "\f19b"; }
.flaticon-381-internet:before { content: "\f19c"; }
.flaticon-381-key:before { content: "\f19d"; }
.flaticon-381-knob:before { content: "\f19e"; }
.flaticon-381-knob-1:before { content: "\f19f"; }
.flaticon-381-layer:before { content: "\f1a0"; }
.flaticon-381-layer-1:before { content: "\f1a1"; }
.flaticon-381-like:before { content: "\f1a2"; }
.flaticon-381-link:before { content: "\f1a3"; }
.flaticon-381-link-1:before { content: "\f1a4"; }
.flaticon-381-list:before { content: "\f1a5"; }
.flaticon-381-list-1:before { content: "\f1a6"; }
.flaticon-381-location:before { content: "\f1a7"; }
.flaticon-381-location-1:before { content: "\f1a8"; }
.flaticon-381-location-2:before { content: "\f1a9"; }
.flaticon-381-location-3:before { content: "\f1aa"; }
.flaticon-381-location-4:before { content: "\f1ab"; }
.flaticon-381-locations:before { content: "\f1ac"; }
.flaticon-381-lock:before { content: "\f1ad"; }
.flaticon-381-lock-1:before { content: "\f1ae"; }
.flaticon-381-lock-2:before { content: "\f1af"; }
.flaticon-381-lock-3:before { content: "\f1b0"; }
.flaticon-381-low-volume:before { content: "\f1b1"; }
.flaticon-381-low-volume-1:before { content: "\f1b2"; }
.flaticon-381-low-volume-2:before { content: "\f1b3"; }
.flaticon-381-low-volume-3:before { content: "\f1b4"; }
.flaticon-381-magic-wand:before { content: "\f1b5"; }
.flaticon-381-magnet:before { content: "\f1b6"; }
.flaticon-381-magnet-1:before { content: "\f1b7"; }
.flaticon-381-magnet-2:before { content: "\f1b8"; }
.flaticon-381-map:before { content: "\f1b9"; }
.flaticon-381-map-1:before { content: "\f1ba"; }
.flaticon-381-map-2:before { content: "\f1bb"; }
.flaticon-381-menu:before { content: "\f1bc"; }
.flaticon-381-menu-1:before { content: "\f1bd"; }
.flaticon-381-menu-2:before { content: "\f1be"; }
.flaticon-381-menu-3:before { content: "\f1bf"; }
.flaticon-381-microphone:before { content: "\f1c0"; }
.flaticon-381-microphone-1:before { content: "\f1c1"; }
.flaticon-381-more:before { content: "\f1c2"; }
.flaticon-381-more-1:before { content: "\f1c3"; }
.flaticon-381-more-2:before { content: "\f1c4"; }
.flaticon-381-multiply:before { content: "\f1c5"; }
.flaticon-381-multiply-1:before { content: "\f1c6"; }
.flaticon-381-music-album:before { content: "\f1c7"; }
.flaticon-381-mute:before { content: "\f1c8"; }
.flaticon-381-mute-1:before { content: "\f1c9"; }
.flaticon-381-mute-2:before { content: "\f1ca"; }
.flaticon-381-network:before { content: "\f1cb"; }
.flaticon-381-network-1:before { content: "\f1cc"; }
.flaticon-381-network-2:before { content: "\f1cd"; }
.flaticon-381-network-3:before { content: "\f1ce"; }
.flaticon-381-networking:before { content: "\f1cf"; }
.flaticon-381-networking-1:before { content: "\f1d0"; }
.flaticon-381-news:before { content: "\f1d1"; }
.flaticon-381-newspaper:before { content: "\f1d2"; }
.flaticon-381-next:before { content: "\f1d3"; }
.flaticon-381-next-1:before { content: "\f1d4"; }
.flaticon-381-note:before { content: "\f1d5"; }
.flaticon-381-notebook:before { content: "\f1d6"; }
.flaticon-381-notebook-1:before { content: "\f1d7"; }
.flaticon-381-notebook-2:before { content: "\f1d8"; }
.flaticon-381-notebook-3:before { content: "\f1d9"; }
.flaticon-381-notebook-4:before { content: "\f1da"; }
.flaticon-381-notebook-5:before { content: "\f1db"; }
.flaticon-381-notepad:before { content: "\f1dc"; }
.flaticon-381-notepad-1:before { content: "\f1dd"; }
.flaticon-381-notepad-2:before { content: "\f1de"; }
.flaticon-381-notification:before { content: "\f1df"; }
.flaticon-381-off:before { content: "\f1e0"; }
.flaticon-381-on:before { content: "\f1e1"; }
.flaticon-381-pad:before { content: "\f1e2"; }
.flaticon-381-padlock:before { content: "\f1e3"; }
.flaticon-381-padlock-1:before { content: "\f1e4"; }
.flaticon-381-padlock-2:before { content: "\f1e5"; }
.flaticon-381-panel:before { content: "\f1e6"; }
.flaticon-381-panel-1:before { content: "\f1e7"; }
.flaticon-381-panel-2:before { content: "\f1e8"; }
.flaticon-381-panel-3:before { content: "\f1e9"; }
.flaticon-381-paperclip:before { content: "\f1ea"; }
.flaticon-381-pause:before { content: "\f1eb"; }
.flaticon-381-pause-1:before { content: "\f1ec"; }
.flaticon-381-pencil:before { content: "\f1ed"; }
.flaticon-381-percentage:before { content: "\f1ee"; }
.flaticon-381-percentage-1:before { content: "\f1ef"; }
.flaticon-381-perspective:before { content: "\f1f0"; }
.flaticon-381-phone-call:before { content: "\f1f1"; }
.flaticon-381-photo:before { content: "\f1f2"; }
.flaticon-381-photo-camera:before { content: "\f1f3"; }
.flaticon-381-photo-camera-1:before { content: "\f1f4"; }
.flaticon-381-picture:before { content: "\f1f5"; }
.flaticon-381-picture-1:before { content: "\f1f6"; }
.flaticon-381-picture-2:before { content: "\f1f7"; }
.flaticon-381-pin:before { content: "\f1f8"; }
.flaticon-381-play-button:before { content: "\f1f9"; }
.flaticon-381-play-button-1:before { content: "\f1fa"; }
.flaticon-381-plus:before { content: "\f1fb"; }
.flaticon-381-presentation:before { content: "\f1fc"; }
.flaticon-381-price-tag:before { content: "\f1fd"; }
.flaticon-381-print:before { content: "\f1fe"; }
.flaticon-381-print-1:before { content: "\f1ff"; }
.flaticon-381-privacy:before { content: "\f200"; }
.flaticon-381-promotion:before { content: "\f201"; }
.flaticon-381-promotion-1:before { content: "\f202"; }
.flaticon-381-push-pin:before { content: "\f203"; }
.flaticon-381-quaver:before { content: "\f204"; }
.flaticon-381-quaver-1:before { content: "\f205"; }
.flaticon-381-radar:before { content: "\f206"; }
.flaticon-381-reading:before { content: "\f207"; }
.flaticon-381-receive:before { content: "\f208"; }
.flaticon-381-record:before { content: "\f209"; }
.flaticon-381-repeat:before { content: "\f20a"; }
.flaticon-381-repeat-1:before { content: "\f20b"; }
.flaticon-381-resume:before { content: "\f20c"; }
.flaticon-381-rewind:before { content: "\f20d"; }
.flaticon-381-rewind-1:before { content: "\f20e"; }
.flaticon-381-ring:before { content: "\f20f"; }
.flaticon-381-ring-1:before { content: "\f210"; }
.flaticon-381-rotate:before { content: "\f211"; }
.flaticon-381-rotate-1:before { content: "\f212"; }
.flaticon-381-route:before { content: "\f213"; }
.flaticon-381-save:before { content: "\f214"; }
.flaticon-381-search:before { content: "\f215"; }
.flaticon-381-search-1:before { content: "\f216"; }
.flaticon-381-search-2:before { content: "\f217"; }
.flaticon-381-search-3:before { content: "\f218"; }
.flaticon-381-send:before { content: "\f219"; }
.flaticon-381-send-1:before { content: "\f21a"; }
.flaticon-381-send-2:before { content: "\f21b"; }
.flaticon-381-settings:before { content: "\f21c"; }
.flaticon-381-settings-1:before { content: "\f21d"; }
.flaticon-381-settings-2:before { content: "\f21e"; }
.flaticon-381-settings-3:before { content: "\f21f"; }
.flaticon-381-settings-4:before { content: "\f220"; }
.flaticon-381-settings-5:before { content: "\f221"; }
.flaticon-381-settings-6:before { content: "\f222"; }
.flaticon-381-settings-7:before { content: "\f223"; }
.flaticon-381-settings-8:before { content: "\f224"; }
.flaticon-381-settings-9:before { content: "\f225"; }
.flaticon-381-share:before { content: "\f226"; }
.flaticon-381-share-1:before { content: "\f227"; }
.flaticon-381-share-2:before { content: "\f228"; }
.flaticon-381-shuffle:before { content: "\f229"; }
.flaticon-381-shuffle-1:before { content: "\f22a"; }
.flaticon-381-shut-down:before { content: "\f22b"; }
.flaticon-381-silence:before { content: "\f22c"; }
.flaticon-381-silent:before { content: "\f22d"; }
.flaticon-381-smartphone:before { content: "\f22e"; }
.flaticon-381-smartphone-1:before { content: "\f22f"; }
.flaticon-381-smartphone-2:before { content: "\f230"; }
.flaticon-381-smartphone-3:before { content: "\f231"; }
.flaticon-381-smartphone-4:before { content: "\f232"; }
.flaticon-381-smartphone-5:before { content: "\f233"; }
.flaticon-381-smartphone-6:before { content: "\f234"; }
.flaticon-381-smartphone-7:before { content: "\f235"; }
.flaticon-381-speaker:before { content: "\f236"; }
.flaticon-381-speedometer:before { content: "\f237"; }
.flaticon-381-spotlight:before { content: "\f238"; }
.flaticon-381-star:before { content: "\f239"; }
.flaticon-381-star-1:before { content: "\f23a"; }
.flaticon-381-stop:before { content: "\f23b"; }
.flaticon-381-stop-1:before { content: "\f23c"; }
.flaticon-381-stopclock:before { content: "\f23d"; }
.flaticon-381-stopwatch:before { content: "\f23e"; }
.flaticon-381-stopwatch-1:before { content: "\f23f"; }
.flaticon-381-stopwatch-2:before { content: "\f240"; }
.flaticon-381-substract:before { content: "\f241"; }
.flaticon-381-substract-1:before { content: "\f242"; }
.flaticon-381-substract-2:before { content: "\f243"; }
.flaticon-381-success:before { content: "\f244"; }
.flaticon-381-success-1:before { content: "\f245"; }
.flaticon-381-success-2:before { content: "\f246"; }
.flaticon-381-sunglasses:before { content: "\f247"; }
.flaticon-381-switch:before { content: "\f248"; }
.flaticon-381-switch-1:before { content: "\f249"; }
.flaticon-381-switch-2:before { content: "\f24a"; }
.flaticon-381-switch-3:before { content: "\f24b"; }
.flaticon-381-switch-4:before { content: "\f24c"; }
.flaticon-381-switch-5:before { content: "\f24d"; }
.flaticon-381-sync:before { content: "\f24e"; }
.flaticon-381-tab:before { content: "\f24f"; }
.flaticon-381-target:before { content: "\f250"; }
.flaticon-381-television:before { content: "\f251"; }
.flaticon-381-time:before { content: "\f252"; }
.flaticon-381-transfer:before { content: "\f253"; }
.flaticon-381-trash:before { content: "\f254"; }
.flaticon-381-trash-1:before { content: "\f255"; }
.flaticon-381-trash-2:before { content: "\f256"; }
.flaticon-381-trash-3:before { content: "\f257"; }
.flaticon-381-turn-off:before { content: "\f258"; }
.flaticon-381-umbrella:before { content: "\f259"; }
.flaticon-381-unlocked:before { content: "\f25a"; }
.flaticon-381-unlocked-1:before { content: "\f25b"; }
.flaticon-381-unlocked-2:before { content: "\f25c"; }
.flaticon-381-unlocked-3:before { content: "\f25d"; }
.flaticon-381-unlocked-4:before { content: "\f25e"; }
.flaticon-381-upload:before { content: "\f25f"; }
.flaticon-381-upload-1:before { content: "\f260"; }
.flaticon-381-user:before { content: "\f261"; }
.flaticon-381-user-1:before { content: "\f262"; }
.flaticon-381-user-2:before { content: "\f263"; }
.flaticon-381-user-3:before { content: "\f264"; }
.flaticon-381-user-4:before { content: "\f265"; }
.flaticon-381-user-5:before { content: "\f266"; }
.flaticon-381-user-6:before { content: "\f267"; }
.flaticon-381-user-7:before { content: "\f268"; }
.flaticon-381-user-8:before { content: "\f269"; }
.flaticon-381-user-9:before { content: "\f26a"; }
.flaticon-381-video-camera:before { content: "\f26b"; }
.flaticon-381-video-clip:before { content: "\f26c"; }
.flaticon-381-video-player:before { content: "\f26d"; }
.flaticon-381-video-player-1:before { content: "\f26e"; }
.flaticon-381-view:before { content: "\f26f"; }
.flaticon-381-view-1:before { content: "\f270"; }
.flaticon-381-view-2:before { content: "\f271"; }
.flaticon-381-volume:before { content: "\f272"; }
.flaticon-381-warning:before { content: "\f273"; }
.flaticon-381-warning-1:before { content: "\f274"; }
.flaticon-381-wifi:before { content: "\f275"; }
.flaticon-381-wifi-1:before { content: "\f276"; }
.flaticon-381-wifi-2:before { content: "\f277"; }
.flaticon-381-windows:before { content: "\f278"; }
.flaticon-381-windows-1:before { content: "\f279"; }
.flaticon-381-zoom-in:before { content: "\f27a"; }
.flaticon-381-zoom-out:before { content: "\f27b"; }

View File

@ -0,0 +1,128 @@
@font-face {
font-family: "Flaticon";
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.eot");
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.eot?#iefix") format("embedded-opentype"),
url("../font/Flaticon_1.woff2") format("woff2"),
url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.woff") format("woff"),
url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.ttf") format("truetype"),
url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.svg#Flaticon") format("svg");
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "Flaticon";
src: url("http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/flaticon_1/Flaticon_1.svg#Flaticon") format("svg");
}
}
.fimanager:before {
display: inline-block;
font-family: "Flaticon";
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-decoration: inherit;
text-rendering: optimizeLegibility;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
display: block;
}
.flaticon-001-arrow-down:before { content: "\f100"; }
.flaticon-002-arrow-down:before { content: "\f101"; }
.flaticon-003-arrow-up:before { content: "\f102"; }
.flaticon-004-arrow-up:before { content: "\f103"; }
.flaticon-005-back-arrow:before { content: "\f104"; }
.flaticon-006-brightness:before { content: "\f105"; }
.flaticon-007-bulleye:before { content: "\f106"; }
.flaticon-008-check:before { content: "\f107"; }
.flaticon-009-check:before { content: "\f108"; }
.flaticon-010-check:before { content: "\f109"; }
.flaticon-011-check:before { content: "\f10a"; }
.flaticon-012-checkmark:before { content: "\f10b"; }
.flaticon-013-checkmark:before { content: "\f10c"; }
.flaticon-014-checkmark:before { content: "\f10d"; }
.flaticon-015-chevron:before { content: "\f10e"; }
.flaticon-016-double-chevron:before { content: "\f10f"; }
.flaticon-017-clipboard:before { content: "\f110"; }
.flaticon-018-clock:before { content: "\f111"; }
.flaticon-019-close:before { content: "\f112"; }
.flaticon-020-close:before { content: "\f113"; }
.flaticon-021-command:before { content: "\f114"; }
.flaticon-022-copy:before { content: "\f115"; }
.flaticon-023-cut:before { content: "\f116"; }
.flaticon-024-dashboard:before { content: "\f117"; }
.flaticon-025-dashboard:before { content: "\f118"; }
.flaticon-026-delete:before { content: "\f119"; }
.flaticon-027-dot:before { content: "\f11a"; }
.flaticon-028-download:before { content: "\f11b"; }
.flaticon-029-ellipsis:before { content: "\f11c"; }
.flaticon-030-ellipsis:before { content: "\f11d"; }
.flaticon-031-ellipsis:before { content: "\f11e"; }
.flaticon-032-ellipsis:before { content: "\f11f"; }
.flaticon-033-feather:before { content: "\f120"; }
.flaticon-034-filter:before { content: "\f121"; }
.flaticon-035-flag:before { content: "\f122"; }
.flaticon-036-floppy-disk:before { content: "\f123"; }
.flaticon-037-funnel:before { content: "\f124"; }
.flaticon-038-gauge:before { content: "\f125"; }
.flaticon-039-goal:before { content: "\f126"; }
.flaticon-040-graph:before { content: "\f127"; }
.flaticon-041-graph:before { content: "\f128"; }
.flaticon-042-menu:before { content: "\f129"; }
.flaticon-043-menu:before { content: "\f12a"; }
.flaticon-044-menu:before { content: "\f12b"; }
.flaticon-045-heart:before { content: "\f12c"; }
.flaticon-046-home:before { content: "\f12d"; }
.flaticon-047-home:before { content: "\f12e"; }
.flaticon-048-home:before { content: "\f12f"; }
.flaticon-049-home:before { content: "\f130"; }
.flaticon-050-info:before { content: "\f131"; }
.flaticon-051-info:before { content: "\f132"; }
.flaticon-052-inside:before { content: "\f133"; }
.flaticon-053-lifebuoy:before { content: "\f134"; }
.flaticon-054-maximize:before { content: "\f135"; }
.flaticon-055-minimize:before { content: "\f136"; }
.flaticon-056-minus:before { content: "\f137"; }
.flaticon-057-minus:before { content: "\f138"; }
.flaticon-058-minus:before { content: "\f139"; }
.flaticon-059-minus:before { content: "\f13a"; }
.flaticon-060-on:before { content: "\f13b"; }
.flaticon-061-outside:before { content: "\f13c"; }
.flaticon-062-pencil:before { content: "\f13d"; }
.flaticon-063-pencil:before { content: "\f13e"; }
.flaticon-064-pin:before { content: "\f13f"; }
.flaticon-065-pin:before { content: "\f140"; }
.flaticon-066-plus:before { content: "\f141"; }
.flaticon-067-plus:before { content: "\f142"; }
.flaticon-068-plus:before { content: "\f143"; }
.flaticon-069-plus:before { content: "\f144"; }
.flaticon-070-power:before { content: "\f145"; }
.flaticon-071-print:before { content: "\f146"; }
.flaticon-072-printer:before { content: "\f147"; }
.flaticon-073-question:before { content: "\f148"; }
.flaticon-074-question:before { content: "\f149"; }
.flaticon-075-reload:before { content: "\f14a"; }
.flaticon-076-remove:before { content: "\f14b"; }
.flaticon-077-remove:before { content: "\f14c"; }
.flaticon-078-remove:before { content: "\f14d"; }
.flaticon-079-search:before { content: "\f14e"; }
.flaticon-080-search:before { content: "\f14f"; }
.flaticon-081-search:before { content: "\f150"; }
.flaticon-082-share:before { content: "\f151"; }
.flaticon-083-share:before { content: "\f152"; }
.flaticon-084-share:before { content: "\f153"; }
.flaticon-085-signal:before { content: "\f154"; }
.flaticon-086-star:before { content: "\f155"; }
.flaticon-087-stop:before { content: "\f156"; }
.flaticon-088-time:before { content: "\f157"; }
.flaticon-089-trash:before { content: "\f158"; }
.flaticon-090-upload:before { content: "\f159"; }
.flaticon-091-warning:before { content: "\f15a"; }
.flaticon-092-warning:before { content: "\f15b"; }
.flaticon-093-waving:before { content: "\f15c"; }

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
/*!
* metismenu https://github.com/onokumus/metismenu#readme
* A jQuery menu plugin
* @version 3.0.3
* @author Osman Nuri Okumus <onokumus@gmail.com> (https://github.com/onokumus)
* @license: MIT
*/.metismenu .arrow{float:right;line-height:1.42857}[dir=rtl] .metismenu .arrow{float:left}.metismenu .glyphicon.arrow:before{content:"\e079"}.metismenu .mm-active>a>.glyphicon.arrow:before{content:"\e114"}.metismenu .fa.arrow:before{content:"\f104"}.metismenu .mm-active>a>.fa.arrow:before{content:"\f107"}.metismenu .ion.arrow:before{content:"\f3d2"}.metismenu .mm-active>a>.ion.arrow:before{content:"\f3d0"}.metismenu .plus-times{float:right}[dir=rtl] .metismenu .plus-times{float:left}.metismenu .fa.plus-times:before{content:"\f067"}.metismenu .mm-active>a>.fa.plus-times{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.metismenu .plus-minus{float:right}[dir=rtl] .metismenu .plus-minus{float:left}.metismenu .fa.plus-minus:before{content:"\f067"}.metismenu .mm-active>a>.fa.plus-minus:before{content:"\f068"}.metismenu .mm-collapse:not(.mm-show){display:none}.metismenu .mm-collapsing{position:relative;height:0;overflow:hidden;transition-timing-function:ease;transition-duration:.35s;transition-property:height,visibility}.metismenu .has-arrow{position:relative}.metismenu .has-arrow:after{position:absolute;content:"";width:.5em;height:.5em;border-width:1px 0 0 1px;border-style:solid;border-color:initial;right:1em;-webkit-transform:rotate(-45deg) translateY(-50%);transform:rotate(-45deg) translateY(-50%);-webkit-transform-origin:top;transform-origin:top;top:50%;transition:all .3s ease-out}[dir=rtl] .metismenu .has-arrow:after{right:auto;left:1em;-webkit-transform:rotate(135deg) translateY(-50%);transform:rotate(135deg) translateY(-50%)}.metismenu .has-arrow[aria-expanded=true]:after,.metismenu .mm-active>.has-arrow:after{-webkit-transform:rotate(-135deg) translateY(-50%);transform:rotate(-135deg) translateY(-50%)}[dir=rtl] .metismenu .has-arrow[aria-expanded=true]:after,[dir=rtl] .metismenu .mm-active>.has-arrow:after{-webkit-transform:rotate(225deg) translateY(-50%);transform:rotate(225deg) translateY(-50%)}
/*# sourceMappingURL=metisMenu.min.css.map */

View File

@ -0,0 +1,141 @@
.nice-select {
-webkit-tap-highlight-color: transparent;
background-color: #fff;
border-radius: 5px;
border: solid 1px #e8e8e8;
box-sizing: border-box;
clear: both;
cursor: pointer;
display: block;
float: left;
font-family: inherit;
font-size: 14px;
font-weight: normal;
height: 42px;
line-height: 40px;
outline: none;
padding-left: 18px;
padding-right: 30px;
position: relative;
text-align: left !important;
-webkit-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: auto; }
.nice-select:hover {
border-color: #dbdbdb; }
.nice-select:active, .nice-select.open, .nice-select:focus {
border-color: #999; }
.nice-select:after {
border-bottom: 3px solid #eee;
border-right: 3px solid #eee;
content: '';
display: block;
height: 10px;
margin-top: -6px;
pointer-events: none;
position: absolute;
right: 8px;
top: 50%;
margin-right:10px;
-webkit-transform-origin: 66% 66%;
-ms-transform-origin: 66% 66%;
transform-origin: 66% 66%;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transition: all 0.15s ease-in-out;
transition: all 0.15s ease-in-out;
width: 10px; }
.nice-select.open:after {
-webkit-transform: rotate(-135deg);
-ms-transform: rotate(-135deg);
transform: rotate(-135deg); }
.nice-select.open .list {
opacity: 1;
pointer-events: auto;
-webkit-transform: scale(1) translateY(0);
-ms-transform: scale(1) translateY(0);
transform: scale(1) translateY(0); }
.nice-select.disabled {
border-color: #ededed;
color: #999;
pointer-events: none; }
.nice-select.disabled:after {
border-color: #cccccc; }
.nice-select.wide {
width: 100%;
line-height:44px;
}
.nice-select.wide .list {
left: 0 !important;
right: 0 !important; }
.nice-select.right {
float: right; }
.nice-select.right .list {
left: auto;
right: 0; }
.nice-select.small {
font-size: 12px;
height: 36px;
line-height: 34px; }
.nice-select.small:after {
height: 4px;
width: 4px; }
.nice-select.small .option {
line-height: 34px;
min-height: 34px; }
.nice-select .list {
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 0 1px rgba(68, 68, 68, 0.11);
box-sizing: border-box;
margin-top: 4px;
opacity: 0;
overflow: hidden;
padding: 0;
pointer-events: none;
position: absolute;
top: 100%;
left: 0;
-webkit-transform-origin: 50% 0;
-ms-transform-origin: 50% 0;
transform-origin: 50% 0;
-webkit-transform: scale(0.75) translateY(-21px);
-ms-transform: scale(0.75) translateY(-21px);
transform: scale(0.75) translateY(-21px);
-webkit-transition: all 0.2s cubic-bezier(0.5, 0, 0, 1.25), opacity 0.15s ease-out;
transition: all 0.2s cubic-bezier(0.5, 0, 0, 1.25), opacity 0.15s ease-out;
z-index: 9; }
.nice-select .list:hover .option:not(:hover) {
background-color: transparent !important; }
.nice-select .option {
cursor: pointer;
font-weight: 400;
line-height: 40px;
list-style: none;
min-height: 40px;
outline: none;
padding-left: 18px;
padding-right: 29px;
text-align: left;
-webkit-transition: all 0.2s;
transition: all 0.2s; }
.nice-select .option:hover, .nice-select .option.focus, .nice-select .option.selected.focus {
background-color: #f6f6f6; }
.nice-select .option.selected {
font-weight: bold; }
.nice-select .option.disabled {
background-color: transparent;
color: #999;
cursor: default; }
.no-csspointerevents .nice-select .list {
display: none; }
.no-csspointerevents .nice-select.open .list {
display: block; }

View File

@ -0,0 +1,116 @@
/*
* Container style
*/
.ps {
overflow: hidden !important;
overflow-anchor: none;
-ms-overflow-style: none;
touch-action: auto;
-ms-touch-action: auto;
}
/*
* Scrollbar rail styles
*/
.ps__rail-x {
display: none;
opacity: 0;
transition: background-color .2s linear, opacity .2s linear;
-webkit-transition: background-color .2s linear, opacity .2s linear;
height: 15px;
/* there must be 'bottom' or 'top' for ps__rail-x */
bottom: 0px;
/* please don't change 'position' */
position: absolute;
}
.ps__rail-y {
display: none;
opacity: 0;
transition: background-color .2s linear, opacity .2s linear;
-webkit-transition: background-color .2s linear, opacity .2s linear;
width: 15px;
/* there must be 'right' or 'left' for ps__rail-y */
right: 0;
/* please don't change 'position' */
position: absolute;
}
.ps--active-x > .ps__rail-x,
.ps--active-y > .ps__rail-y {
display: block;
background-color: transparent;
}
.ps:hover > .ps__rail-x,
.ps:hover > .ps__rail-y,
.ps--focus > .ps__rail-x,
.ps--focus > .ps__rail-y,
.ps--scrolling-x > .ps__rail-x,
.ps--scrolling-y > .ps__rail-y {
opacity: 0.6;
}
.ps .ps__rail-x:hover,
.ps .ps__rail-y:hover,
.ps .ps__rail-x:focus,
.ps .ps__rail-y:focus,
.ps .ps__rail-x.ps--clicking,
.ps .ps__rail-y.ps--clicking {
background-color: #eee;
opacity: 0.9;
}
/*
* Scrollbar thumb styles
*/
.ps__thumb-x {
background-color: #aaa;
border-radius: 6px;
transition: background-color .2s linear, height .2s ease-in-out;
-webkit-transition: background-color .2s linear, height .2s ease-in-out;
height: 6px;
/* there must be 'bottom' for ps__thumb-x */
bottom: 2px;
/* please don't change 'position' */
position: absolute;
}
.ps__thumb-y {
background-color: #aaa;
border-radius: 6px;
transition: background-color .2s linear, width .2s ease-in-out;
-webkit-transition: background-color .2s linear, width .2s ease-in-out;
width: 6px;
/* there must be 'right' for ps__thumb-y */
right: 2px;
/* please don't change 'position' */
position: absolute;
}
.ps__rail-x:hover > .ps__thumb-x,
.ps__rail-x:focus > .ps__thumb-x,
.ps__rail-x.ps--clicking .ps__thumb-x {
background-color: #999;
height: 11px;
}
.ps__rail-y:hover > .ps__thumb-y,
.ps__rail-y:focus > .ps__thumb-y,
.ps__rail-y.ps--clicking .ps__thumb-y {
background-color: #999;
width: 11px;
}
/* MS supports */
@supports (-ms-overflow-style: none) {
.ps {
overflow: auto !important;
}
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.ps {
overflow: auto !important;
}
}

View File

@ -0,0 +1,754 @@
@font-face {
font-family: 'simple-line-icons';
src: url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/simple-line-icons/fonts/Simple-Line-Icons4c82.eot?-i3a2kk');
src: url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/simple-line-icons/fonts/Simple-Line-Iconsd41d.eot?#iefix-i3a2kk') format('embedded-opentype'), url('../font/Simple-Line-Icons4c82.ttf') format('truetype'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/simple-line-icons/fonts/Simple-Line-Icons4c82.woff2?-i3a2kk') format('woff2'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/simple-line-icons/fonts/Simple-Line-Icons4c82.woff?-i3a2kk') format('woff'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/simple-line-icons/fonts/Simple-Line-Icons4c82.svg?-i3a2kk#simple-line-icons') format('svg');
font-weight: normal;
font-style: normal;
}
/*
Use the following CSS code if you want to have a class per icon.
Instead of a list of all class selectors, you can use the generic [class*="icon-"] selector, but it's slower:
*/
.icon-user,
.icon-people,
.icon-user-female,
.icon-user-follow,
.icon-user-following,
.icon-user-unfollow,
.icon-login,
.icon-logout,
.icon-emotsmile,
.icon-phone,
.icon-call-end,
.icon-call-in,
.icon-call-out,
.icon-map,
.icon-location-pin,
.icon-direction,
.icon-directions,
.icon-compass,
.icon-layers,
.icon-menu,
.icon-list,
.icon-options-vertical,
.icon-options,
.icon-arrow-down,
.icon-arrow-left,
.icon-arrow-right,
.icon-arrow-up,
.icon-arrow-up-circle,
.icon-arrow-left-circle,
.icon-arrow-right-circle,
.icon-arrow-down-circle,
.icon-check,
.icon-clock,
.icon-plus,
.icon-close,
.icon-trophy,
.icon-screen-smartphone,
.icon-screen-desktop,
.icon-plane,
.icon-notebook,
.icon-mustache,
.icon-mouse,
.icon-magnet,
.icon-energy,
.icon-disc,
.icon-cursor,
.icon-cursor-move,
.icon-crop,
.icon-chemistry,
.icon-speedometer,
.icon-shield,
.icon-screen-tablet,
.icon-magic-wand,
.icon-hourglass,
.icon-graduation,
.icon-ghost,
.icon-game-controller,
.icon-fire,
.icon-eyeglass,
.icon-envelope-open,
.icon-envelope-letter,
.icon-bell,
.icon-badge,
.icon-anchor,
.icon-wallet,
.icon-vector,
.icon-speech,
.icon-puzzle,
.icon-printer,
.icon-present,
.icon-playlist,
.icon-pin,
.icon-picture,
.icon-handbag,
.icon-globe-alt,
.icon-globe,
.icon-folder-alt,
.icon-folder,
.icon-film,
.icon-feed,
.icon-drop,
.icon-drawar,
.icon-docs,
.icon-doc,
.icon-diamond,
.icon-cup,
.icon-calculator,
.icon-bubbles,
.icon-briefcase,
.icon-book-open,
.icon-basket-loaded,
.icon-basket,
.icon-bag,
.icon-action-undo,
.icon-action-redo,
.icon-wrench,
.icon-umbrella,
.icon-trash,
.icon-tag,
.icon-support,
.icon-frame,
.icon-size-fullscreen,
.icon-size-actual,
.icon-shuffle,
.icon-share-alt,
.icon-share,
.icon-rocket,
.icon-question,
.icon-pie-chart,
.icon-pencil,
.icon-note,
.icon-loop,
.icon-home,
.icon-grid,
.icon-graph,
.icon-microphone,
.icon-music-tone-alt,
.icon-music-tone,
.icon-earphones-alt,
.icon-earphones,
.icon-equalizer,
.icon-like,
.icon-dislike,
.icon-control-start,
.icon-control-rewind,
.icon-control-play,
.icon-control-pause,
.icon-control-forward,
.icon-control-end,
.icon-volume-1,
.icon-volume-2,
.icon-volume-off,
.icon-calender,
.icon-bulb,
.icon-chart,
.icon-ban,
.icon-bubble,
.icon-camrecorder,
.icon-camera,
.icon-cloud-download,
.icon-cloud-upload,
.icon-envelope,
.icon-eye,
.icon-flag,
.icon-heart,
.icon-info,
.icon-key,
.icon-link,
.icon-lock,
.icon-lock-open,
.icon-magnifier,
.icon-magnifier-add,
.icon-magnifier-remove,
.icon-paper-clip,
.icon-paper-plane,
.icon-power,
.icon-refresh,
.icon-reload,
.icon-settings,
.icon-star,
.icon-symble-female,
.icon-symbol-male,
.icon-target,
.icon-credit-card,
.icon-paypal,
.icon-social-tumblr,
.icon-social-twitter,
.icon-social-facebook,
.icon-social-instagram,
.icon-social-linkedin,
.icon-social-pintarest,
.icon-social-github,
.icon-social-gplus,
.icon-social-reddit,
.icon-social-skype,
.icon-social-dribbble,
.icon-social-behance,
.icon-social-foursqare,
.icon-social-soundcloud,
.icon-social-spotify,
.icon-social-stumbleupon,
.icon-social-youtube,
.icon-social-dropbox {
font-family: 'simple-line-icons';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-user:before {
content: "\e005";
}
.icon-people:before {
content: "\e001";
}
.icon-user-female:before {
content: "\e000";
}
.icon-user-follow:before {
content: "\e002";
}
.icon-user-following:before {
content: "\e003";
}
.icon-user-unfollow:before {
content: "\e004";
}
.icon-login:before {
content: "\e066";
}
.icon-logout:before {
content: "\e065";
}
.icon-emotsmile:before {
content: "\e021";
}
.icon-phone:before {
content: "\e600";
}
.icon-call-end:before {
content: "\e048";
}
.icon-call-in:before {
content: "\e047";
}
.icon-call-out:before {
content: "\e046";
}
.icon-map:before {
content: "\e033";
}
.icon-location-pin:before {
content: "\e096";
}
.icon-direction:before {
content: "\e042";
}
.icon-directions:before {
content: "\e041";
}
.icon-compass:before {
content: "\e045";
}
.icon-layers:before {
content: "\e034";
}
.icon-menu:before {
content: "\e601";
}
.icon-list:before {
content: "\e067";
}
.icon-options-vertical:before {
content: "\e602";
}
.icon-options:before {
content: "\e603";
}
.icon-arrow-down:before {
content: "\e604";
}
.icon-arrow-left:before {
content: "\e605";
}
.icon-arrow-right:before {
content: "\e606";
}
.icon-arrow-up:before {
content: "\e607";
}
.icon-arrow-up-circle:before {
content: "\e078";
}
.icon-arrow-left-circle:before {
content: "\e07a";
}
.icon-arrow-right-circle:before {
content: "\e079";
}
.icon-arrow-down-circle:before {
content: "\e07b";
}
.icon-check:before {
content: "\e080";
}
.icon-clock:before {
content: "\e081";
}
.icon-plus:before {
content: "\e095";
}
.icon-close:before {
content: "\e082";
}
.icon-trophy:before {
content: "\e006";
}
.icon-screen-smartphone:before {
content: "\e010";
}
.icon-screen-desktop:before {
content: "\e011";
}
.icon-plane:before {
content: "\e012";
}
.icon-notebook:before {
content: "\e013";
}
.icon-mustache:before {
content: "\e014";
}
.icon-mouse:before {
content: "\e015";
}
.icon-magnet:before {
content: "\e016";
}
.icon-energy:before {
content: "\e020";
}
.icon-disc:before {
content: "\e022";
}
.icon-cursor:before {
content: "\e06e";
}
.icon-cursor-move:before {
content: "\e023";
}
.icon-crop:before {
content: "\e024";
}
.icon-chemistry:before {
content: "\e026";
}
.icon-speedometer:before {
content: "\e007";
}
.icon-shield:before {
content: "\e00e";
}
.icon-screen-tablet:before {
content: "\e00f";
}
.icon-magic-wand:before {
content: "\e017";
}
.icon-hourglass:before {
content: "\e018";
}
.icon-graduation:before {
content: "\e019";
}
.icon-ghost:before {
content: "\e01a";
}
.icon-game-controller:before {
content: "\e01b";
}
.icon-fire:before {
content: "\e01c";
}
.icon-eyeglass:before {
content: "\e01d";
}
.icon-envelope-open:before {
content: "\e01e";
}
.icon-envelope-letter:before {
content: "\e01f";
}
.icon-bell:before {
content: "\e027";
}
.icon-badge:before {
content: "\e028";
}
.icon-anchor:before {
content: "\e029";
}
.icon-wallet:before {
content: "\e02a";
}
.icon-vector:before {
content: "\e02b";
}
.icon-speech:before {
content: "\e02c";
}
.icon-puzzle:before {
content: "\e02d";
}
.icon-printer:before {
content: "\e02e";
}
.icon-present:before {
content: "\e02f";
}
.icon-playlist:before {
content: "\e030";
}
.icon-pin:before {
content: "\e031";
}
.icon-picture:before {
content: "\e032";
}
.icon-handbag:before {
content: "\e035";
}
.icon-globe-alt:before {
content: "\e036";
}
.icon-globe:before {
content: "\e037";
}
.icon-folder-alt:before {
content: "\e039";
}
.icon-folder:before {
content: "\e089";
}
.icon-film:before {
content: "\e03a";
}
.icon-feed:before {
content: "\e03b";
}
.icon-drop:before {
content: "\e03e";
}
.icon-drawar:before {
content: "\e03f";
}
.icon-docs:before {
content: "\e040";
}
.icon-doc:before {
content: "\e085";
}
.icon-diamond:before {
content: "\e043";
}
.icon-cup:before {
content: "\e044";
}
.icon-calculator:before {
content: "\e049";
}
.icon-bubbles:before {
content: "\e04a";
}
.icon-briefcase:before {
content: "\e04b";
}
.icon-book-open:before {
content: "\e04c";
}
.icon-basket-loaded:before {
content: "\e04d";
}
.icon-basket:before {
content: "\e04e";
}
.icon-bag:before {
content: "\e04f";
}
.icon-action-undo:before {
content: "\e050";
}
.icon-action-redo:before {
content: "\e051";
}
.icon-wrench:before {
content: "\e052";
}
.icon-umbrella:before {
content: "\e053";
}
.icon-trash:before {
content: "\e054";
}
.icon-tag:before {
content: "\e055";
}
.icon-support:before {
content: "\e056";
}
.icon-frame:before {
content: "\e038";
}
.icon-size-fullscreen:before {
content: "\e057";
}
.icon-size-actual:before {
content: "\e058";
}
.icon-shuffle:before {
content: "\e059";
}
.icon-share-alt:before {
content: "\e05a";
}
.icon-share:before {
content: "\e05b";
}
.icon-rocket:before {
content: "\e05c";
}
.icon-question:before {
content: "\e05d";
}
.icon-pie-chart:before {
content: "\e05e";
}
.icon-pencil:before {
content: "\e05f";
}
.icon-note:before {
content: "\e060";
}
.icon-loop:before {
content: "\e064";
}
.icon-home:before {
content: "\e069";
}
.icon-grid:before {
content: "\e06a";
}
.icon-graph:before {
content: "\e06b";
}
.icon-microphone:before {
content: "\e063";
}
.icon-music-tone-alt:before {
content: "\e061";
}
.icon-music-tone:before {
content: "\e062";
}
.icon-earphones-alt:before {
content: "\e03c";
}
.icon-earphones:before {
content: "\e03d";
}
.icon-equalizer:before {
content: "\e06c";
}
.icon-like:before {
content: "\e068";
}
.icon-dislike:before {
content: "\e06d";
}
.icon-control-start:before {
content: "\e06f";
}
.icon-control-rewind:before {
content: "\e070";
}
.icon-control-play:before {
content: "\e071";
}
.icon-control-pause:before {
content: "\e072";
}
.icon-control-forward:before {
content: "\e073";
}
.icon-control-end:before {
content: "\e074";
}
.icon-volume-1:before {
content: "\e09f";
}
.icon-volume-2:before {
content: "\e0a0";
}
.icon-volume-off:before {
content: "\e0a1";
}
.icon-calender:before {
content: "\e075";
}
.icon-bulb:before {
content: "\e076";
}
.icon-chart:before {
content: "\e077";
}
.icon-ban:before {
content: "\e07c";
}
.icon-bubble:before {
content: "\e07d";
}
.icon-camrecorder:before {
content: "\e07e";
}
.icon-camera:before {
content: "\e07f";
}
.icon-cloud-download:before {
content: "\e083";
}
.icon-cloud-upload:before {
content: "\e084";
}
.icon-envelope:before {
content: "\e086";
}
.icon-eye:before {
content: "\e087";
}
.icon-flag:before {
content: "\e088";
}
.icon-heart:before {
content: "\e08a";
}
.icon-info:before {
content: "\e08b";
}
.icon-key:before {
content: "\e08c";
}
.icon-link:before {
content: "\e08d";
}
.icon-lock:before {
content: "\e08e";
}
.icon-lock-open:before {
content: "\e08f";
}
.icon-magnifier:before {
content: "\e090";
}
.icon-magnifier-add:before {
content: "\e091";
}
.icon-magnifier-remove:before {
content: "\e092";
}
.icon-paper-clip:before {
content: "\e093";
}
.icon-paper-plane:before {
content: "\e094";
}
.icon-power:before {
content: "\e097";
}
.icon-refresh:before {
content: "\e098";
}
.icon-reload:before {
content: "\e099";
}
.icon-settings:before {
content: "\e09a";
}
.icon-star:before {
content: "\e09b";
}
.icon-symble-female:before {
content: "\e09c";
}
.icon-symbol-male:before {
content: "\e09d";
}
.icon-target:before {
content: "\e09e";
}
.icon-credit-card:before {
content: "\e025";
}
.icon-paypal:before {
content: "\e608";
}
.icon-social-tumblr:before {
content: "\e00a";
}
.icon-social-twitter:before {
content: "\e009";
}
.icon-social-facebook:before {
content: "\e00b";
}
.icon-social-instagram:before {
content: "\e609";
}
.icon-social-linkedin:before {
content: "\e60a";
}
.icon-social-pintarest:before {
content: "\e60b";
}
.icon-social-github:before {
content: "\e60c";
}
.icon-social-gplus:before {
content: "\e60d";
}
.icon-social-reddit:before {
content: "\e60e";
}
.icon-social-skype:before {
content: "\e60f";
}
.icon-social-dribbble:before {
content: "\e00d";
}
.icon-social-behance:before {
content: "\e610";
}
.icon-social-foursqare:before {
content: "\e611";
}
.icon-social-soundcloud:before {
content: "\e612";
}
.icon-social-spotify:before {
content: "\e613";
}
.icon-social-stumbleupon:before {
content: "\e614";
}
.icon-social-youtube:before {
content: "\e008";
}
.icon-social-dropbox:before {
content: "\e00c";
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,548 @@
/*--------------------------------
avasta Web Font
Generated using nucleoapp.com
-------------------------------- */
@font-face {
font-family: 'avasta';
src: url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/avasta/fonts/avasta.eot');
src: url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/avasta/fonts/avasta.eot') format('embedded-opentype'), url('../font/avasta.woff2') format('woff2'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/avasta/fonts/avasta.woff') format('woff'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/avasta/fonts/avasta.ttf') format('truetype'), url('http://view.jqueryfuns.com/2021/8/26/e73ec354e91f5ab06a7c2f4ae0b80a6f/icons/avasta/fonts/avasta.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/*------------------------
base class definition
-------------------------*/
.icon {
display: inline-block;
font: normal normal normal 1em/1 'avasta';
speak: none;
text-transform: none;
/* Better Font Rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/*------------------------
change icon size
-------------------------*/
/* relative units */
.icon-sm {
font-size: 0.8em;
}
.icon-lg {
font-size: 1.2em;
}
/* absolute units */
.icon-16 {
font-size: 16px;
}
.icon-32 {
font-size: 32px;
}
/*----------------------------------
add a square/circle background
-----------------------------------*/
.icon-bg-square,
.icon-bg-circle {
padding: 0.35em;
background-color: #eee;
}
.icon-bg-circle {
border-radius: 50%;
}
/*------------------------------------
use icons as list item markers
-------------------------------------*/
.icon-ul {
padding-left: 0;
list-style-type: none;
}
.icon-ul > li {
display: flex;
align-items: flex-start;
line-height: 1.4;
}
.icon-ul > li > .icon {
margin-right: 0.4em;
line-height: inherit;
}
/*------------------------
spinning icons
-------------------------*/
.icon-is-spinning {
-webkit-animation: icon-spin 2s infinite linear;
-moz-animation: icon-spin 2s infinite linear;
animation: icon-spin 2s infinite linear;
}
@-webkit-keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes icon-spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*------------------------
rotated/flipped icons
-------------------------*/
.icon-rotate-90 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.icon-rotate-180 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.icon-rotate-270 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
.icon-flip-y {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
-webkit-transform: scale(-1, 1);
-moz-transform: scale(-1, 1);
-ms-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
}
.icon-flip-x {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: scale(1, -1);
-moz-transform: scale(1, -1);
-ms-transform: scale(1, -1);
-o-transform: scale(1, -1);
transform: scale(1, -1);
}
/*------------------------
icons
-------------------------*/
.icon-cloud-download-95::before {
content: "\ea02";
}
.icon-home-minimal::before {
content: "\ea03";
}
.icon-single-04::before {
content: "\ea04";
}
.icon-users-mm::before {
content: "\ea05";
}
.icon-webpage::before {
content: "\ea06";
}
.icon-layout-25::before {
content: "\ea07";
}
.icon-analytics::before {
content: "\ea08";
}
.icon-chart-pie-36::before {
content: "\ea09";
}
.icon-chart-bar-33::before {
content: "\ea0a";
}
.icon-single-copy-06::before {
content: "\ea0b";
}
.icon-home::before {
content: "\ea0c";
}
.icon-single-content-03::before {
content: "\ea0d";
}
.icon-bell-53::before {
content: "\ea0e";
}
.icon-email-84::before {
content: "\ea0f";
}
.icon-send::before {
content: "\ea10";
}
.icon-at-sign::before {
content: "\ea11";
}
.icon-attach-87::before {
content: "\ea12";
}
.icon-edit-72::before {
content: "\ea13";
}
.icon-tail-right::before {
content: "\ea14";
}
.icon-minimal-right::before {
content: "\ea15";
}
.icon-tail-left::before {
content: "\ea16";
}
.icon-minimal-left::before {
content: "\ea17";
}
.icon-tail-up::before {
content: "\ea18";
}
.icon-minimal-up::before {
content: "\ea19";
}
.icon-minimal-down::before {
content: "\ea1a";
}
.icon-tail-down::before {
content: "\ea1b";
}
.icon-settings-gear-64::before {
content: "\ea1c";
}
.icon-settings::before {
content: "\ea1d";
}
.icon-menu-dots::before {
content: "\ea1e";
}
.icon-menu-left::before {
content: "\ea1f";
}
.icon-funnel-40::before {
content: "\ea20";
}
.icon-filter::before {
content: "\ea21";
}
.icon-preferences-circle::before {
content: "\ea22";
}
.icon-check-2::before {
content: "\ea23";
}
.icon-cart-simple::before {
content: "\ea24";
}
.icon-cart-9::before {
content: "\ea25";
}
.icon-card-update::before {
content: "\ea26";
}
.icon-basket::before {
content: "\ea27";
}
.icon-check-circle-07::before {
content: "\ea28";
}
.icon-simple-remove::before {
content: "\ea29";
}
.icon-circle-remove::before {
content: "\ea2a";
}
.icon-alert-circle-exc::before {
content: "\ea2b";
}
.icon-bug::before {
content: "\ea2c";
}
.icon-share-66::before {
content: "\ea2d";
}
.icon-time-3::before {
content: "\ea2e";
}
.icon-time::before {
content: "\ea2f";
}
.icon-coffee::before {
content: "\ea30";
}
.icon-smile::before {
content: "\ea31";
}
.icon-sad::before {
content: "\ea32";
}
.icon-broken-heart::before {
content: "\ea33";
}
.icon-heart-2::before {
content: "\ea34";
}
.icon-pin-3::before {
content: "\ea35";
}
.icon-marker-3::before {
content: "\ea36";
}
.icon-globe-2::before {
content: "\ea37";
}
.icon-world-2::before {
content: "\ea38";
}
.icon-phone-2::before {
content: "\ea39";
}
.icon-check-square-11::before {
content: "\ea3a";
}
.icon-wallet-90::before {
content: "\ea3b";
}
.icon-credit-card::before {
content: "\ea3c";
}
.icon-payment::before {
content: "\ea3d";
}
.icon-tag::before {
content: "\ea3e";
}
.icon-tag-cut::before {
content: "\ea3f";
}
.icon-tag-content::before {
content: "\ea40";
}
.icon-flag-diagonal-33::before {
content: "\ea41";
}
.icon-triangle-right-17::before {
content: "\ea47";
}
.icon-puzzle-10::before {
content: "\ea48";
}
.icon-triangle-right-17-2::before {
content: "\ea49";
}
.icon-btn-play::before {
content: "\ea4a";
}
.icon-btn-play-2::before {
content: "\ea4b";
}
.icon-menu-34::before {
content: "\ea4c";
}
.icon-menu-left-2::before {
content: "\ea4d";
}
.icon-heart-2-2::before {
content: "\ea4e";
}
.icon-single-04-2::before {
content: "\ea4f";
}
.icon-users-mm-2::before {
content: "\ea50";
}
.icon-l-settings::before {
content: "\ea51";
}
.icon-book-open-2::before {
content: "\ea52";
}
.icon-layers-3::before {
content: "\ea53";
}
.icon-logo-fb-simple::before {
content: "\ea55";
}
.icon-logo-twitter::before {
content: "\ea56";
}
.icon-google::before {
content: "\ea57";
}
.icon-logo-pinterest::before {
content: "\ea58";
}
.icon-logo-instagram::before {
content: "\ea59";
}
.icon-logo-dribbble::before {
content: "\ea5a";
}
.icon-tablet-mobile::before {
content: "\ea5b";
}
.icon-house-search-engine::before {
content: "\ea5c";
}
.icon-house-pricing::before {
content: "\ea5d";
}
.icon-pulse-chart::before {
content: "\ea5e";
}
.icon-plug::before {
content: "\ea5f";
}
.icon-app-store::before {
content: "\ea60";
}
.icon-power-level::before {
content: "\ea61";
}
.icon-window-add::before {
content: "\ea62";
}
.icon-form::before {
content: "\ea63";
}
.icon-folder-15::before {
content: "\ea64";
}
.icon-lock::before {
content: "\ea65";
}
.icon-unlocked::before {
content: "\ea66";
}
.icon-e-reader::before {
content: "\ea67";
}
.icon-layout-grid::before {
content: "\ea68";
}
.icon-single-copies::before {
content: "\ea69";
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="">
<meta name="author" content="">
<meta name="robots" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- PAGE TITLE HERE -->
<title>Error</title>
<link href="/css/bootstrap-select.min.css" rel="stylesheet">
<link href="/css/style.css" rel="stylesheet">
</head>
<body class="vh-100">
<div class="authincation h-100">
<div class="container h-100">
<div class="row justify-content-center h-100 align-items-center">
<div class="col-md-5">
<div class="form-input-content text-center error-page">
<h1 class="error-text fw-bold">400</h1>
<h4><i class="fa fa-thumbs-down text-danger"></i> Bad Request</h4>
<p>Your Request resulted in an error</p>
<div>
<a class="btn btn-primary" href="/">Back to Home</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--**********************************
Scripts
***********************************-->
<!-- Required vendors -->
<script src="/js/global.min.js"></script>
<script src="/js/custom.min.js"></script>
<script src="/js/styleSwitcher.js"></script>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="">
<meta name="author" content="">
<meta name="robots" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- PAGE TITLE HERE -->
<title>Error</title>
<link href="/css/style.css" rel="stylesheet">
</head>
<body class="vh-100">
<div class="authincation h-100">
<div class="container h-100">
<div class="row justify-content-center h-100 align-items-center">
<div class="col-md-5">
<div class="form-input-content text-center error-page">
<h1 class="error-text fw-bold">403</h1>
<h4><i class="fa fa-times-circle text-danger"></i> Forbidden Error!</h4>
<p>You do not have permission to view this resource.</p>
<div>
<a class="btn btn-primary" href="/">Back to Home</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--**********************************
Scripts
***********************************-->
<!-- Required vendors -->
<script src="/js/global.min.js"></script>
<script src="/js/custom.min.js"></script>
<script src="/js/styleSwitcher.js"></script>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="">
<meta name="author" content="">
<meta name="robots" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- PAGE TITLE HERE -->
<title>Error</title>
<link href="/css/style.css" rel="stylesheet">
</head>
<body class="vh-100">
<div class="authincation h-100">
<div class="container h-100">
<div class="row justify-content-center h-100 align-items-center">
<div class="col-md-7">
<div class="form-input-content text-center error-page">
<h1 class="error-text fw-bold">404</h1>
<h4><i class="fa fa-exclamation-triangle text-warning"></i> The page you were looking for is not found!</h4>
<p>You may have mistyped the address or the page may have moved.</p>
<div>
<a class="btn btn-primary" href="/">Back to Home</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--**********************************
Scripts
***********************************-->
<!-- Required vendors -->
<script src="/js/global.min.js"></script>
<script src="/js/custom.min.js"></script>
<script src="/js/styleSwitcher.js"></script>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="">
<meta name="author" content="">
<meta name="robots" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- PAGE TITLE HERE -->
<title>Error</title>
<link href="/css/style.css" rel="stylesheet">
</head>
<body class="vh-100">
<div class="authincation h-100">
<div class="container h-100">
<div class="row justify-content-center h-100 align-items-center">
<div class="col-md-5">
<div class="form-input-content text-center error-page">
<h1 class="error-text fw-bold">500</h1>
<h4><i class="fa fa-times-circle text-danger"></i> Internal Server Error</h4>
<p>You do not have permission to view this resource</p>
<div>
<a class="btn btn-primary" href="/">Back to Home</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--**********************************
Scripts
***********************************-->
<!-- Required vendors -->
<script src="/js/global.min.js"></script>
<script src="/js/custom.min.js"></script>
<script src="/js/styleSwitcher.js"></script>
</body>
</html>

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