mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-14 12:30:49 +08:00
temporary invite
This commit is contained in:
39
app/Console/Commands/InviteAddTemporary.php
Normal file
39
app/Console/Commands/InviteAddTemporary.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\GenerateTemporaryInvite;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class InviteAddTemporary extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invite:tmp {uid} {days} {count}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add temporary invite to user, argument: uid(Multiple comma separated), days, count';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$uid = $this->argument('uid');
|
||||
$days = $this->argument('days');
|
||||
$count = $this->argument('count');
|
||||
$this->info("uid: $uid, days: $days, count: $count");
|
||||
$uidArr = preg_split('/[\s,]+/', $uid);
|
||||
GenerateTemporaryInvite::dispatch($uidArr, $days, $count);
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use App\Models\Exam;
|
||||
use App\Models\ExamProgress;
|
||||
use App\Models\ExamUser;
|
||||
use App\Models\HitAndRun;
|
||||
use App\Models\Invite;
|
||||
use App\Models\Medal;
|
||||
use App\Models\Peer;
|
||||
use App\Models\SearchBox;
|
||||
@@ -94,10 +95,9 @@ class Test extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$rep = new WorkRepository();
|
||||
$rep->settleRole(4);
|
||||
$uid = "2,3,4";
|
||||
$uidArr = preg_split('/[\s,]+/', $uid);
|
||||
dd($uidArr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
112
app/Filament/Resources/User/InviteResource.php
Normal file
112
app/Filament/Resources/User/InviteResource.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User;
|
||||
|
||||
use App\Filament\Resources\User\InviteResource\Pages;
|
||||
use App\Filament\Resources\User\InviteResource\RelationManagers;
|
||||
use App\Models\Invite;
|
||||
use Filament\Forms;
|
||||
use Filament\Resources\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Resources\Table;
|
||||
use Filament\Tables;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class InviteResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Invite::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-user-add';
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 7;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.invite');
|
||||
}
|
||||
|
||||
public static function getBreadcrumb(): string
|
||||
{
|
||||
return self::getNavigationLabel();
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
//
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id'),
|
||||
Tables\Columns\TextColumn::make('inviter')
|
||||
->label(__('invite.fields.inviter'))
|
||||
->formatStateUsing(fn ($state) => username_for_admin($state))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('invitee')
|
||||
->label(__('invite.fields.invitee'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('hash')
|
||||
,
|
||||
Tables\Columns\TextColumn::make('time_invited')
|
||||
->label(__('invite.fields.time_invited'))
|
||||
,
|
||||
Tables\Columns\IconColumn::make('valid')
|
||||
->label(__('invite.fields.valid'))
|
||||
->boolean()
|
||||
,
|
||||
Tables\Columns\TextColumn::make('invitee_register_uid')
|
||||
->label(__('invite.fields.invitee_register_uid'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('invitee_register_email')
|
||||
->label(__('invite.fields.invitee_register_email'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('invitee_register_email')
|
||||
->label(__('invite.fields.invitee_register_email'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('invitee_register_username')
|
||||
->label(__('invite.fields.invitee_register_username'))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('expired_at')
|
||||
->label(__('invite.fields.expired_at'))
|
||||
->formatStateUsing(fn ($state) => format_datetime($state))
|
||||
,
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label(__('label.created_at'))
|
||||
->formatStateUsing(fn ($state) => format_datetime($state))
|
||||
,
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
// Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
// Tables\Actions\DeleteBulkAction::make(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListInvites::route('/'),
|
||||
'create' => Pages\CreateInvite::route('/create'),
|
||||
'edit' => Pages\EditInvite::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\InviteResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\InviteResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateInvite extends CreateRecord
|
||||
{
|
||||
protected static string $resource = InviteResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\InviteResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\InviteResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditInvite extends EditRecord
|
||||
{
|
||||
protected static string $resource = InviteResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\InviteResource\Pages;
|
||||
|
||||
use App\Filament\PageList;
|
||||
use App\Filament\Resources\User\InviteResource;
|
||||
use App\Models\Invite;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class ListInvites extends PageList
|
||||
{
|
||||
protected static string $resource = InviteResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
// Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getTableQuery(): Builder
|
||||
{
|
||||
return Invite::query()->with(['inviter_user']);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,14 @@
|
||||
namespace App\Filament\Resources\User\UserResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\UserResource;
|
||||
use App\Models\Invite;
|
||||
use App\Models\Medal;
|
||||
use App\Models\User;
|
||||
use App\Models\UserMeta;
|
||||
use App\Repositories\ExamRepository;
|
||||
use App\Repositories\MedalRepository;
|
||||
use App\Repositories\UserRepository;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Resources\Pages\Concerns\HasRelationManagers;
|
||||
use Filament\Resources\Pages\Concerns\InteractsWithRecord;
|
||||
use Filament\Resources\Pages\Page;
|
||||
@@ -129,20 +131,44 @@ class UserProfile extends ViewRecord
|
||||
'invites' => __('label.user.invites'),
|
||||
'seedbonus' => __('label.user.seedbonus'),
|
||||
'attendance_card' => __('label.user.attendance_card'),
|
||||
])->label(__('admin.resources.user.actions.change_bonus_etc_field_label'))->inline()->required(),
|
||||
'tmp_invites' => __('label.user.tmp_invites'),
|
||||
])
|
||||
->label(__('admin.resources.user.actions.change_bonus_etc_field_label'))
|
||||
->inline()
|
||||
->required()
|
||||
->reactive()
|
||||
,
|
||||
Forms\Components\Radio::make('action')->options([
|
||||
'Increment' => __("admin.resources.user.actions.change_bonus_etc_action_increment"),
|
||||
'Decrement' => __("admin.resources.user.actions.change_bonus_etc_action_decrement"),
|
||||
])->label(__('admin.resources.user.actions.change_bonus_etc_action_label'))->inline()->required(),
|
||||
])
|
||||
->label(__('admin.resources.user.actions.change_bonus_etc_action_label'))
|
||||
->inline()
|
||||
->required()
|
||||
,
|
||||
Forms\Components\TextInput::make('value')->integer()->required()
|
||||
->label(__('admin.resources.user.actions.change_bonus_etc_value_label'))
|
||||
->helperText(__('admin.resources.user.actions.change_bonus_etc_value_help')),
|
||||
Forms\Components\Textarea::make('reason')->label(__('admin.resources.user.actions.change_bonus_etc_reason_label')),
|
||||
->helperText(__('admin.resources.user.actions.change_bonus_etc_value_help'))
|
||||
,
|
||||
|
||||
Forms\Components\TextInput::make('duration')->integer()
|
||||
->label(__('admin.resources.user.actions.change_bonus_etc_duration_label'))
|
||||
->helperText(__('admin.resources.user.actions.change_bonus_etc_duration_help'))
|
||||
->hidden(fn (\Closure $get) => $get('field') != 'tmp_invites')
|
||||
,
|
||||
|
||||
Forms\Components\Textarea::make('reason')
|
||||
->label(__('admin.resources.user.actions.change_bonus_etc_reason_label'))
|
||||
,
|
||||
])
|
||||
->action(function ($data) {
|
||||
$userRep = $this->getRep();
|
||||
try {
|
||||
$userRep->incrementDecrement(Auth::user(), $this->record->id, $data['action'], $data['field'], $data['value'], $data['reason']);
|
||||
if ($data['field'] == 'tmp_invites') {
|
||||
$userRep->addTemporaryInvite(Auth::user(), $this->record->id, $data['action'], $data['value'], $data['duration'], $data['reason']);
|
||||
} else {
|
||||
$userRep->incrementDecrement(Auth::user(), $this->record->id, $data['action'], $data['field'], $data['value'], $data['reason']);
|
||||
}
|
||||
$this->notify('success', 'Success!');
|
||||
$this->emitSelf(self::EVENT_RECORD_UPDATED, $this->record->id);
|
||||
} catch (\Exception $exception) {
|
||||
@@ -298,6 +324,7 @@ class UserProfile extends ViewRecord
|
||||
{
|
||||
return [
|
||||
'props' => $this->listUserProps(),
|
||||
'temporary_invite_count' => $this->countTemporaryInvite()
|
||||
];
|
||||
}
|
||||
|
||||
@@ -319,4 +346,13 @@ class UserProfile extends ViewRecord
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
private function countTemporaryInvite()
|
||||
{
|
||||
return Invite::query()->where('inviter', $this->record->id)
|
||||
->where('invitee', '')
|
||||
->whereNotNull('expired_at')
|
||||
->where('expired_at', '>', Carbon::now())
|
||||
->count();
|
||||
}
|
||||
}
|
||||
|
||||
81
app/Jobs/GenerateTemporaryInvite.php
Normal file
81
app/Jobs/GenerateTemporaryInvite.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Invite;
|
||||
use App\Repositories\ToolRepository;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class GenerateTemporaryInvite implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private int $count;
|
||||
|
||||
private array $uidArr;
|
||||
|
||||
private int $days;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $uidArr, int $days, int $count)
|
||||
{
|
||||
$this->uidArr = $uidArr;
|
||||
$this->days = $days;
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the time at which the job should timeout.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function retryUntil()
|
||||
{
|
||||
return now()->addHours(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$toolRep = new ToolRepository();
|
||||
foreach ($this->uidArr as $uid) {
|
||||
try {
|
||||
$hashArr = $toolRep->generateUniqueInviteHash([], $this->count, $this->count);
|
||||
$data = [];
|
||||
foreach($hashArr as $hash) {
|
||||
$data[] = [
|
||||
'inviter' => $uid,
|
||||
'invitee' => '',
|
||||
'hash' => $hash,
|
||||
'valid' => 0,
|
||||
'expired_at' => Carbon::now()->addDays($this->days),
|
||||
'created_at' => Carbon::now(),
|
||||
];
|
||||
}
|
||||
if (!empty($data)) {
|
||||
Invite::query()->insert($data);
|
||||
}
|
||||
do_log("success add $this->count temporary invite ($this->days days) to $uid");
|
||||
} catch (\Exception $exception) {
|
||||
do_log("fail add $this->count temporary invite ($this->days days) to $uid: " . $exception->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,10 @@ class Invite extends NexusModel
|
||||
const VALID_YES = 1;
|
||||
const VALID_NO = 0;
|
||||
|
||||
protected $casts = [
|
||||
'expired_at' => 'datetime',
|
||||
];
|
||||
|
||||
public static $validInfo = [
|
||||
self::VALID_NO => ['text' => 'No'],
|
||||
self::VALID_YES => ['text' => 'Yes'],
|
||||
|
||||
@@ -360,6 +360,15 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
return $this->belongsTo(User::class, 'invited_by');
|
||||
}
|
||||
|
||||
public function temporary_invites()
|
||||
{
|
||||
return $this->hasMany(Invite::class, 'inviter')
|
||||
->where('invitee', '')
|
||||
->whereNotNull('expired_at')
|
||||
->where('expired_at', '>=', Carbon::now())
|
||||
;
|
||||
}
|
||||
|
||||
public function send_messages()
|
||||
{
|
||||
return $this->hasMany(Message::class, 'sender');
|
||||
|
||||
@@ -153,6 +153,11 @@ class ClaimRepository extends BaseRepository
|
||||
|
||||
public function settleUser($uid, $force = false, $test = false): bool
|
||||
{
|
||||
$shouldDoSettle = apply_filter('user_should_do_claim_settle', true, $uid);
|
||||
if (!$shouldDoSettle) {
|
||||
do_log("uid: $uid, filter: user_should_do_claim_settle => false");
|
||||
return false;
|
||||
}
|
||||
$user = User::query()->with('language')->findOrFail($uid);
|
||||
$list = Claim::query()->where('uid', $uid)->with(['snatch', 'torrent' => fn ($query) => $query->select(Torrent::$commentFields)])->get();
|
||||
$now = Carbon::now();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Invite;
|
||||
use App\Models\Message;
|
||||
use App\Models\News;
|
||||
use App\Models\Poll;
|
||||
@@ -11,6 +12,7 @@ use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Nexus\Database\NexusDB;
|
||||
use Nexus\Plugin\Plugin;
|
||||
use NexusPlugin\Permission\PermissionRepository;
|
||||
@@ -416,4 +418,25 @@ class ToolRepository extends BaseRepository
|
||||
$uidPermissionsCached[$uid] = $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function generateUniqueInviteHash(array $hashArr, int $total, int $left, int $deep = 0): array
|
||||
{
|
||||
do_log("total: $total, left: $left, deep: $deep");
|
||||
if ($deep > 10) {
|
||||
throw new \RuntimeException("deep: $deep > 10");
|
||||
}
|
||||
if (count($hashArr) >= $total) {
|
||||
return array_slice(array_values($hashArr), 0, $total);
|
||||
}
|
||||
for ($i = 0; $i < $left; $i++) {
|
||||
$hash = Str::random(32);
|
||||
$hashArr[$hash] = $hash;
|
||||
}
|
||||
$exists = Invite::query()->whereIn('hash', array_values($hashArr))->get(['id', 'hash']);
|
||||
foreach($exists as $value) {
|
||||
unset($hashArr[$value->hash]);
|
||||
}
|
||||
return $this->generateUniqueInviteHash($hashArr, $total, $total - count($hashArr), ++$deep);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Exceptions\NexusException;
|
||||
use App\Http\Resources\ExamUserResource;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\ExamUser;
|
||||
use App\Models\Invite;
|
||||
use App\Models\Message;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
@@ -566,4 +567,81 @@ class UserRepository extends BaseRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public function addTemporaryInvite(User $operator, int $uid, string $action, int $count, int|null $days, string|null $reason = '')
|
||||
{
|
||||
do_log("uid: $uid, action: $action, count: $count, days: $days, reason: $reason");
|
||||
$action = strtolower($action);
|
||||
if ($count <= 0 || ($action == 'increment' && $days <= 0)) {
|
||||
throw new \InvalidArgumentException("days or count lte 0");
|
||||
}
|
||||
$targetUser = User::query()->findOrFail($uid, User::$commonFields);
|
||||
$this->checkPermission($operator, $targetUser);
|
||||
$toolRep = new ToolRepository();
|
||||
$locale = $targetUser->locale;
|
||||
|
||||
$changeType = nexus_trans("nexus.$action", [], $locale);
|
||||
$subject = nexus_trans('message.temporary_invite_change.subject', ['change_type' => $changeType], $locale);
|
||||
$body = nexus_trans('message.temporary_invite_change.body', [
|
||||
'change_type' => $changeType,
|
||||
'count' => $count,
|
||||
'operator' => $operator->username,
|
||||
'reason' => $reason,
|
||||
], $locale);
|
||||
$message = [
|
||||
'sender' => 0,
|
||||
'receiver' => $targetUser->id,
|
||||
'subject' => $subject,
|
||||
'msg' => $body,
|
||||
'added' => Carbon::now(),
|
||||
];
|
||||
$inviteData = [];
|
||||
if ($action == 'increment') {
|
||||
$hashArr = $toolRep->generateUniqueInviteHash([], $count, $count);
|
||||
foreach ($hashArr as $hash) {
|
||||
$inviteData[] = [
|
||||
'inviter' => $uid,
|
||||
'invitee' => '',
|
||||
'hash' => $hash,
|
||||
'valid' => 0,
|
||||
'expired_at' => Carbon::now()->addDays($days),
|
||||
'created_at' => Carbon::now(),
|
||||
];
|
||||
}
|
||||
}
|
||||
NexusDB::transaction(function () use ($uid, $message, $inviteData, $count) {
|
||||
if (!empty($inviteData)) {
|
||||
Invite::query()->insert($inviteData);
|
||||
do_log("[INSERT TEMPORARY INVITE] to $uid, count: $count");
|
||||
} else {
|
||||
Invite::query()->where('inviter', $uid)
|
||||
->where('invitee', '')
|
||||
->orderBy('expired_at', 'asc')
|
||||
->limit($count)
|
||||
->delete()
|
||||
;
|
||||
do_log("[DELETE TEMPORARY INVITE] of $uid, count: $count");
|
||||
}
|
||||
Message::add($message);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getInviteBtnText(int $uid)
|
||||
{
|
||||
if (Setting::get('main.invitesystem') != 'yes') {
|
||||
throw new NexusException(nexus_trans('invite.send_deny_reasons.invite_system_closed'));
|
||||
}
|
||||
$permission = 'sendinvite';
|
||||
if (!user_can($permission, false, $uid)) {
|
||||
$requireClass = get_setting("authority.$permission");
|
||||
throw new NexusException(nexus_trans('invite.send_deny_reasons.no_permission', ['class' => User::getClassText($requireClass)]));
|
||||
}
|
||||
$userInfo = User::query()->findOrFail($uid, User::$commonFields);
|
||||
$temporaryInviteCount = $userInfo->temporary_invites()->count();
|
||||
if ($userInfo->invites + $temporaryInviteCount < 1) {
|
||||
throw new NexusException(nexus_trans('invite.send_deny_reasons.invite_not_enough'));
|
||||
}
|
||||
return nexus_trans('invite.send_allow_text');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('invites', function (Blueprint $table) {
|
||||
$table->dateTime('expired_at')->nullable(true)->index();
|
||||
$table->dateTime('created_at')->useCurrent();
|
||||
$table->index(['inviter'], 'idx_inviter');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('invites', function (Blueprint $table) {
|
||||
$table->dropColumn('expired_at', 'created_at');
|
||||
$table->dropIndex('idx_inviter');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('invites', function (Blueprint $table) {
|
||||
$table->string('invitee')->default('')->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -248,6 +248,7 @@ function docleanup($forceAll = 0, $printProgress = false) {
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(1);
|
||||
$now = time();
|
||||
$nowStr = \Carbon\Carbon::now()->toDateTimeString();
|
||||
do_log("start docleanup(), forceAll: $forceAll, printProgress: $printProgress, now: $now, " . date('Y-m-d H:i:s', $now));
|
||||
|
||||
//Priority Class 1: cleanup every 15 mins
|
||||
@@ -592,7 +593,7 @@ function docleanup($forceAll = 0, $printProgress = false) {
|
||||
//6.delete old invite codes
|
||||
$secs = $invite_timeout*24*60*60; // when?
|
||||
$dt = sqlesc(date("Y-m-d H:i:s",(TIMENOW - $secs))); // calculate date.
|
||||
sql_query("DELETE FROM invites WHERE time_invited < $dt") or sqlerr(__FILE__, __LINE__);
|
||||
sql_query("DELETE FROM invites WHERE ((time_invited < $dt and time_invited is not null and invitee != '') or (invitee = '' and expired_at < '$nowStr' and expired_at is not null))") or sqlerr(__FILE__, __LINE__);
|
||||
$log = "delete old invite codes";
|
||||
do_log($log);
|
||||
if ($printProgress) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.0');
|
||||
defined('RELEASE_DATE') || define('RELEASE_DATE', '2022-12-08');
|
||||
defined('RELEASE_DATE') || define('RELEASE_DATE', '2022-12-13');
|
||||
defined('IN_TRACKER') || define('IN_TRACKER', false);
|
||||
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
|
||||
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
|
||||
|
||||
@@ -2659,7 +2659,7 @@ else {
|
||||
[<a href="torrents.php?inclbookmarked=1&allsec=1&incldead=0"><?php echo $lang_functions['text_bookmarks'] ?></a>]
|
||||
<font class = 'color_bonus'><?php echo $lang_functions['text_bonus'] ?></font>[<a href="mybonus.php"><?php echo $lang_functions['text_use'] ?></a>]: <?php echo number_format($CURUSER['seedbonus'], 1)?>
|
||||
<?php if($attendance){ printf(' <a href="attendance.php" class="">'.$lang_functions['text_attended'].'</a>', $attendance->points, $CURUSER['attendance_card']); }else{ printf(' <a href="attendance.php" class="faqlink">%s</a>', $lang_functions['text_attendance']);}?>
|
||||
<font class = 'color_invite'><?php echo $lang_functions['text_invite'] ?></font>[<a href="invite.php?id=<?php echo $CURUSER['id']?>"><?php echo $lang_functions['text_send'] ?></a>]: <?php echo $CURUSER['invites']?>
|
||||
<font class = 'color_invite'><?php echo $lang_functions['text_invite'] ?></font>[<a href="invite.php?id=<?php echo $CURUSER['id']?>"><?php echo $lang_functions['text_send'] ?></a>]: <?php echo sprintf('%s(%s)', $CURUSER['invites'], \App\Models\Invite::query()->where('inviter', $CURUSER['id'])->where('invitee', '')->where('expired_at', '>', now())->count())?>
|
||||
<?php if(get_user_class() >= \App\Models\User::CLASS_ADMINISTRATOR) printf('[<a href="%s" target="_blank">%s</a>]', nexus_env('FILAMENT_PATH', 'nexusphp'), $lang_functions['text_management_system'])?>
|
||||
<br />
|
||||
<font class="color_ratio"><?php echo $lang_functions['text_ratio'] ?></font> <?php echo $ratio?>
|
||||
|
||||
@@ -57,6 +57,11 @@ $lang_invite = array
|
||||
'text_seed_torrent_bonus_per_hour_help' => '即做种积分,单纯做种的值,不考虑捐赠、官种、后宫等任何加成',
|
||||
'text_seed_torrent_last_announce_at' => '最后做种汇报时间',
|
||||
'text_enabled' => '启用',
|
||||
'text_tmp_status' => '临时邀请状态',
|
||||
'text_expired_at' => 'hash 过期时间',
|
||||
'text_permanent' => '永久有效邀请',
|
||||
'text_consume_invite' => '使用邀请',
|
||||
'text_temporary_left' => '%s个临时邀请',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -24,6 +24,9 @@ $lang_takeinvite = array
|
||||
'std_no_invite' => "你没有剩余邀请名额。你怎么到这来的?",
|
||||
'std_invitation_already_sent_to' => "发送失败!此邮箱",
|
||||
'std_await_user_registeration' => "已收到过邀请函,请勿重复发送。请等待用户注册。",
|
||||
'std_must_select_invite' => "请选择要使用的邀请。",
|
||||
'hash_not_exists' => "hash 不存在。",
|
||||
'hash_expired' => "hash 已经过期。",
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -57,6 +57,8 @@ $lang_invite = array
|
||||
'text_seed_torrent_bonus_per_hour_help' => '即做種積分,單純做種的值,不考慮捐贈、官種、後宮等任何加成',
|
||||
'text_seed_torrent_last_announce_at' => '最後做種匯報時間',
|
||||
'text_enabled' => '啟用',
|
||||
'text_tmp_status' => '臨時邀請狀態',
|
||||
'text_expired_at' => '過期時間',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -60,6 +60,8 @@ Best Regards,
|
||||
'text_seed_torrent_bonus_per_hour_help' => 'That is, seed points, do not consider donations, official torrent, harems and any other additions',
|
||||
'text_seed_torrent_last_announce_at' => 'Last announce time',
|
||||
'text_enabled' => 'Enabled',
|
||||
'text_tmp_status' => 'Temporary invite status',
|
||||
'text_expired_at' => 'Expired at',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -10,6 +10,7 @@ $validTypeMap = [
|
||||
'attendance_card' => 'Attend card',
|
||||
'invites' => 'Invite',
|
||||
'uploaded' => 'Upload',
|
||||
'tmp_invites' => 'Temporary invite',
|
||||
];
|
||||
$type = $_REQUEST['type'] ?? '';
|
||||
stdhead("Add Bonus/Attend card/Invite/upload", false);
|
||||
@@ -49,6 +50,7 @@ $classes = array_chunk(\App\Models\User::$classes, 4, true);
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td class="rowhead" valign="top">Amount </td><td class="rowfollow"><input type=text name=amount size=10></td></tr>
|
||||
<tr><td class="rowhead" valign="top">Duration </td><td class="rowfollow"><input type=number min="1" name=duration size=10> Only required when Type = 'Temporary invite', Unit: Day</td></tr>
|
||||
<tr>
|
||||
<td class="rowhead" valign="top">Add to Class</td><td class="rowfollow">
|
||||
<table style="border: 0" width="100%" cellpadding="0" cellspacing="0">
|
||||
|
||||
@@ -8,23 +8,31 @@ $id = intval($_GET["id"] ?? 0);
|
||||
$type = unesc($_GET["type"] ?? '');
|
||||
$menuSelected = $_REQUEST['menu'] ?? 'invitee';
|
||||
$pageSize = 50;
|
||||
$userRep = new \App\Repositories\UserRepository();
|
||||
|
||||
function inviteMenu ($selected = "invitee") {
|
||||
global $lang_invite, $id, $CURUSER, $invitesystem;
|
||||
global $lang_invite, $id, $CURUSER, $invitesystem, $userRep;
|
||||
begin_main_frame("", false, "100%");
|
||||
print ("<div id=\"invitenav\" style='position: relative'><ul id=\"invitemenu\" class=\"menu\">");
|
||||
print ("<li" . ($selected == "invitee" ? " class=selected" : "") . "><a href=\"?id=".$id."&menu=invitee\">".$lang_invite['text_invite_status']."</a></li>");
|
||||
print ("<li" . ($selected == "sent" ? " class=selected" : "") . "><a href=\"?id=".$id."&menu=sent\">".$lang_invite['text_sent_invites_status']."</a></li>");
|
||||
if (user_can('sendinvite') && $invitesystem == 'yes') {
|
||||
print ("</ul><form style='position: absolute;top:0;right:0' method=post action=invite.php?id=".htmlspecialchars($id)."&type=new><input type=submit ".($CURUSER['invites'] <= 0 ? "disabled " : "")." value='".$lang_invite['sumbit_invite_someone']."'></form></div>");
|
||||
print ("<li" . ($selected == "tmp" ? " class=selected" : "") . "><a href=\"?id=".$id."&menu=tmp\">".$lang_invite['text_tmp_status']."</a></li>");
|
||||
try {
|
||||
$sendBtnText = $userRep->getInviteBtnText($CURUSER['id']);
|
||||
$disabled = '';
|
||||
} catch (\Exception $exception) {
|
||||
$sendBtnText = $exception->getMessage();
|
||||
$disabled = ' disabled';
|
||||
}
|
||||
print ("</ul><form style='position: absolute;top:0;right:0' method=post action=invite.php?id=".htmlspecialchars($id)."&type=new><input type=submit ".$disabled." value='".$sendBtnText."'></form></div>");
|
||||
end_main_frame();
|
||||
}
|
||||
|
||||
if (($CURUSER['id'] != $id && !user_can('viewinvite')) || !is_valid_id($id))
|
||||
stderr($lang_invite['std_sorry'],$lang_invite['std_permission_denied']);
|
||||
$res = sql_query("SELECT username FROM users WHERE id = ".mysql_real_escape_string($id)) or sqlerr();
|
||||
$user = mysql_fetch_assoc($res);
|
||||
if (!$user) {
|
||||
stderr($lang_invite['std_sorry'], 'Invalid id');
|
||||
}
|
||||
stdhead($lang_invite['head_invites']);
|
||||
print("<table width=100% class=main border=0 cellspacing=0 cellpadding=0><tr><td class=embedded>");
|
||||
|
||||
@@ -46,24 +54,34 @@ if ($inv["invites"] != 1){
|
||||
}
|
||||
|
||||
if ($type == 'new'){
|
||||
if (!user_can('sendinvite'))
|
||||
stderr($lang_invite['std_sorry'],$lang_invite['std_only'].get_user_class_name($sendinvite_class,false,true,true).$lang_invite['std_or_above_can_invite'],false, false);
|
||||
try {
|
||||
$sendBtnText = $userRep->getInviteBtnText($CURUSER['id']);
|
||||
} catch (\Exception $exception) {
|
||||
stdmsg($lang_invite['std_sorry'],$exception->getMessage().
|
||||
" <a class=altlink href=invite.php?id={$CURUSER['id']}>".$lang_invite['here_to_go_back'],false);
|
||||
print("</td></tr></table>");
|
||||
stdfoot();
|
||||
die;
|
||||
}
|
||||
registration_check('invitesystem',true,false);
|
||||
if ($CURUSER['invites'] <= 0) {
|
||||
stdmsg($lang_invite['std_sorry'],$lang_invite['std_no_invites_left'].
|
||||
"<a class=altlink href=invite.php?id={$CURUSER['id']}>".$lang_invite['here_to_go_back'],false);
|
||||
print("</td></tr></table>");
|
||||
stdfoot();
|
||||
die;
|
||||
}
|
||||
$temporaryInvites = \App\Models\Invite::query()->where('inviter', $CURUSER['id'])
|
||||
->where('invitee', '')
|
||||
->where('expired_at', '>', now())
|
||||
->orderBy('expired_at', 'asc')
|
||||
->get()
|
||||
;
|
||||
$invitation_body = $lang_invite['text_invitation_body'].$CURUSER['username'];
|
||||
//$invitation_body_insite = str_replace("<br />","\n",$invitation_body);
|
||||
$inviteSelectOptions = '<option value="permanent">'.$lang_invite['text_permanent'].'</option>';
|
||||
foreach ($temporaryInvites as $tmp) {
|
||||
$inviteSelectOptions .= sprintf('<option value="%s">%s(%s: %s)</option>', $tmp->hash, $tmp->hash, $lang_invite['text_expired_at'], $tmp->expired_at);
|
||||
}
|
||||
print("<form method=post action=takeinvite.php?id=".htmlspecialchars($id).">".
|
||||
"<table border=1 width=100% cellspacing=0 cellpadding=5>".
|
||||
"<tr align=center><td colspan=2><b>".$lang_invite['text_invite_someone']."$SITENAME ({$inv['invites']}".$lang_invite['text_invitation'].$_s.$lang_invite['text_left'] .")</b></td></tr>".
|
||||
"<tr align=center><td colspan=2><b>".$lang_invite['text_invite_someone']."$SITENAME ({$inv['invites']}".$lang_invite['text_invitation'].$_s.$lang_invite['text_left'] .' + '.sprintf($lang_invite['text_temporary_left'], $temporaryInvites->count()).")</b></td></tr>".
|
||||
"<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\">".$lang_invite['text_email_address']."</td><td align=left><input type=text size=40 name=email><br /><font align=left class=small>".$lang_invite['text_email_address_note']."</font>".($restrictemaildomain == 'yes' ? "<br />".$lang_invite['text_email_restriction_note'].allowedemails() : "")."</td></tr>".
|
||||
"<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\">".$lang_invite['text_message']."</td><td align=left><textarea name=body rows=10 style='width: 100%'>" .$invitation_body.
|
||||
"</textarea></td></tr>".
|
||||
"<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\">".$lang_invite['text_consume_invite']."</td><td align=left><select name='hash'>".$inviteSelectOptions."</select></td></tr>".
|
||||
"<tr><td class=\"rowhead nowrap\" valign=\"top\" align=\"right\">".$lang_invite['text_message']."</td><td align=left><textarea name=body rows=10 style='width: 100%'>" .$invitation_body. "</textarea></td></tr>".
|
||||
"<tr><td align=center colspan=2><input type=submit value='".$lang_invite['submit_invite']."'></td></tr>".
|
||||
"</form></table></td></tr></table>");
|
||||
|
||||
@@ -94,7 +112,9 @@ if ($type == 'new'){
|
||||
$name, $_GET['status'] == $name ? ' selected' : '', $text
|
||||
);
|
||||
}
|
||||
|
||||
$resetText = nexus_trans('label.reset');
|
||||
$submitText = nexus_trans('label.submit');
|
||||
$filterForm = <<<FORM
|
||||
<div>
|
||||
<form id="filterForm" action="{$_SERVER['REQUEST_URI']}" method="get">
|
||||
@@ -112,7 +132,7 @@ if ($type == 'new'){
|
||||
{$statusOptions}
|
||||
</select>
|
||||
|
||||
<input type="submit">
|
||||
<input type="submit" value="{$submitText}">
|
||||
<input type="button" id="reset" value="{$resetText}">
|
||||
</form>
|
||||
</div>
|
||||
@@ -220,22 +240,32 @@ JS;
|
||||
}
|
||||
print("</table>");
|
||||
print("</td></tr></table>$pagertop");
|
||||
} elseif ($menuSelected == 'sent') {
|
||||
$rul = sql_query("SELECT COUNT(*) FROM invites WHERE inviter =".mysql_real_escape_string($id)) or sqlerr();
|
||||
} elseif (in_array($menuSelected, ['sent', 'tmp'])) {
|
||||
$whereStr = "inviter = " . sqlesc($id);
|
||||
if ($menuSelected == 'sent') {
|
||||
$whereStr .= " and invitee != ''";
|
||||
} elseif ($menuSelected == 'tmp') {
|
||||
$whereStr .= " and invitee = '' and expired_at is not null";
|
||||
}
|
||||
$rul = sql_query("SELECT COUNT(*) FROM invites WHERE $whereStr");
|
||||
$arre = mysql_fetch_row($rul);
|
||||
$number1 = $arre[0];
|
||||
|
||||
print("<table border=1 width=100% cellspacing=0 cellpadding=5>");
|
||||
|
||||
if(!$number1){
|
||||
print("<tr align=center><td colspan=6>".$lang_invite['text_no_invitation_sent']."</tr>");
|
||||
print("<tr align=center><td colspan=6>".$lang_functions['text_none']."</tr>");
|
||||
} else {
|
||||
list($pagertop, $pagerbottom, $limit) = pager($pageSize, $number1, "?id=$id&menu=$menuSelected&");
|
||||
|
||||
$rer = sql_query("SELECT * FROM invites WHERE inviter = ".mysql_real_escape_string($id) . " $limit") or sqlerr();
|
||||
$rer = sql_query("SELECT * FROM invites WHERE $whereStr $limit") or sqlerr();
|
||||
$num1 = mysql_num_rows($rer);
|
||||
|
||||
print("<tr><td class=colhead>".$lang_invite['text_email']."</td><td class=colhead>".$lang_invite['text_hash']."</td><td class=colhead>".$lang_invite['text_send_date']."</td><td class='colhead'>".$lang_invite['text_hash_status']."</td><td class='colhead'>".$lang_invite['text_invitee_user']."</td></tr>");
|
||||
print("<tr><td class=colhead>".$lang_invite['text_email']."</td><td class=colhead>".$lang_invite['text_hash']."</td><td class=colhead>".$lang_invite['text_send_date']."</td><td class='colhead'>".$lang_invite['text_hash_status']."</td><td class='colhead'>".$lang_invite['text_invitee_user']."</td>");
|
||||
if ($menuSelected == 'tmp') {
|
||||
print("<td class='colhead'>".$lang_invite['text_expired_at']."</td>");
|
||||
print("<td class='colhead'>".nexus_trans('label.created_at')."</td>");
|
||||
}
|
||||
print("</tr>");
|
||||
for ($i = 0; $i < $num1; ++$i)
|
||||
{
|
||||
$arr1 = mysql_fetch_assoc($rer);
|
||||
@@ -254,6 +284,10 @@ JS;
|
||||
} else {
|
||||
$tr .= "<td class='rowfollow'></td>";
|
||||
}
|
||||
if ($menuSelected == 'tmp') {
|
||||
$tr .= "<td class=rowfollow>{$arr1['expired_at']}</td>";
|
||||
$tr .= "<td class=rowfollow>{$arr1['created_at']}</td>";
|
||||
}
|
||||
$tr .= "</tr>";
|
||||
print($tr);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ $validTypeMap = [
|
||||
'attendance_card' => 'Attend card',
|
||||
'invites' => 'Invite',
|
||||
'uploaded' => 'Upload',
|
||||
'tmp_invites' => 'Temporary invite',
|
||||
];
|
||||
$sender_id = ($_POST['sender'] == 'system' ? 0 : (int)$CURUSER['id']);
|
||||
$dt = sqlesc(date("Y-m-d H:i:s"));
|
||||
@@ -29,8 +30,9 @@ if (!isset($validTypeMap[$type])) {
|
||||
if ($type == 'uploaded') {
|
||||
$amount = sqlesc(getsize_int($amount,"G"));
|
||||
}
|
||||
$isTypeTmpInvite = $type == 'tmp_invites';
|
||||
$subject = trim($_POST['subject']);
|
||||
$size = 10000;
|
||||
$size = 2000;
|
||||
$page = 1;
|
||||
set_time_limit(300);
|
||||
$conditions = [];
|
||||
@@ -41,7 +43,12 @@ $conditions = apply_filter("role_query_conditions", $conditions, $_POST);
|
||||
if (empty($conditions)) {
|
||||
stderr("Error","No valid filter");
|
||||
}
|
||||
if ($isTypeTmpInvite && (empty($_POST['duration']) || $_POST['duration'] < 1)) {
|
||||
stderr("Error","Invalid duration");
|
||||
}
|
||||
$whereStr = implode(' OR ', $conditions);
|
||||
$phpPath = nexus_env('PHP_PATH', 'php');
|
||||
$webRoot = rtrim(ROOT_PATH, '/');
|
||||
while (true) {
|
||||
$msgValues = $idArr = [];
|
||||
$offset = ($page - 1) * $size;
|
||||
@@ -54,10 +61,19 @@ while (true) {
|
||||
if (empty($idArr)) {
|
||||
break;
|
||||
}
|
||||
$idStr = implode(', ', $idArr);
|
||||
$idStr = implode(',', $idArr);
|
||||
if ($isTypeTmpInvite) {
|
||||
$command = sprintf(
|
||||
'%s %s/artisan invite:tmp %s %s %s',
|
||||
$phpPath, $webRoot, $idStr, $_POST['duration'], $amount
|
||||
);
|
||||
$result = exec("$command 2>&1", $output, $result_code);
|
||||
do_log(sprintf('command: %s, result_code: %s, result: %s, output: %s', $command, $result_code, $result, json_encode($output)));
|
||||
} else {
|
||||
sql_query("UPDATE users SET $type = $type + $amount WHERE id in ($idStr)");
|
||||
}
|
||||
$sql = "INSERT INTO messages (sender, receiver, added, subject, msg) VALUES " . implode(', ', $msgValues);
|
||||
sql_query($sql);
|
||||
sql_query("UPDATE users SET $type = $type + $amount WHERE id in ($idStr)");
|
||||
$page++;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ require_once("../include/bittorrent.php");
|
||||
dbconn();
|
||||
require_once(get_langfile_path());
|
||||
registration_check('invitesystem', true, false);
|
||||
if (!user_can('sendinvite'))
|
||||
stderr($lang_takeinvite['std_error'],$lang_takeinvite['std_invite_denied']);
|
||||
if ($CURUSER['invites'] < 1)
|
||||
stderr($lang_takeinvite['std_error'],$lang_takeinvite['std_no_invite']);
|
||||
$userRep = new \App\Repositories\UserRepository();
|
||||
try {
|
||||
$sendText = $userRep->getInviteBtnText($CURUSER['id']);
|
||||
} catch (\Exception $exception) {
|
||||
stderr($lang_takeinvite['std_error'], $exception->getMessage());
|
||||
}
|
||||
function bark($msg) {
|
||||
stdhead();
|
||||
stdmsg($lang_takeinvite['head_invitation_failed'], $msg);
|
||||
@@ -43,7 +45,24 @@ if ($b[0] != 0)
|
||||
$ret = sql_query("SELECT username FROM users WHERE id = ".sqlesc($id)) or sqlerr();
|
||||
$arr = mysql_fetch_assoc($ret);
|
||||
|
||||
$hash = md5(mt_rand(1,10000).$CURUSER['username'].TIMENOW.$CURUSER['passhash']);
|
||||
if (empty($_POST['hash'])) {
|
||||
bark($lang_takeinvite['std_must_select_invite']);
|
||||
}
|
||||
if ($_POST['hash'] == 'permanent') {
|
||||
$hash = md5(mt_rand(1,10000).$CURUSER['username'].TIMENOW.$CURUSER['passhash']);
|
||||
} else {
|
||||
$hashRecord = \App\Models\Invite::query()->where('inviter', $CURUSER['id'])->where('hash', $_POST['hash'])->first();
|
||||
if (!$hashRecord) {
|
||||
bark($lang_takeinvite['hash_not_exists']);
|
||||
}
|
||||
if ($hashRecord->invitee != '') {
|
||||
bark('hash '.$lang_takeinvite['std_is_in_use']);
|
||||
}
|
||||
if ($hashRecord->expired_at->lt(now())) {
|
||||
bark($lang_takeinvite['hash_expired']);
|
||||
}
|
||||
$hash = $_POST['hash'];
|
||||
}
|
||||
|
||||
$title = $SITENAME.$lang_takeinvite['mail_tilte'];
|
||||
|
||||
@@ -60,8 +79,16 @@ EOD;
|
||||
$sendResult = sent_mail($email,$SITENAME,$SITEEMAIL,$title,$message,"invitesignup",false,false,'');
|
||||
//this email is sent only when someone give out an invitation
|
||||
if ($sendResult === true) {
|
||||
sql_query("INSERT INTO invites (inviter, invitee, hash, time_invited) VALUES ('".mysql_real_escape_string($id)."', '".mysql_real_escape_string($email)."', '".mysql_real_escape_string($hash)."', " . sqlesc(date("Y-m-d H:i:s")) . ")");
|
||||
sql_query("UPDATE users SET invites = invites - 1 WHERE id = ".mysql_real_escape_string($id)) or sqlerr(__FILE__, __LINE__);
|
||||
if (isset($hashRecord)) {
|
||||
$hashRecord->update([
|
||||
'invitee' => $email,
|
||||
'time_invited' => now(),
|
||||
'valid' => 1,
|
||||
]);
|
||||
} else {
|
||||
sql_query("INSERT INTO invites (inviter, invitee, hash, time_invited) VALUES ('".mysql_real_escape_string($id)."', '".mysql_real_escape_string($email)."', '".mysql_real_escape_string($hash)."', " . sqlesc(date("Y-m-d H:i:s")) . ")");
|
||||
sql_query("UPDATE users SET invites = invites - 1 WHERE id = ".mysql_real_escape_string($id)) or sqlerr(__FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
header("Refresh: 0; url=invite.php?id=".htmlspecialchars($id)."&sent=1");
|
||||
|
||||
@@ -32,6 +32,7 @@ return [
|
||||
'category' => 'Categories',
|
||||
'second_icon' => 'Second icons',
|
||||
'torrent_operation_log' => 'Torrent operation logs',
|
||||
'invite' => 'Invites',
|
||||
],
|
||||
'resources' => [
|
||||
'agent_allow' => [
|
||||
@@ -76,6 +77,8 @@ return [
|
||||
'grant_prop_form_duration' => 'Duration',
|
||||
'grant_prop_form_duration_help' => 'Unit: days. If left blank, the user has it permanently. Note: There is no time limit for Name Change Card, ignore this value.' ,
|
||||
'confirm_bulk' => 'Bulk confirm',
|
||||
'change_bonus_etc_duration_label' => 'Duration',
|
||||
'change_bonus_etc_duration_help' => 'Required when adding temporary invitation, in days',
|
||||
]
|
||||
],
|
||||
'exam_user' => [
|
||||
|
||||
@@ -2,4 +2,20 @@
|
||||
|
||||
return [
|
||||
'invalid_inviter' => 'Invalid inviter! The invite code is banned!',
|
||||
'fields' => [
|
||||
'inviter' => 'Sender',
|
||||
'invitee' => 'Receive email',
|
||||
'time_invited' => 'Send time',
|
||||
'valid' => 'Valid',
|
||||
'invitee_register_uid' => 'Registered UID',
|
||||
'invitee_register_email' => 'Registered email',
|
||||
'invitee_register_username' => 'Registered username',
|
||||
'expired_at' => 'hash expired at',
|
||||
],
|
||||
'send_deny_reasons' => [
|
||||
'invite_system_closed' => 'Invite system is closed',
|
||||
'no_permission' => 'Require :class or above to send invitations',
|
||||
'invite_not_enough' => 'Invites not enough',
|
||||
],
|
||||
'send_allow_text' => 'Invite someone',
|
||||
];
|
||||
|
||||
@@ -102,6 +102,7 @@ return [
|
||||
'downloadpos' => 'Download privileges',
|
||||
'parked' => 'Parked',
|
||||
'offer_allowed_count' => 'Offer allowed count',
|
||||
'tmp_invites' => 'Temporary invite',
|
||||
],
|
||||
'medal' => [
|
||||
'label' => 'Medal',
|
||||
|
||||
@@ -23,4 +23,8 @@ return [
|
||||
'subject' => 'Download permission restored',
|
||||
'body' => 'Your download privileges restored, you can now download torrents. By: :operator',
|
||||
],
|
||||
'temporary_invite_change' => [
|
||||
'subject' => 'Temporary invite :change_type',
|
||||
'body' => 'Your temporary invite count had :change_type :count by :operator, reason: :reason.',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -10,4 +10,6 @@ return [
|
||||
],
|
||||
'select_all' => 'Select all',
|
||||
'unselect_all' => 'Unselect all',
|
||||
'increment' => 'increment',
|
||||
'decrement' => 'decrement',
|
||||
];
|
||||
|
||||
@@ -30,6 +30,7 @@ return [
|
||||
'category' => '主分类',
|
||||
'second_icon' => '第二图标',
|
||||
'torrent_operation_log' => '种子操作记录',
|
||||
'invite' => '用户邀请',
|
||||
],
|
||||
'resources' => [
|
||||
'agent_allow' => [
|
||||
@@ -74,6 +75,8 @@ return [
|
||||
'grant_prop_form_duration' => '有效时长',
|
||||
'grant_prop_form_duration_help' => '单位:天。如果留空,用户永久拥有。注:改名卡没有时间限制,忽略该值。',
|
||||
'confirm_bulk' => '批量确认',
|
||||
'change_bonus_etc_duration_label' => '有效期',
|
||||
'change_bonus_etc_duration_help' => '增加临时邀请时必须,单位:天',
|
||||
]
|
||||
],
|
||||
'exam_user' => [
|
||||
|
||||
@@ -2,4 +2,20 @@
|
||||
|
||||
return [
|
||||
'invalid_inviter' => '非法邀请者!此邀请码已被禁用!',
|
||||
'fields' => [
|
||||
'inviter' => '发邀者',
|
||||
'invitee' => '接收邮箱',
|
||||
'time_invited' => '发邀时间',
|
||||
'valid' => '是否有效',
|
||||
'invitee_register_uid' => '注册用户 UID',
|
||||
'invitee_register_email' => '注册用户邮箱',
|
||||
'invitee_register_username' => '注册用户名',
|
||||
'expired_at' => 'hash 过期时间',
|
||||
],
|
||||
'send_deny_reasons' => [
|
||||
'invite_system_closed' => '邀请系统已关闭',
|
||||
'no_permission' => ':class 或以上等级才可以发送邀请',
|
||||
'invite_not_enough' => '邀请数量不足',
|
||||
],
|
||||
'send_allow_text' => '邀请其他人',
|
||||
];
|
||||
|
||||
@@ -102,6 +102,7 @@ return [
|
||||
'downloadpos' => '下载权限',
|
||||
'parked' => '挂起',
|
||||
'offer_allowed_count' => '候选通过数',
|
||||
'tmp_invites' => '临时邀请',
|
||||
],
|
||||
'medal' => [
|
||||
'label' => '勋章',
|
||||
|
||||
@@ -23,4 +23,8 @@ return [
|
||||
'subject' => '下载权限恢复',
|
||||
'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator',
|
||||
],
|
||||
'temporary_invite_change' => [
|
||||
'subject' => '临时邀请:change_type',
|
||||
'body' => '你的临时邀请被管理员 :operator :change_type :count 个,理由::reason。',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -10,4 +10,6 @@ return [
|
||||
],
|
||||
'select_all' => '全选',
|
||||
'unselect_all' => '全不选',
|
||||
'increment' => '增加',
|
||||
'decrement' => '减少',
|
||||
];
|
||||
|
||||
@@ -32,6 +32,7 @@ return [
|
||||
'category' => '主分類',
|
||||
'second_icon' => '第二圖標',
|
||||
'torrent_operation_log' => '種子操作記錄',
|
||||
'invite' => '用戶邀請',
|
||||
],
|
||||
'resources' => [
|
||||
'agent_allow' => [
|
||||
@@ -76,6 +77,8 @@ return [
|
||||
'grant_prop_form_duration' => '有效時長',
|
||||
'grant_prop_form_duration_help' => '單位:天。如果留空,用戶永久擁有。註:改名卡沒有時間限製,忽略該值。',
|
||||
'confirm_bulk' => '批量確認',
|
||||
'change_bonus_etc_duration_label' => '有效期',
|
||||
'change_bonus_etc_duration_help' => '增加臨時邀請時必須,單位:天',
|
||||
]
|
||||
],
|
||||
'exam_user' => [
|
||||
|
||||
@@ -2,4 +2,20 @@
|
||||
|
||||
return [
|
||||
'invalid_inviter' => '非法邀請者!此邀請碼已被禁用!',
|
||||
'fields' => [
|
||||
'inviter' => '發邀者',
|
||||
'invitee' => '接收郵箱',
|
||||
'time_invited' => '發邀時間',
|
||||
'valid' => '是否有效',
|
||||
'invitee_register_uid' => '註冊用戶 UID',
|
||||
'invitee_register_email' => '註冊用戶郵箱',
|
||||
'invitee_register_username' => '註冊用戶名',
|
||||
'expired_at' => 'hash 過期時間',
|
||||
],
|
||||
'send_deny_reasons' => [
|
||||
'invite_system_closed' => '邀請系統已關閉',
|
||||
'no_permission' => ':class 或以上等級才可以發送邀請',
|
||||
'invite_not_enough' => '邀請數量不足',
|
||||
],
|
||||
'send_allow_text' => '邀請其他人',
|
||||
];
|
||||
|
||||
@@ -102,6 +102,7 @@ return [
|
||||
'downloadpos' => '下載權限',
|
||||
'parked' => '掛起',
|
||||
'offer_allowed_count' => '候選通過數',
|
||||
'tmp_invites' => '臨時邀請',
|
||||
],
|
||||
'medal' => [
|
||||
'label' => '勛章',
|
||||
|
||||
@@ -22,4 +22,8 @@ return [
|
||||
'subject' => '下載權限恢復',
|
||||
'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator',
|
||||
],
|
||||
'temporary_invite_change' => [
|
||||
'subject' => '臨時邀請:change_type',
|
||||
'body' => '你的臨時邀請被管理員 :operator :change_type :count 個,理由::reason。',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -10,4 +10,6 @@ return [
|
||||
],
|
||||
'select_all' => '全選',
|
||||
'unselect_all' => '全不選',
|
||||
'increment' => '增加',
|
||||
'decrement' => '減少',
|
||||
];
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ __('label.user.invites') }}</th>
|
||||
<td>{{$record->invites}}</td>
|
||||
<td>{{sprintf('%s(%s)', $record->invites, $temporary_invite_count)}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user