mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-03 14:10:57 +08:00
add spoiler tag + fix attendance additional rewards
This commit is contained in:
@@ -118,24 +118,13 @@ class Test extends Command
|
||||
// $r = $searchRep->deleteBookmark(1);
|
||||
// $r = $searchRep->addBookmark(1);
|
||||
|
||||
// $rep = new AttendanceRepository();
|
||||
// $uid = 1;
|
||||
// $attendance = $rep->getAttendance($uid);
|
||||
$rep = new AttendanceRepository();
|
||||
$uid = 1;
|
||||
$attendance = $rep->getAttendance($uid);
|
||||
// $r = $rep->migrateAttendanceLogs($uid);
|
||||
// $r = $rep->getContinuousDays($attendance);
|
||||
// $r = $rep->getContinuousPoints(30);
|
||||
// $today = Carbon::today();
|
||||
// $tomorrow = Carbon::tomorrow();
|
||||
// $yesterday = Carbon::parse('+10 days');
|
||||
// dd($today->diffInDays($yesterday));
|
||||
// $r = get_smile(12);
|
||||
// dd($r);
|
||||
|
||||
// $key = "dddd1";
|
||||
// $model = \App\Models\TorrentSecret::query()->where('id', 1)->first();
|
||||
// \Nexus\Database\NexusDB::cache_put($key, $model);
|
||||
|
||||
$peer = new Peer(['last_action' => '2022-04-08 22:20:14']);
|
||||
$r = $rep->getContinuousPoints(11);
|
||||
dd($r);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ class AttendanceRepository extends BaseRepository
|
||||
$diffDays = $today->diffInDays($added);
|
||||
if ($diffDays == 1) {
|
||||
//yesterday do it, it's continuous
|
||||
do_log("[CONTINUOUS]");
|
||||
$continuousDays = $this->getContinuousDays($attendance);
|
||||
$points = $this->getContinuousPoints($continuousDays);
|
||||
$continuousDays = $this->getContinuousDays($attendance, Carbon::yesterday());
|
||||
$points = $this->getContinuousPoints($continuousDays + 1);
|
||||
do_log("[CONTINUOUS] continuous days from yesterday: $continuousDays, points: $points");
|
||||
$update = [
|
||||
'added' => $now,
|
||||
'points' => $points,
|
||||
@@ -93,10 +93,10 @@ class AttendanceRepository extends BaseRepository
|
||||
$step = $settings['attendance_step'] ?? Attendance::STEP_BONUS;
|
||||
$max = $settings['attendance_max'] ?? Attendance::MAX_BONUS;
|
||||
$extraAwards = $settings['attendance_continuous'] ?? Attendance::CONTINUOUS_BONUS;
|
||||
$points = min($initial + $days * $step, $max);
|
||||
$points = min($initial + ($days - 1) * $step, $max);
|
||||
krsort($extraAwards);
|
||||
foreach ($extraAwards as $key => $value) {
|
||||
if ($days >= $key - 1) {
|
||||
if ($days == $key) {
|
||||
$points += $value;
|
||||
break;
|
||||
}
|
||||
@@ -248,14 +248,10 @@ class AttendanceRepository extends BaseRepository
|
||||
return $insertCount;
|
||||
}
|
||||
|
||||
public function getContinuousDays(Attendance $attendance, $start = ''): int
|
||||
public function getContinuousDays(Attendance $attendance, $start): int
|
||||
{
|
||||
if (!empty($start)) {
|
||||
$start = Carbon::parse($start);
|
||||
} else {
|
||||
$start = $attendance->added;
|
||||
}
|
||||
$logQuery = $attendance->logs()->where('date', '<=', $start)->orderBy('date', 'desc');
|
||||
$start = Carbon::parse($start);
|
||||
$logQuery = $attendance->logs()->where('date', '<=', $start->format('Y-m-d'))->orderBy('date', 'desc');
|
||||
$attendanceLogs = $logQuery->get(['date'])->keyBy('date');
|
||||
$counts = $attendanceLogs->count();
|
||||
do_log(sprintf('user: %s, log counts: %s from query: %s', $attendance->uid, $counts, last_query()));
|
||||
@@ -269,9 +265,9 @@ class AttendanceRepository extends BaseRepository
|
||||
$checkDate = $value->format('Y-m-d');
|
||||
if ($attendanceLogs->has($checkDate)) {
|
||||
$days++;
|
||||
do_log(sprintf('user: %s, date: %s, has attendance, now days: %s', $attendance->uid, $checkDate, $days));
|
||||
do_log(sprintf('user: %s, date: %s, [HAS_ATTENDANCE], now days: %s', $attendance->uid, $checkDate, $days));
|
||||
} else {
|
||||
do_log(sprintf('user: %s, date: %s, not attendance, now days: %s', $attendance->uid, $checkDate, $days));
|
||||
do_log(sprintf('user: %s, date: %s, [NOT_ATTENDANCE], now days: %s', $attendance->uid, $checkDate, $days));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -286,24 +282,24 @@ class AttendanceRepository extends BaseRepository
|
||||
}
|
||||
$attendance = $this->getAttendance($user->id);
|
||||
if (!$attendance) {
|
||||
throw new \LogicException("Haven't attendance yet");
|
||||
throw new \LogicException(nexus_trans('attendance.have_not_attendance_yet'));
|
||||
}
|
||||
$date = Carbon::createFromTimestampMs($timestampMs);
|
||||
$now = Carbon::now();
|
||||
if ($date->gte($now) || $now->diffInDays($date) > Attendance::MAX_RETROACTIVE_DAYS) {
|
||||
throw new \LogicException(sprintf("date: %s can't be retroactive attend", $date->format('Y-m-d')));
|
||||
throw new \LogicException(nexus_trans('attendance.target_date_can_no_be_retroactive', ['date' => $date->format('Y-m-d')]));
|
||||
}
|
||||
return NexusDB::transaction(function () use ($user, $attendance, $date) {
|
||||
if (AttendanceLog::query()->where('uid', $user->id)->where('date', $date->format('Y-m-d'))->exists()) {
|
||||
throw new \RuntimeException("Already attendance");
|
||||
throw new \RuntimeException(nexus_trans('attendance.already_attendance'));
|
||||
}
|
||||
if ($user->attendance_card < 1) {
|
||||
throw new \RuntimeException("Attendance card not enough");
|
||||
throw new \RuntimeException(nexus_trans('attendance.card_not_enough'));
|
||||
}
|
||||
$log = sprintf('user: %s, card: %s, retroactive date: %s', $user->id, $user->attendance_card, $date->format('Y-m-d'));
|
||||
$continuousDays = $this->getContinuousDays($attendance, $date->clone()->subDay(1));
|
||||
$log .= ", continuousDays: $continuousDays";
|
||||
$points = $this->getContinuousPoints($continuousDays);
|
||||
$continuousDays = $this->getContinuousDays($attendance, $date->clone()->subDays(1));
|
||||
$log .= ", continuousDays from prev day: $continuousDays";
|
||||
$points = $this->getContinuousPoints($continuousDays + 1);
|
||||
$log .= ", points: $points";
|
||||
do_log($log);
|
||||
$userUpdates = [
|
||||
|
||||
@@ -262,6 +262,36 @@ function formatYoutube($src, $width = '', $height = ''): string
|
||||
$width, $height, $videoId
|
||||
));
|
||||
}
|
||||
|
||||
function formatSpoiler($content, $title = '', $defaultCollapsed = true): string
|
||||
{
|
||||
global $lang_functions;
|
||||
if (!$title) {
|
||||
$title = $lang_functions['spoiler_default_title'];
|
||||
}
|
||||
$content = str_replace(['<br>', '<br />'], '', $content);
|
||||
$contentClass = "spoiler-content";
|
||||
if ($defaultCollapsed) {
|
||||
$contentClass .= " collapse";
|
||||
}
|
||||
$HTML = sprintf(
|
||||
'<div><div><div class="spoiler-title" title="%s">%s</div></div><div class="%s"><pre>%s</pre></div></div>',
|
||||
$lang_functions['spoiler_expand_collapse'], $title, $contentClass, $content
|
||||
);
|
||||
$js = <<<JS
|
||||
jQuery('.spoiler-title').on('click', function () {
|
||||
let content = jQuery(this).parent().next();
|
||||
if (content.hasClass('collapse')) {
|
||||
content.height(content[0].scrollHeight).removeClass('collapse')
|
||||
} else {
|
||||
content.height(0).addClass('collapse')
|
||||
}
|
||||
})
|
||||
JS;
|
||||
\Nexus\Nexus::js($js, 'footer', false, 'spoiler');
|
||||
return addTempCode($HTML);
|
||||
}
|
||||
|
||||
function format_urls($text, $newWindow = false) {
|
||||
// return preg_replace("/((https?|ftp|gopher|news|telnet|mms|rtsp):\/\/[^()\[\]<>\s]+)/ei", "formatUrl('\\1', ".($newWindow==true ? 1 : 0).", '', 'faqlink')", $text);
|
||||
return preg_replace_callback("/((https?|ftp|gopher|news|telnet|mms|rtsp):\/\/[^()\[\]<>\s]+)/i", function ($matches) use ($newWindow) {
|
||||
@@ -350,6 +380,12 @@ function format_comment($text, $strip_html = true, $xssclean = false, $newtab =
|
||||
return formatYoutube($matches[4], $matches[2], $matches[3]);
|
||||
}, $s);
|
||||
}
|
||||
//[spoiler=What happens to the hero?]The hero dies at the end![/spoiler]
|
||||
if (str_contains($s, '[spoiler')) {
|
||||
$s = preg_replace_callback("/\[spoiler(=(.*))?\](.+?)\[\/spoiler\]/is", function ($matches) {
|
||||
return formatSpoiler($matches[3], $matches[2], nexus()->getScript() != 'preview');
|
||||
}, $s);
|
||||
}
|
||||
|
||||
// [url=http://www.example.com]Text[/url]
|
||||
if ($adid) {
|
||||
@@ -2202,7 +2238,7 @@ function menu ($selected = "home") {
|
||||
else
|
||||
print ("<li" . ($selected == "forums" ? " class=\"selected\"" : "") . "><a href=\"" . $extforumurl."\" target=\"_blank\">".$lang_functions['text_forums']."</a></li>");
|
||||
print ("<li" . ($selected == "torrents" ? " class=\"selected\"" : "") . "><a href=\"torrents.php\">".$lang_functions['text_torrents']."</a></li>");
|
||||
if ($enablespecial == 'yes')
|
||||
if ($enablespecial == 'yes' && get_user_class() >= get_setting('authority.view_special_torrent'))
|
||||
print ("<li" . ($selected == "special" ? " class=\"selected\"" : "") . "><a href=\"special.php\">".$lang_functions['text_special']."</a></li>");
|
||||
if ($enableoffer == 'yes')
|
||||
print ("<li" . ($selected == "offers" ? " class=\"selected\"" : "") . "><a href=\"offers.php\">".$lang_functions['text_offers']."</a></li>");
|
||||
@@ -5105,11 +5141,11 @@ function strip_all_tags($text)
|
||||
//替换掉无参数标签
|
||||
$bbTags = [
|
||||
'[*]', '[b]', '[/b]', '[i]', '[/i]', '[u]', '[/u]', '[pre]', '[/pre]', '[quote]', '[/quote]',
|
||||
'[/color]', '[/font]', '[/size]', '[/url]'
|
||||
'[/color]', '[/font]', '[/size]', '[/url]', '[/youtube]',
|
||||
];
|
||||
$text = str_replace($bbTags, '', $text);
|
||||
//替换掉有参数标签
|
||||
$pattern = '/\[url=.*\]|\[color=.*\]|\[font=.*\]|\[size=.*\]/isU';
|
||||
$pattern = '/\[url=.*\]|\[color=.*\]|\[font=.*\]|\[size=.*\]|\[youtube.*\]/isU';
|
||||
$text = preg_replace($pattern, "", $text);
|
||||
//去掉表情
|
||||
static $emoji = null;
|
||||
@@ -5365,7 +5401,7 @@ function build_medal_image(\Illuminate\Support\Collection $medals, $maxHeight =
|
||||
if ($medal->pivot->status == \App\Models\UserMedal::STATUS_WEARING) {
|
||||
$checked = ' checked';
|
||||
}
|
||||
$html .= sprintf('<label>%s<input type="checkbox" name="medal_wearing_status" value="%s"%s></label>', '佩戴', $medal->id, $checked);
|
||||
$html .= sprintf('<label>%s<input type="checkbox" name="medal_wearing_status" value="%s"%s></label>', nexus_trans('medal.action_wearing'), $medal->pivot->id, $checked);
|
||||
}
|
||||
$html .= '</div>';
|
||||
$medalImages[] = $html;
|
||||
|
||||
@@ -320,6 +320,8 @@ $lang_functions = array
|
||||
'text_technical_info_help_text' => 'MediaInfo 来自软件 <b><a href="https://mediaarea.net/en/MediaInfo" target=\'_blank\'>MediaInfo</a></b>,用该软件打开文件,点击菜单视图(View)->文件(Text),在框中右键->全选,再右键->复制,粘贴到这里来。',
|
||||
'text_management_system' => '管理系统',
|
||||
'text_seed_points' => '做种积分',
|
||||
'spoiler_expand_collapse' => '点击展开/收缩',
|
||||
'spoiler_default_title' => '折叠内容',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -129,6 +129,10 @@ $lang_tags = array
|
||||
'text_ninety_eight_image_syntax' => " [98img=[auto|number]]图片文件[/98img]",
|
||||
'text_ninety_eight_image_example' => "[98img=150]uploadfile/2008/10/30/2362924185.png[/98img]",
|
||||
'text_ninety_eight_image_remarks' => "CC98是浙江大学的一个论坛",
|
||||
'text_spoiler' => '折叠',
|
||||
'text_spoiler_description' => '在页面插入可展开/收缩的内容',
|
||||
'text_spoiler_syntax' => '[spoiler=标题]这是被折叠的内容[/spoiler]',
|
||||
'text_spoiler_example' => '[spoiler=英雄最后的结局怎么样了?]英雄最后死掉了![/spoiler]',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -321,6 +321,8 @@ $lang_functions = array
|
||||
'text_technical_info_help_text' => 'MediaInfo 來自軟件 <b><a href="https://mediaarea.net/en/MediaInfo" target=\'_blank\'>MediaInfo</a></b>,用該軟件打開文件,點擊菜單視圖(View)->文件(Text),在框中右鍵->全選,再右鍵->復制,粘貼到這裏來。',
|
||||
'text_management_system' => '管理系統',
|
||||
'text_seed_points' => '做種積分',
|
||||
'spoiler_expand_collapse' => '點擊展開/收縮',
|
||||
'spoiler_default_title' => '折疊內容',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -129,6 +129,10 @@ $lang_tags = array
|
||||
'text_ninety_eight_image_syntax' => " [98img=[auto|number]]圖片文件[/98img]",
|
||||
'text_ninety_eight_image_example' => "[98img=150]uploadfile/2008/10/30/2362924185.png[/98img]",
|
||||
'text_ninety_eight_image_remarks' => "CC98是浙江大學的一個論壇",
|
||||
'text_spoiler' => '折疊',
|
||||
'text_spoiler_description' => '在頁面插入可展開/收縮的內容',
|
||||
'text_spoiler_syntax' => '[spoiler=標題]這是被折疊的內容[/spoiler]',
|
||||
'text_spoiler_example' => '[spoiler=英雄最後的結局怎麽樣了?]英雄最後死掉了![/spoiler]',
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -322,6 +322,8 @@ $lang_functions = array
|
||||
'text_technical_info_help_text' => 'MediaInfo comes from software <b><a href="https://mediaarea.net/en/MediaInfo" target=\'_blank\'>MediaInfo</a></b>,open file, click the view menu > text > right click in the box > select all > copy > past into this box.',
|
||||
'text_management_system' => 'Management system',
|
||||
'text_seed_points' => 'Seed points',
|
||||
'spoiler_expand_collapse' => 'Click to expand/collapse',
|
||||
'spoiler_default_title' => 'Collapse content',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -129,6 +129,10 @@ $lang_tags = array
|
||||
'text_ninety_eight_image_syntax' => " [98img=[auto|number]]image file[/98img]",
|
||||
'text_ninety_eight_image_example' => "[98img=150]uploadfile/2008/10/30/2362924185.png[/98img]",
|
||||
'text_ninety_eight_image_remarks' => "CC98 is a forum at Zhejiang University",
|
||||
'text_spoiler' => 'Spoiler',
|
||||
'text_spoiler_description' => 'Insert expandable/collapsible content on the page',
|
||||
'text_spoiler_syntax' => '[spoiler=title]This is the folded content[/spoiler]',
|
||||
'text_spoiler_example' => '[spoiler=What happened to the final ending of the hero?]The hero died last![/spoiler]',
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -217,33 +217,39 @@ final class Nexus
|
||||
$this->platform = (string)$this->retrieveFromServer(['HTTP_PLATFORM', 'Platform', 'platform'], true);
|
||||
}
|
||||
|
||||
public static function js(string $js, string $position, bool $isFile)
|
||||
public static function js(string $js, string $position, bool $isFile, $key = null)
|
||||
{
|
||||
if ($isFile) {
|
||||
$append = sprintf('<script type="text/javascript" src="%s"></script>', $js);
|
||||
} else {
|
||||
$append = sprintf('<script type="text/javascript">%s</script>', $js);
|
||||
}
|
||||
if ($position == 'header') {
|
||||
self::$appendHeaders[] = $append;
|
||||
} elseif ($position == 'footer') {
|
||||
self::$appendFooters[] = $append;
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Invalid position: $position");
|
||||
}
|
||||
self::appendJsCss($append, $position, $key);
|
||||
}
|
||||
|
||||
public static function css(string $css, string $position, bool $isFile)
|
||||
public static function css(string $css, string $position, bool $isFile, $key = null)
|
||||
{
|
||||
if ($isFile) {
|
||||
$append = sprintf('<link rel="stylesheet" href="%s" type="text/css">', $css);
|
||||
} else {
|
||||
$append = sprintf('<style type="text/css">%s</style>', $css);
|
||||
}
|
||||
self::appendJsCss($append, $position, $key);
|
||||
}
|
||||
|
||||
private static function appendJsCss($append, $position, $key = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
$key = md5($append);
|
||||
}
|
||||
if ($position == 'header') {
|
||||
self::$appendHeaders[] = $append;
|
||||
if (!isset(self::$appendHeaders[$key])) {
|
||||
self::$appendHeaders[$key] = $append;
|
||||
}
|
||||
} elseif ($position == 'footer') {
|
||||
self::$appendFooters[] = $append;
|
||||
if (!isset(self::$appendFooters[$key])) {
|
||||
self::$appendFooters[$key] = $append;
|
||||
}
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Invalid position: $position");
|
||||
}
|
||||
|
||||
15
public/styles/sprites.css
vendored
15
public/styles/sprites.css
vendored
@@ -480,3 +480,18 @@ img.hitandrun {
|
||||
background: url(icons.gif) no-repeat -100px -171px;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.spoiler-title {
|
||||
line-height: 40px;
|
||||
color: #4d6c99;
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
background-color: rgba(77, 108, 153, 0.1);
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.spoiler-content {
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
@@ -252,6 +252,15 @@ insert_tag(
|
||||
$lang_tags['text_ninety_eight_image_remarks']
|
||||
);*/
|
||||
|
||||
|
||||
insert_tag(
|
||||
$lang_tags['text_spoiler'],
|
||||
$lang_tags['text_spoiler_description'],
|
||||
$lang_tags['text_spoiler_syntax'],
|
||||
$lang_tags['text_spoiler_example'],
|
||||
""
|
||||
);
|
||||
|
||||
end_frame();
|
||||
end_main_frame();
|
||||
stdfoot();
|
||||
|
||||
8
resources/lang/en/attendance.php
Normal file
8
resources/lang/en/attendance.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'have_not_attendance_yet' => "Haven't attendance yet",
|
||||
'target_date_can_no_be_retroactive' => 'Date::date can not be retroactive',
|
||||
'already_attendance' => 'Already attendance',
|
||||
'card_not_enough' => 'Attendance card not enough',
|
||||
];
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'action_wearing' => 'Wear',
|
||||
'admin' => [
|
||||
'list' => [
|
||||
'page_title' => 'Medal list'
|
||||
|
||||
8
resources/lang/zh_CN/attendance.php
Normal file
8
resources/lang/zh_CN/attendance.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'have_not_attendance_yet' => '还没有签过到',
|
||||
'target_date_can_no_be_retroactive' => '日期::date 无法补签',
|
||||
'already_attendance' => '已经签到',
|
||||
'card_not_enough' => '补签卡不足',
|
||||
];
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'action_wearing' => '佩戴',
|
||||
'admin' => [
|
||||
'list' => [
|
||||
'page_title' => '勋章列表'
|
||||
|
||||
9
resources/lang/zh_TW/attendance.php
Normal file
9
resources/lang/zh_TW/attendance.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'have_not_attendance_yet' => '還沒有簽過到',
|
||||
'target_date_can_no_be_retroactive' => '日期::date 無法補簽',
|
||||
'already_attendance' => '已經簽到',
|
||||
'card_not_enough' => '補簽卡不足',
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'action_wearing' => '佩戴',
|
||||
'admin' => [
|
||||
'list' => [
|
||||
'page_title' => '勛章列表'
|
||||
|
||||
Reference in New Issue
Block a user