nexus clients

This commit is contained in:
xiaomlove
2021-04-21 00:07:32 +08:00
parent be9b8634c4
commit c7a6616618
23 changed files with 897 additions and 31 deletions

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
class Test extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Just for test';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
dd(strlen(Hash::make('123456')));
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Http\Requests\AgentAllowRequest;
use App\Http\Resources\AgentAllowResource;
use App\Models\AgentAllow;
use Illuminate\Http\Request;
@@ -24,11 +25,13 @@ class AgentAllowController extends Controller
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @return array
*/
public function store(Request $request)
public function store(AgentAllowRequest $request)
{
//
$result = AgentAllow::query()->create($request->all());
$resource = new AgentAllowResource($result);
return success('agent allow store', $resource);
}
/**
@@ -47,21 +50,26 @@ class AgentAllowController extends Controller
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
* @return array
*/
public function update(Request $request, $id)
{
//
$result = AgentAllow::query()->findOrFail($id);
$result->update($request->all());
$resource = new AgentAllowResource($result);
return success('agent allow update', $resource);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
* @return array
*/
public function destroy($id)
{
//
$result = AgentAllow::query()->findOrFail($id);
$success = $result->delete();
return success('agent allow delete', $success);
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace App\Http\Controllers;
use App\Http\Resources\UserResource;
use App\Models\User;
use App\Repositories\UserRepository;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* @return array
*/
public function index(Request $request)
{
$result = (new UserRepository())->getList($request->all());
$resource = UserResource::collection($result);
return success('user list', $resource);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function store(Request $request)
{
$result = (new UserRepository())->store($request->all());
$resource = new UserResource($result);
return success('user store', $resource);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return array
*/
public function update(Request $request, $id)
{
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return array
*/
public function destroy($id)
{
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class AgentAllowRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'family' => 'required|string',
'start_name' => 'required|string',
'peer_id_pattern' => 'required|string',
'peer_id_match_num' => 'required|numeric',
'peer_id_matchtype' => 'required|in:hex,dec',
'peer_id_start' => 'required|string',
'agent_pattern' => 'required|string',
'agent_match_num' => 'required|numeric',
'agent_matchtype' => 'required|in:hex,dec',
'agent_start' => 'required|string',
'exception' => 'required|in:yes,no',
'allowhttps' => 'required|in:yes,no',
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'username' => $this->username,
'uploaded' => $this->uploaded,
'downloaded' => $this->downloaded,
];
}
}

View File

@@ -11,5 +11,7 @@ class NexusModel extends Model
public $timestamps = false;
protected $casts = [
'added' => 'datetime'
];
}

View File

@@ -17,9 +17,7 @@ class User extends Authenticatable
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'username', 'email', 'passhash', 'secret', 'status', 'added'
];
/**
@@ -28,8 +26,7 @@ class User extends Authenticatable
* @var array
*/
protected $hidden = [
'password',
'remember_token',
'passhash', 'secret'
];
/**
@@ -38,6 +35,6 @@ class User extends Authenticatable
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'added' => 'datetime',
];
}

View File

@@ -0,0 +1,86 @@
<?php
namespace App\Repositories;
use App\Models\User;
use Illuminate\Support\Facades\Log;
class UserRepository
{
public function store(array $params)
{
$required = ['username', 'email', 'password', 'password_confirmation'];
foreach ($required as $field) {
if (empty($params[$field])) {
throw new \InvalidArgumentException("Require $field");
}
}
$username = $params['username'];
$email = $params['email'];
$password = $params['password'];
$confirmPassword = $params['password_confirmation'];
if (!validusername($username)) {
throw new \InvalidArgumentException("Invalid username: $username");
}
$email = htmlspecialchars(trim($email));
$email = safe_email($email);
if (!check_email($email)) {
throw new \InvalidArgumentException("Invalid email: $email");
}
$exists = User::query()->where('email', $email)->exists();
if ($exists) {
throw new \InvalidArgumentException("The email address: $email is already in use");
}
if (mb_strlen($password) < 6 || mb_strlen($password) > 40) {
throw new \InvalidArgumentException("Invalid password: $password, it should be more than 6 character and less than 40 character");
}
if ($password != $confirmPassword) {
throw new \InvalidArgumentException("confirmPassword: $confirmPassword != password: $password");
}
$setting = get_setting('main');
$secret = mksecret();
$passhash = md5($secret . $password . $secret);
$insert = [
'username' => $username,
'passhash' => $passhash,
'secret' => $secret,
'email' => $email,
'stylesheet' => $setting['defstylesheet'],
'status' => 'confirmed',
'added' => now()->toDateTimeString(),
];
Log::info("create user: " . nexus_json_encode($insert));
return User::query()->create($insert);
}
public function getList(array $params)
{
$query = User::query();
$sortField = 'id';
$validSortFields = ['uploaded', 'downloaded', ];
if (!empty($params['sort']) && in_array($params['sort'], $validSortFields)) {
$sortField = $params['sort'];
}
$fields = ['id', 'username', 'avatar', 'email', 'uploaded', 'downloaded', 'class', 'added'];
if (!empty($params['fields'])) {
$fields = $params['fields'];
}
if (!empty($params['id'])) {
$query->where('id', $params['id']);
}
if (!empty($params['username'])) {
$query->where('username', $params['username']);
}
if (!empty($params['email'])) {
$query->where('email', $params['email']);
}
$result = $query->orderBy($sortField, 'desc')->select($fields)->paginate();
return $result;
}
}

View File

@@ -17,7 +17,8 @@
"Database\\Seeders\\": "database/seeders/"
},
"files": [
"include/globalfunctions.php"
"include/globalfunctions.php",
"include/functions.php"
]
},
"require": {

View File

@@ -37,7 +37,7 @@ return [
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single'],
'channels' => ['daily'],
'ignore_exceptions' => false,
],

View File

@@ -10,7 +10,6 @@ $showversion = " - Powered by ".PROJECTNAME;
$rootpath= dirname(__DIR__);
set_include_path(get_include_path() . PATH_SEPARATOR . $rootpath);
$rootpath .= "/";
require $rootpath . 'include/functions.php';
require $rootpath . 'classes/class_advertisement.php';
require $rootpath . 'classes/class_attendance.php';
require $rootpath . 'include/core.php';

View File

@@ -11,7 +11,7 @@ if (!file_exists($rootpath . '.env')) {
$installScriptRelativePath = 'install/install.php';
$installScriptFile = $rootpath . "public/$installScriptRelativePath";
if (file_exists($installScriptFile)) {
redirect($installScriptRelativePath);
nexus_redirect($installScriptRelativePath);
}
}
require $rootpath . 'vendor/autoload.php';

View File

@@ -1251,7 +1251,7 @@ function allowedemails()
return $list['value'];
}
function redirect($url)
function nexus_redirect($url)
{
if (substr($url, 0, 4) != 'http') {
$url = getSchemeAndHttpHost() . '/' . trim($url, '/');

View File

@@ -428,6 +428,12 @@ function getBaseUrl()
return trim($url, '/');
}
function nexus_json_encode($data)
{
return json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
}
function api(...$args)
{
if (!isset($args[2])) {
@@ -459,7 +465,7 @@ function api(...$args)
'ret' => (int)$ret,
'msg' => (string)$msg,
'data' => $data,
'timeuse' => (float)number_format(microtime(true) - $start, 3),
'time' => (float)number_format(microtime(true) - $start, 3),
];
}

41
lang/chs/lang_clients.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
$lang_clients = [
'client_management' => '客户端管理',
'text_manage' => '管理',
'text_add' => '添加',
'text_client' => '客户端',
'text_delete' => '删除',
'text_edit' => '编辑',
'col_id' => 'ID',
'col_name' => 'Name',
'col_name_help' => '仅允许数字、字母、下划线',
'col_label' => '显示标签',
'col_type' => '类型',
'col_required' => '不能为空',
'col_help' => '辅助说明',
'col_options' => '选项',
'col_options_help' => '类型为单选、多选、下拉时必填,一行一个,格式:选项值|选项描述文本',
'col_action' => '操作',
'col_is_single_row' => '展示时单独一行',
'col_family' => '家族',
'col_start_name' => '起始名称',
'col_peer_id_pattern' => 'Peer 正则',
'col_peer_id_match_num' => 'Peer 匹配次数',
'col_peer_id_matchtype' => 'Peer 匹配类型',
'col_peer_id_start' => 'Peer 起始',
'col_agent_pattern' => 'Agent 正则',
'col_agent_match_num' => 'Agent 匹配次数',
'col_agent_matchtype' => 'Agent 匹配类型',
'col_agent_start' => 'Agent 起始',
'js_sure_to_delete_this' => '你确信要删除此项目吗?',
'submit_submit' => '提交',
'client_type_text' => '短文本',
'client_type_textarea' => '长文本',
'client_type_radio' => '横向单选',
'client_type_checkbox' => '横向多选',
'client_type_select' => '下拉单选',
'client_type_image' => '图片',
];

463
nexus/Client/Client.php Normal file
View File

@@ -0,0 +1,463 @@
<?php
namespace Nexus\Client;
use Nexus\Core\Management;
use Nexus\Database\DB;
class Client extends Management
{
const TYPE_ALLOW = 'allow';
const TYPE_DENY = 'deny';
private static $types = [
self::TYPE_ALLOW => [
'table' => 'agent_allowed_family',
'table_columns' => [
'id', 'family', 'start_name',
// 'peer_id_pattern', 'peer_id_match_num', 'peer_id_matchtype', 'peer_id_start',
'agent_pattern', 'agent_match_num', 'agent_matchtype', 'agent_start',
],
'form_fields' => [
'family', 'start_name',
'peer_id_pattern', 'peer_id_match_num', 'peer_id_matchtype', 'peer_id_start',
'agent_pattern', 'agent_match_num', 'agent_matchtype', 'agent_start',
'exception', 'allowhttps', 'comment',
],
],
];
private $type;
public function __construct($type)
{
if (!isset(self::$types[$type])) {
throw new \InvalidArgumentException("Invalid type: $type");
}
$this->type = $type;
}
public function getTypeHuman($type)
{
global $lang_fields;
$map = [
self::TYPE_TEXT => $lang_fields['field_type_text'],
self::TYPE_TEXTAREA => $lang_fields['field_type_textarea'],
self::TYPE_RADIO => $lang_fields['field_type_radio'],
self::TYPE_CHECKBOX => $lang_fields['field_type_checkbox'],
self::TYPE_SELECT => $lang_fields['field_type_select'],
self::TYPE_IMAGE => $lang_fields['field_type_image'],
];
return $map[$type] ?? '';
}
public function getTypeRadioOptions()
{
$out = [];
foreach (self::$types as $key => $value) {
$out[$key] = sprintf('%s(%s)', $value['text'], $this->getTypeHuman($key));
}
return $out;
}
public function radio($name, $options, $current = null)
{
$arr = [];
foreach ($options as $value => $label) {
$arr[] = sprintf(
'<label style="margin-right: 4px;"><input type="radio" name="%s" value="%s"%s />%s</label>',
$name, $value, (string)$current === (string)$value ? ' checked' : '', $label
);
}
return implode('', $arr);
}
function buildFieldForm(array $row = [])
{
global $lang_fields, $lang_functions;
$trName = tr($lang_fields['col_name'] . '<font color="red">*</font>', '<input type="text" name="name" value="' . ($row['name'] ?? '') . '" style="width: 300px" />&nbsp;&nbsp;' . $lang_fields['col_name_help'], 1, '', true);
$trLabel = tr($lang_fields['col_label'] . '<font color="red">*</font>', '<input type="text" name="label" value="' . ($row['label'] ?? '') . '" style="width: 300px" />', 1, '', true);
$trType = tr($lang_fields['col_type'] . '<font color="red">*</font>', $this->radio('type', $this->getTypeRadioOptions(), $row['type'] ?? null), 1, '', true);
$trRequired = tr($lang_fields['col_required'] . '<font color="red">*</font>', $this->radio('required', ['0' => $lang_functions['text_no'], '1' => $lang_functions['text_yes']], $row['required'] ?? null), 1, '', true);
$trHelp = tr($lang_fields['col_help'], '<textarea name="help" rows="4" cols="80">' . ($row['help'] ?? '') . '</textarea>', 1, '', true);
$trOptions = tr($lang_fields['col_options'], '<textarea name="options" rows="6" cols="80">' . ($row['options'] ?? '') . '</textarea><br/>' . $lang_fields['col_options_help'], 1, '', true);
$trIsSingleRow = tr($lang_fields['col_is_single_row'] . '<font color="red">*</font>', $this->radio('is_single_row', ['0' => $lang_functions['text_no'], '1' => $lang_functions['text_yes']], $row['is_single_row'] ?? null), 1, '', true);
$id = $row['id'] ?? 0;
$form = <<<HTML
<div>
<h1 align="center"><a class="faqlink" href="?action=view">{$lang_fields['text_field']}</a></h1>
<form method="post" action="fields.php?action=submit">
<div>
<table border="1" cellspacing="0" cellpadding="10" width="100%">
<input type="hidden" name="id" value="{$id}"/>
{$trName}
{$trLabel}
{$trType}
{$trRequired}
{$trHelp}
{$trOptions}
{$trIsSingleRow}
</table>
</div>
<div style="text-align: center; margin-top: 10px;">
<input type="submit" value="{$lang_fields['submit_submit']}" />
</div>
</form>
</div>
HTML;
return $form;
}
private function getHeader()
{
global $lang_clients;
$header = [];
foreach (self::$types[$this->type]['table_columns'] as $column) {
$header[$column] = $lang_clients['col_' . $column] ?? ucfirst($column);
}
$header['action'] = $lang_clients['col_action'];
return $header;
}
function buildClientTable()
{
global $lang_clients, $lang_functions;
$tableName = self::$types[$this->type]['table'];
$perPage = 10;
$total = get_row_count($tableName);
list($paginationTop, $paginationBottom, $limit) = pager($perPage, $total, "?");
$sql = "select * from $tableName order by family asc $limit";
$res = sql_query($sql);
$header = $this->getHeader();
$rows = [];
while ($row = mysql_fetch_assoc($res)) {
$row['action'] = sprintf(
"<a href=\"javascript:confirm_delete('%s', '%s', '');\">%s</a> | <a href=\"?action=edit&id=%s\">%s</a>",
$row['id'], $lang_clients['js_sure_to_delete_this'], $lang_clients['text_delete'], $row['id'], $lang_clients['text_edit']
);
$rows[] = $row;
}
$head = <<<HEAD
<h1 align="center">{$lang_clients['client_management']}</h1>
<div style="margin-bottom: 8px;">
<span id="add">
<a href="?action=add" class="big"><b>{$lang_clients['text_add']}</b></a>
</span>
</div>
HEAD;
$table = $this->buildTable($header, $rows);
return $head . $table . $paginationBottom;
}
public function save($data)
{
global $lang_functions, $lang_fields;
$attributes = [];
if (empty($data['name'])) {
throw new \InvalidArgumentException("{$lang_fields['col_name']} {$lang_functions['text_required']}");
}
if (!preg_match('/^\w+$/', $data['name'])) {
throw new \InvalidArgumentException("{$lang_fields['col_name']} {$lang_functions['text_invalid']}");
}
$attributes['name'] = $data['name'];
if (empty($data['label'])) {
throw new \InvalidArgumentException("{$lang_fields['col_label']} {$lang_functions['text_required']}");
}
$attributes['label'] = $data['label'];
if (empty($data['type'])) {
throw new \InvalidArgumentException("{$lang_fields['col_type']} {$lang_functions['text_required']}");
}
if (!isset(self::$types[$data['type']])) {
throw new \InvalidArgumentException("{$lang_fields['col_type']} {$lang_functions['text_invalid']}");
}
$attributes['type'] = $data['type'];
if (!isset($data['required'])) {
throw new \InvalidArgumentException("{$lang_fields['col_required']} {$lang_functions['text_required']}");
}
if (!in_array($data['required'], ["0", "1"], true)) {
throw new \InvalidArgumentException("{$lang_fields['col_name']} {$lang_functions['text_invalid']}");
}
$attributes['required'] = $data['required'];
if (!isset($data['is_single_row'])) {
throw new \InvalidArgumentException("{$lang_fields['col_is_single_row']} {$lang_functions['text_required']}");
}
if (!in_array($data['is_single_row'], ["0", "1"], true)) {
throw new \InvalidArgumentException("{$lang_fields['col_is_single_row']} {$lang_functions['text_invalid']}");
}
$attributes['is_single_row'] = $data['is_single_row'];
$attributes['help'] = $data['help'] ?? '';
$attributes['options'] = trim($data['options'] ?? '');
$now = date('Y-m-d H:i:s');
$attributes['updated_at'] = $now;
$table = 'torrents_custom_fields';
if (!empty($data['id'])) {
$result = DB::update($table, $attributes, "id = " . sqlesc($data['id']));
} else {
$attributes['created_at'] = $now;
$result = DB::insert($table, $attributes);
}
return $result;
}
public function buildFieldCheckbox($name, $current = [])
{
$sql = 'select * from torrents_custom_fields';
$res = sql_query($sql);
if (!is_array($current)) {
$current = explode(',', $current);
}
$checkbox = '';
while ($row = mysql_fetch_assoc($res)) {
$checkbox .= sprintf(
'<label style="margin-right: 4px;"><input type="checkbox" name="%s" value="%s"%s>%s</label>',
$name, $row['id'], in_array($row['id'], $current) ? ' checked' : '', "{$row['name']}[{$row['label']}]"
);
}
$checkbox .= '';
return $checkbox;
}
public function renderOnUploadPage($torrentId = 0)
{
global $browsecatmode;
$searchBox = DB::getOne('searchbox', "id = $browsecatmode");
if (empty($searchBox)) {
throw new \RuntimeException("Invalid search box: $browsecatmode");
}
$customValues = $this->listTorrentCustomField($torrentId);
$sql = sprintf('select * from torrents_custom_fields where id in (%s)', $searchBox['custom_fields'] ?: 0);
$res = sql_query($sql);
$html = '';
while ($row = mysql_fetch_assoc($res)) {
$name = "custom_fields[{$row['id']}]";
$currentValue = $customValues[$row['id']]['custom_field_value'] ?? '';
if ($row['type'] == self::TYPE_TEXT) {
$html .= tr($row['label'], sprintf('<input type="text" name="%s" value="%s" style="width: 650px"/>', $name, $currentValue), 1);
} elseif ($row['type'] == self::TYPE_TEXTAREA) {
$html .= tr($row['label'], sprintf('<textarea name="%s" rows="4" style="width: 650px">%s</textarea>', $name, $currentValue), 1);
} elseif ($row['type'] == self::TYPE_RADIO || $row['type'] == self::TYPE_CHECKBOX) {
if ($row['type'] == self::TYPE_CHECKBOX) {
$name .= '[]';
}
$part = "";
foreach (preg_split('/[\r\n]+/', trim($row['options'])) as $option) {
if (empty($option) || ($pos = strpos($option, '|')) === false) {
continue;
}
$value = substr($option, 0, $pos);
$label = substr($option, $pos + 1);
$checked = "";
if ($row['type'] == self::TYPE_RADIO && (string)$currentValue === (string)$value) {
$checked = " checked";
}
if ($row['type'] == self::TYPE_CHECKBOX && in_array($value, (array)$currentValue)) {
$checked = " checked";
}
$part .= sprintf(
'<label style="margin-right: 4px"><input type="%s" name="%s" value="%s"%s />%s</label>',
$row['type'], $name, $value, $checked, $label
);
}
$html .= tr($row['label'], $part, 1);
} elseif ($row['type'] == self::TYPE_SELECT) {
$part = '<select name="' . $name . '">';
foreach (preg_split('/[\r\n]+/', trim($row['options'])) as $option) {
if (empty($option) || ($pos = strpos($option, '|')) === false) {
continue;
}
$value = substr($option, 0, $pos);
$label = substr($option, $pos + 1);
$selected = "";
if (in_array($value, (array)$currentValue)) {
$selected = " selected";
}
$part .= sprintf(
'<option value="%s"%s>%s</option>',
$value, $selected, $label
);
}
$part .= '</select>';
$html .= tr($row['label'], $part, 1);
} elseif ($row['type'] == self::TYPE_IMAGE) {
$callbackFunc = "preview_custom_field_image_" . $row['id'];
$iframeId = "iframe_$callbackFunc";
$inputId = "input_$callbackFunc";
$imgId = "attach" . $row['id'];
$previewBoxId = "preview_$callbackFunc";
$y = '<iframe id="' . $iframeId . '" src="' . getSchemeAndHttpHost() . '/attachment.php?callback_func=' . $callbackFunc . '" width="100%" height="24" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>';
$y .= sprintf('<input id="%s" type="text" name="%s" value="%s" style="width: 650px;margin: 10px 0">', $inputId, $name, $currentValue);
$y .= '<div id="' . $previewBoxId . '">';
if (!empty($currentValue)) {
if (substr($currentValue, 0, 4) == 'http') {
$y .= formatImg($currentValue, true, 700, 0, $imgId);
} else {
$y .= format_comment($currentValue);
}
}
$y .= '</div>';
$y .= <<<JS
<script>
function {$callbackFunc}(delkey, url)
{
var previewBox = $('$previewBoxId')
var existsImg = $('$imgId')
var input = $('$inputId')
if (existsImg) {
previewBox.removeChild(existsImg)
input.value = ''
}
var img = document.createElement('img')
img.src=url
img.setAttribute('onload', 'Scale(this, 700, 0);')
img.setAttribute('onclick', 'Preview(this);')
input.value = '[attach]' + delkey + '[/attach]'
img.id='$imgId'
previewBox.appendChild(img)
}
</script>
JS;
$html .= tr($row['label'], $y, 1);
}
}
return $html;
}
public function listTorrentCustomField($torrentId, $searchBoxId = 0)
{
global $browsecatmode;
if ($searchBoxId <= 0) {
$searchBoxId = $browsecatmode;
}
//suppose torrentId is array
$isArray = true;
$torrentIdArr = $torrentId;
if (!is_array($torrentId)) {
$isArray = false;
$torrentIdArr = [$torrentId];
}
$torrentIdStr = implode(',', $torrentIdArr);
$res = sql_query("select f.*, v.custom_field_value, v.torrent_id from torrents_custom_field_values v inner join torrents_custom_fields f on v.custom_field_id = f.id inner join searchbox box on box.id = $searchBoxId and find_in_set(f.id, box.custom_fields) where torrent_id in ($torrentIdStr)");
$values = [];
$result = [];
while ($row = mysql_fetch_assoc($res)) {
$typeInfo = self::$types[$row['type']];
if ($typeInfo['has_option']) {
$options = preg_split('/[\r\n]+/', trim($row['options']));
$optionsArr = [];
foreach ($options as $option) {
$pos = strpos($option, '|');
$value = substr($option, 0, $pos);
$label = substr($option, $pos + 1);
$optionsArr[$value] = $label;
}
$row['options'] = $optionsArr;
}
$result[$row['torrent_id']][$row['id']] = $row;
if ($typeInfo['is_value_multiple']) {
$values[$row['torrent_id']][$row['id']][] = $row['custom_field_value'];
} else {
$values[$row['torrent_id']][$row['id']] = $row['custom_field_value'];
}
}
foreach ($result as $tid => &$fields) {
foreach ($fields as &$field) {
$field['custom_field_value'] = $values[$tid][$field['id']];
}
}
return $isArray ? $result : ($result[$torrentId] ?? []);
}
public function renderOnTorrentDetailsPage($torrentId)
{
global $browsecatmode;
$displayName = get_searchbox_value($browsecatmode, 'custom_fields_display_name');
$display = get_searchbox_value($browsecatmode, 'custom_fields_display');
$customFields = $this->listTorrentCustomField($torrentId);
// dd($displayName, $display, $customFields);
$mixedRowContent = nl2br($display);
$rowByRowHtml = '';
foreach ($customFields as $field) {
$content = $this->formatCustomFieldValue($field);
$mixedRowContent = str_replace("<%{$field['name']}.label%>", $field['label'], $mixedRowContent);
$mixedRowContent = str_replace("<%{$field['name']}.value%>", $content, $mixedRowContent);
if ($field['is_single_row']) {
$rowByRowHtml .= tr($field['label'], $content, 1);
}
}
$result = $rowByRowHtml;
if (!empty($mixedRowContent)) {
$result .= tr($displayName, $mixedRowContent, 1);
}
return $result;
}
protected function formatCustomFieldValue(array $customFieldWithValue)
{
$result = '';
$fieldValue = $customFieldWithValue['custom_field_value'];
switch ($customFieldWithValue['type']) {
case self::TYPE_TEXT:
case self::TYPE_TEXTAREA:
$result .= format_comment($fieldValue);
break;
case self::TYPE_IMAGE:
if (substr($fieldValue, 0, 4) == 'http') {
$result .= formatImg($fieldValue, true, 700, 0, "attach{$customFieldWithValue['id']}");
} else {
$result .= format_comment($fieldValue);
}
break;
case self::TYPE_RADIO:
case self::TYPE_CHECKBOX:
case self::TYPE_SELECT;
$fieldContent = [];
foreach ((array)$fieldValue as $item) {
$fieldContent[] = $customFieldWithValue['options'][$item] ?? '';
}
$result .= implode(' ', $fieldContent);
break;
default:
break;
}
return $result;
}
public function prepareTorrents(array $torrentIdArr)
{
$customFieldValues = $this->listTorrentCustomField($torrentIdArr);
$result = [];
foreach ($customFieldValues as $tid => &$customFields) {
foreach ($customFields as &$field) {
$field['custom_field_value_formatted'] = $this->formatCustomFieldValue($field);
$result[$tid][$field['name']] = $field;
}
}
$this->preparedTorrentCustomFieldValues = $result;
}
public function getPreparedTorrent($torrentId = null, $fieldName = null)
{
if (is_null($torrentId)) {
return $this->preparedTorrentCustomFieldValues;
}
if (is_null($fieldName)) {
return $this->preparedTorrentCustomFieldValues[$torrentId] ?? [];
}
return $this->preparedTorrentCustomFieldValues[$torrentId][$fieldName] ?? '';
}
}

26
nexus/Core/Management.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace Nexus\Core;
class Management
{
protected function buildTable(array $header, array $rows)
{
$table = '<table border="1" cellspacing="0" cellpadding="5" width="100%"><thead><tr>';
foreach ($header as $key => $value) {
$table .= sprintf('<td class="colhead">%s</td>', $value);
}
$table .= '</tr></thead><tbody>';
foreach ($rows as $row) {
$table .= '<tr>';
foreach ($header as $headerKey => $headerValue) {
$table .= sprintf('<td class="colfollow">%s</td>', $row[$headerKey] ?? '');
}
$table .= '</tr>';
}
$table .= '</tbody></table>';
return $table;
}
}

View File

@@ -261,7 +261,7 @@ class Install
public function gotoStep($step)
{
redirect(getBaseUrl() . "?step=$step");
nexus_redirect(getBaseUrl() . "?step=$step");
}
public function maxStep()

58
public/clients.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
require "../include/bittorrent.php";
dbconn();
require_once(get_langfile_path());
loggedinorreturn();
if (get_user_class() < UC_SYSOP) {
permissiondenied();
}
$type = $_GET['type'] ?? 'allow';
$client = new \Nexus\Client\Client($type);
$action = $_GET['action'] ?? 'view';
if ($action == 'view') {
stdhead($lang_clients['client_management']." - ".$lang_clients['text_field']);
begin_main_frame();
$r = $client->buildClientTable();
echo $r;
stdfoot();
} elseif ($action == 'add') {
stdhead($lang_clients['field_management']." - ".$lang_clients['text_add']);
begin_main_frame();
echo $client->buildFieldForm();
} elseif ($action == 'submit') {
try {
$result = $client->save($_REQUEST);
nexus_redirect('clients.php?action=view');
} catch (\Exception $e) {
stderr($lang_clients['field_management'], $e->getMessage());
}
} elseif ($action == 'edit') {
$id = intval($_GET['id'] ?? 0);
if ($id == 0) {
stderr($lang_clients['field_management'], "Invalid id");
}
$sql = "select * from torrents_custom_fields where id = $id";
$res = sql_query($sql);
$row = mysql_fetch_assoc($res);
if (empty($row)) {
stderr('', 'Invalid id');
}
stdhead($lang_clients['field_management']." - ".$lang_clients['text_edit']);
begin_main_frame();
echo $client->buildFieldForm($row);
} elseif ($action == 'del') {
$id = intval($_GET['id'] ?? 0);
if ($id == 0) {
stderr($lang_clients['field_management'], "Invalid id");
}
$sql = "delete from torrents_custom_fields where id = $id";
$res = sql_query($sql);
nexus_redirect('clients.php?action=view');
}

View File

@@ -23,7 +23,7 @@ if ($action == 'view') {
} elseif ($action == 'submit') {
try {
$result = $field->save($_REQUEST);
redirect('fields.php?action=view');
nexus_redirect('fields.php?action=view');
} catch (\Exception $e) {
stderr($lang_fields['field_management'], $e->getMessage());
}
@@ -48,7 +48,7 @@ if ($action == 'view') {
}
$sql = "delete from torrents_custom_fields where id = $id";
$res = sql_query($sql);
redirect('fields.php?action=view');
nexus_redirect('fields.php?action=view');
}

View File

@@ -21,7 +21,7 @@ function safe_query ($query,$id,$where = '') {
$result = sql_query($query);
if (!$result)
return sqlerr(__FILE__,__LINE__);
redirect("maxlogin.php?update=".htmlspecialchars($where));
nexus_redirect("maxlogin.php?update=".htmlspecialchars($where));
}
function searchform () {
?>

View File

@@ -333,7 +333,7 @@ if ($action == "exchange") {
$up = $upload + $bonusarray['menge'];
$bonuscomment = date("Y-m-d") . " - " .$points. " Points for upload bonus.\n " .$bonuscomment;
sql_query("UPDATE users SET uploaded = ".sqlesc($up).", seedbonus = seedbonus - $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=upload");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=upload");
}
}
//=== trade for one month VIP status ***note "SET class = '10'" change "10" to whatever your VIP class number is
@@ -346,7 +346,7 @@ if ($action == "exchange") {
$vip_until = date("Y-m-d H:i:s",(strtotime(date("Y-m-d H:i:s")) + 28*86400));
$bonuscomment = date("Y-m-d") . " - " .$points. " Points for 1 month VIP Status.\n " .htmlspecialchars($bonuscomment);
sql_query("UPDATE users SET class = '".UC_VIP."', vip_added = 'yes', vip_until = ".sqlesc($vip_until).", seedbonus = seedbonus - $points WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=vip");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=vip");
}
//=== trade for invites
elseif($art == "invite") {
@@ -356,7 +356,7 @@ if ($action == "exchange") {
$inv = $invites+$bonusarray['menge'];
$bonuscomment = date("Y-m-d") . " - " .$points. " Points for invites.\n " .htmlspecialchars($bonuscomment);
sql_query("UPDATE users SET invites = ".sqlesc($inv).", seedbonus = seedbonus - $points WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=invite");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=invite");
}
//=== trade for special title
/**** the $words array are words that you DO NOT want the user to have... use to filter "bad words" & user class...
@@ -370,7 +370,7 @@ if ($action == "exchange") {
$title = str_replace($words, $lang_mybonus['text_wasted_karma'], $title);
$bonuscomment = date("Y-m-d") . " - " .$points. " Points for custom title. Old title is ".htmlspecialchars(trim($CURUSER["title"]))." and new title is $title\n " .htmlspecialchars($bonuscomment);
sql_query("UPDATE users SET title = $title, seedbonus = seedbonus - $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=title");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=title");
}
elseif($art == "noad" && $enablead_advertisement == 'yes' && $enablebonusnoad_advertisement == 'yes') {
if (($enablenoad_advertisement == 'yes' && get_user_class() >= $noad_advertisement) || strtotime($CURUSER['noaduntil']) >= TIMENOW || get_user_class() < $bonusnoad_advertisement)
@@ -379,7 +379,7 @@ if ($action == "exchange") {
$noaduntil = date("Y-m-d H:i:s",(TIMENOW + $bonusarray['menge']));
$bonuscomment = date("Y-m-d") . " - " .$points. " Points for ".$bonusnoadtime_advertisement." days without ads.\n " .htmlspecialchars($bonuscomment);
sql_query("UPDATE users SET noad='yes', noaduntil='".$noaduntil."', seedbonus = seedbonus - $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id=".sqlesc($userid));
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=noad");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=noad");
}
}
elseif($art == 'gift_2') // charity giving
@@ -404,7 +404,7 @@ if ($action == "exchange") {
sql_query("UPDATE users SET seedbonus = seedbonus - $points, charity = charity + $points, bonuscomment = ".sqlesc($bonuscomment)." WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__);
$charityPerUser = $points/$charityReceiverCount;
sql_query("UPDATE users SET seedbonus = seedbonus + $charityPerUser WHERE enabled='yes' AND 10737418240 < downloaded AND $ratiocharity > uploaded/downloaded") or sqlerr(__FILE__, __LINE__);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=charity");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=charity");
}
else
{
@@ -466,7 +466,7 @@ if ($action == "exchange") {
$msg = sqlesc($msg);
sql_query("INSERT INTO messages (sender, subject, receiver, msg, added) VALUES(0, $subject, $useridgift, $msg, $added)") or sqlerr(__FILE__, __LINE__);
$usernamegift = unesc($_POST["username"]);
redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=transfer");
nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=transfer");
}
else{
print("<table width=\"940\"><tr><td class=\"colhead\" align=\"left\" colspan=\"2\"><h1>".$lang_mybonus['text_oups']."</h1></td></tr>");

View File

@@ -16,4 +16,5 @@ use Illuminate\Support\Facades\Route;
Route::group([], function () {
Route::resource('agent-allow', \App\Http\Controllers\AgentAllowController::class);
Route::resource('user', \App\Http\Controllers\UserController::class);
});