diff --git a/admin/src/views/user/form.vue b/admin/src/views/user/form.vue
index 962c72c6..a6d84616 100644
--- a/admin/src/views/user/form.vue
+++ b/admin/src/views/user/form.vue
@@ -20,6 +20,22 @@
+
+
+
+
+
+
+
+
+
+
+
Submit
@@ -47,11 +63,14 @@ export default {
const { id } = route.query
const state = reactive({
id: id,
+ userClasses: [],
formData: {
username: '',
email: '',
password: '',
password_confirmation: '',
+ id: '',
+ class: ''
},
rules: {
username: [
@@ -68,8 +87,8 @@ export default {
],
},
})
- onMounted( () => {
-
+ onMounted( async () => {
+ await listAllClass()
})
onBeforeUnmount(() => {
@@ -83,6 +102,12 @@ export default {
}
})
}
+
+ const listAllClass = async () => {
+ let res = await api.listClass()
+ state.userClasses = res.data
+ }
+
return {
...toRefs(state),
formRef,
diff --git a/app/Http/Resources/TorrentResource.php b/app/Http/Resources/TorrentResource.php
index e787bc64..d2baf86d 100644
--- a/app/Http/Resources/TorrentResource.php
+++ b/app/Http/Resources/TorrentResource.php
@@ -33,9 +33,16 @@ class TorrentResource extends JsonResource
'seeders' => $this->seeders,
'times_completed' => $this->times_completed,
'numfiles' => $this->numfiles,
+ 'sp_state' => $this->sp_state,
+ 'sp_state_real' => $this->sp_state_real,
+ 'sp_state_real_text' => $this->spStateRealText,
+ 'hr' => $this->hr,
+ 'pick_type' => $this->picktype,
+ 'pick_time' => $this->picktime,
'download_url' => $this->download_url,
'user' => new UserResource($this->whenLoaded('user')),
'basic_category' => new CategoryResource($this->whenLoaded('basic_category')),
+ 'tags' => TagResource::collection($this->whenLoaded('tags')),
];
$descriptionArr = format_description($this->descr);
$out['cover'] = get_image_from_description($descriptionArr, true);
diff --git a/app/Models/Torrent.php b/app/Models/Torrent.php
index 85d9ded0..e29e0353 100644
--- a/app/Models/Torrent.php
+++ b/app/Models/Torrent.php
@@ -2,6 +2,8 @@
namespace App\Models;
+use App\Repositories\TagRepository;
+
class Torrent extends NexusModel
{
protected $fillable = [
@@ -9,9 +11,11 @@ class Torrent extends NexusModel
'category', 'source', 'medium', 'codec', 'standard', 'processing', 'team', 'audiocodec',
'size', 'added', 'type', 'numfiles', 'owner', 'nfo', 'sp_state', 'promotion_time_type',
'promotion_until', 'anonymous', 'url', 'pos_state', 'cache_stamp', 'picktype', 'picktime',
- 'last_reseed', 'pt_gen', 'tags', 'technical_info'
+ 'last_reseed', 'pt_gen', 'technical_info'
];
+ private static $globalPromotionState;
+
const VISIBLE_YES = 'yes';
const VISIBLE_NO = 'no';
@@ -49,6 +53,59 @@ class Torrent extends NexusModel
self::HR_YES => ['text' => 'YES'],
];
+ const PROMOTION_NORMAL = 1;
+ const PROMOTION_FREE = 2;
+ const PROMOTION_TWO_TIMES_UP = 3;
+ const PROMOTION_FREE_TWO_TIMES_UP = 4;
+ const PROMOTION_HALF_DOWN = 5;
+ const PROMOTION_HALF_DOWN_TWO_TIMES_UP = 6;
+ const PROMOTION_ONE_THIRD_DOWN = 7;
+
+ public static $promotionTypes = [
+ self::PROMOTION_NORMAL => ['text' => 'Normal', 'up_multiplier' => 1, 'down_multiplier' => 1],
+ self::PROMOTION_FREE => ['text' => 'Free', 'up_multiplier' => 1, 'down_multiplier' => 0],
+ self::PROMOTION_TWO_TIMES_UP => ['text' => '2X', 'up_multiplier' => 2, 'down_multiplier' => 1],
+ self::PROMOTION_FREE_TWO_TIMES_UP => ['text' => '2X Free', 'up_multiplier' => 2, 'down_multiplier' => 0],
+ self::PROMOTION_HALF_DOWN => ['text' => '50%', 'up_multiplier' => 1, 'down_multiplier' => 0.5],
+ self::PROMOTION_HALF_DOWN_TWO_TIMES_UP => ['text' => '2X 50%', 'up_multiplier' => 2, 'down_multiplier' => 0.5],
+ self::PROMOTION_ONE_THIRD_DOWN => ['text' => '30%', 'up_multiplier' => 1, 'down_multiplier' => 0.3],
+ ];
+
+ public function getSpStateRealTextAttribute()
+ {
+ $spStateReal = $this->sp_state_real;
+ return self::$promotionTypes[$spStateReal]['text'] ?? '';
+ }
+
+ public function getSpStateRealAttribute()
+ {
+ $spState = $this->sp_state;
+ $global = self::getGlobalPromotionState();
+ $log = sprintf('torrent: %s sp_state: %s, global sp state: %s', $this->id, $spState, $global);
+ if ($global != self::PROMOTION_NORMAL) {
+ $spState = $global;
+ $log .= sprintf(", global != %s, set sp_state to global: %s", self::PROMOTION_NORMAL, $global);
+ }
+ if (!isset(self::$promotionTypes[$spState])) {
+ $log .= ", but now sp_state: $spState, is invalid, reset to: " . self::PROMOTION_NORMAL;
+ $spState = self::PROMOTION_NORMAL;
+ }
+ do_log($log, 'debug');
+ return $spState;
+ }
+
+ public static function getGlobalPromotionState()
+ {
+ if (is_null(self::$globalPromotionState)) {
+ $result = TorrentState::query()->first(['global_sp_state']);
+ if (!$result) {
+ do_log("global sp state no value", 'error');
+ }
+ self::$globalPromotionState = $result->global_sp_state ?? false;
+ }
+ return self::$globalPromotionState;
+ }
+
public function getHrAttribute(): string
{
$hrMode = Setting::get('hr.mode');
@@ -208,6 +265,7 @@ class Torrent extends NexusModel
public function tags(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
- return $this->belongsToMany(Tag::class, 'torrent_tags', 'torrent_id', 'tag_id');
+ return $this->belongsToMany(Tag::class, 'torrent_tags', 'torrent_id', 'tag_id')
+ ->orderByRaw(sprintf("field(`tags`.`id`,%s)", TagRepository::getOrderByFieldIdString()));
}
}
diff --git a/app/Models/TorrentState.php b/app/Models/TorrentState.php
new file mode 100644
index 00000000..fbe8f7b7
--- /dev/null
+++ b/app/Models/TorrentState.php
@@ -0,0 +1,11 @@
+createBasicQuery();
@@ -41,7 +43,7 @@ class TagRepository extends BaseRepository
return $result;
}
- public function createBasicQuery()
+ public static function createBasicQuery()
{
return Tag::query()->orderBy('priority', 'desc')->orderBy('id', 'desc');
}
@@ -127,5 +129,14 @@ class TagRepository extends BaseRepository
return count($values);
}
+ public static function getOrderByFieldIdString()
+ {
+ if (is_null(self::$orderByFieldIdString)) {
+ $results = self::createBasicQuery()->get(['id']);
+ self::$orderByFieldIdString = $results->isEmpty() ? '0' : $results->implode('id', ',');
+ }
+ return self::$orderByFieldIdString;
+ }
+
}
diff --git a/app/Repositories/TorrentRepository.php b/app/Repositories/TorrentRepository.php
index 6a98285a..caf75f9c 100644
--- a/app/Repositories/TorrentRepository.php
+++ b/app/Repositories/TorrentRepository.php
@@ -82,7 +82,7 @@ class TorrentRepository extends BaseRepository
$query = $this->handleGetListSort($query, $params);
- $with = ['user'];
+ $with = ['user', 'tags'];
$torrents = $query->with($with)->paginate();
$userArr = $user->toArray();
foreach($torrents as &$item) {
diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php
index a70a4250..a9b990f3 100644
--- a/app/Repositories/UserRepository.php
+++ b/app/Repositories/UserRepository.php
@@ -66,27 +66,61 @@ class UserRepository extends BaseRepository
];
}
+ /**
+ * create user
+ *
+ * @param array $params must: username, email, password, password_confirmation. optional: id, class
+ * @return User
+ */
public function store(array $params)
{
$password = $params['password'];
if ($password != $params['password_confirmation']) {
throw new \InvalidArgumentException("password confirmation != password");
}
-
+ $username = $params['username'];
+ if (!validusername($username)) {
+ throw new \InvalidArgumentException("Innvalid username: $username");
+ }
+ $email = htmlspecialchars(trim($params['email']));
+ $email = safe_email($email);
+ if (!check_email($email)) {
+ throw new \InvalidArgumentException("Innvalid email: $email");
+ }
+ if (User::query()->where('email', $email)->exists()) {
+ throw new \InvalidArgumentException("The email address: $email is already in use");
+ }
+ if (mb_strlen($password) < 6 || mb_strlen($password) > 40) {
+ throw new \InvalidArgumentException("Innvalid password: $password, it should be more than 6 character and less than 40 character");
+ }
+ $class = !empty($params['class']) ? intval($params['class']) : User::CLASS_USER;
+ if (!isset(User::$classes[$class])) {
+ throw new \InvalidArgumentException("Invalid user class: $class");
+ }
$setting = Setting::get('main');
$secret = mksecret();
$passhash = md5($secret . $password . $secret);
$data = [
- 'username' => $params['username'],
- 'email' => $params['email'],
+ 'username' => $username,
+ 'email' => $email,
'secret' => $secret,
'editsecret' => '',
'passhash' => $passhash,
'stylesheet' => $setting['defstylesheet'],
'added' => now()->toDateTimeString(),
'status' => User::STATUS_CONFIRMED,
+ 'class' => $class
];
- $user = User::query()->create($data);
+ $user = new User($data);
+ if ($params['id']) {
+ if (User::query()->where('id', $params['id'])->exists()) {
+ throw new \InvalidArgumentException("uid: {$params['id']} already exists.");
+ }
+ do_log("[CREATE_USER], specific id: " . $params['id']);
+ $user->id = $params['id'];
+ }
+ $user->save();
+
return $user;
}
diff --git a/database/migrations/2021_06_08_113437_create_users_table.php b/database/migrations/2021_06_08_113437_create_users_table.php
index 444fc4d7..dc9d78f2 100644
--- a/database/migrations/2021_06_08_113437_create_users_table.php
+++ b/database/migrations/2021_06_08_113437_create_users_table.php
@@ -17,7 +17,7 @@ class CreateUsersTable extends Migration
return;
}
Schema::create('users', function (Blueprint $table) {
- $table->increments('id');
+ $table->id('id')->startingValue(10001);
$table->string('username', 40)->default('')->unique('username');
$table->string('passhash', 32)->default('');
$table->binary('secret');
@@ -133,6 +133,7 @@ class CreateUsersTable extends Migration
$table->enum('showfb', ['yes', 'no'])->default('yes');
$table->string('page')->nullable()->default('');
$table->index(['status', 'added'], 'status_added');
+
});
}
diff --git a/include/cleanup.php b/include/cleanup.php
index f472a5cb..6b8d3749 100644
--- a/include/cleanup.php
+++ b/include/cleanup.php
@@ -168,7 +168,9 @@ function user_to_peasant($down_floor_gb, $minratio){
function ban_user_with_leech_warning_expired()
{
$dt = date("Y-m-d H:i:s"); // take date time
+ // VIP or above won't effect
$results = \App\Models\User::query()
+ ->where('class', '<', \App\Models\User::CLASS_VIP)
->where('enabled', \App\Models\User::ENABLED_YES)
->where('leechwarn', 'yes')
->where('leechwarnuntil', '<', $dt)
diff --git a/nexus/Install/Install.php b/nexus/Install/Install.php
index cabfedc4..72457251 100644
--- a/nexus/Install/Install.php
+++ b/nexus/Install/Install.php
@@ -2,6 +2,8 @@
namespace Nexus\Install;
+use App\Models\User;
+use App\Repositories\UserRepository;
use Illuminate\Support\Str;
use Nexus\Database\NexusDB;
@@ -384,44 +386,22 @@ class Install
public function createAdministrator($username, $email, $password, $confirmPassword)
{
- $count = get_row_count('users', 'where class = 16');
+ $class = User::CLASS_STAFF_LEADER;
+ $count = get_row_count('users', 'where class = ' . $class);
if ($count > 0) {
throw new \InvalidArgumentException("Administrator already exists");
}
- if (!validusername($username)) {
- throw new \InvalidArgumentException("Innvalid username: $username");
- }
- $email = htmlspecialchars(trim($email));
- $email = safe_email($email);
- if (!check_email($email)) {
- throw new \InvalidArgumentException("Innvalid email: $email");
- }
- $res = sql_query("SELECT id FROM users WHERE email=" . sqlesc($email));
- $arr = mysql_fetch_row($res);
- if ($arr) {
- throw new \InvalidArgumentException("The email address: $email is already in use");
- }
- if (mb_strlen($password) < 6 || mb_strlen($password) > 40) {
- throw new \InvalidArgumentException("Innvalid password: $password, it should be more than 6 character and less than 40 character");
- }
- if ($password != $confirmPassword) {
- throw new \InvalidArgumentException("confirmPassword: $confirmPassword != password");
- }
- $setting = get_setting('main');
- $secret = mksecret();
- $passhash = md5($secret . $password . $secret);
- $insert = [
+ $data = [
'username' => $username,
- 'passhash' => $passhash,
- 'secret' => $secret,
'email' => $email,
- 'stylesheet' => $setting['defstylesheet'],
- 'class' => 16,
- 'status' => 'confirmed',
- 'added' => date('Y-m-d H:i:s'),
+ 'password' => $password,
+ 'password_confirmation' => $confirmPassword,
+ 'class' => $class,
+ 'id' => 1,
];
- $this->doLog("[CREATE ADMINISTRATOR] " . json_encode($insert));
- return NexusDB::insert('users', $insert);
+ $user = (new UserRepository())->store($data);
+ $this->doLog("[CREATE ADMINISTRATOR] " . $user->toJson());
+ return $user;
}
public function createEnvFile($data, $scene = 'install')