diff --git a/app/Console/Commands/Test.php b/app/Console/Commands/Test.php
index 053ee869..488adcda 100644
--- a/app/Console/Commands/Test.php
+++ b/app/Console/Commands/Test.php
@@ -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);
}
diff --git a/app/Repositories/AttendanceRepository.php b/app/Repositories/AttendanceRepository.php
index 5fdc182a..572865c1 100644
--- a/app/Repositories/AttendanceRepository.php
+++ b/app/Repositories/AttendanceRepository.php
@@ -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 = [
diff --git a/include/functions.php b/include/functions.php
index bbeddac2..b2846fdd 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -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(['
', '
'], '', $content);
+ $contentClass = "spoiler-content";
+ if ($defaultCollapsed) {
+ $contentClass .= " collapse";
+ }
+ $HTML = sprintf(
+ '
',
+ $lang_functions['spoiler_expand_collapse'], $title, $contentClass, $content
+ );
+ $js = <<\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 ("".$lang_functions['text_forums']."");
print ("".$lang_functions['text_torrents']."");
- if ($enablespecial == 'yes')
+ if ($enablespecial == 'yes' && get_user_class() >= get_setting('authority.view_special_torrent'))
print ("".$lang_functions['text_special']."");
if ($enableoffer == 'yes')
print ("".$lang_functions['text_offers']."");
@@ -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('', '佩戴', $medal->id, $checked);
+ $html .= sprintf('', nexus_trans('medal.action_wearing'), $medal->pivot->id, $checked);
}
$html .= '';
$medalImages[] = $html;
diff --git a/lang/chs/lang_functions.php b/lang/chs/lang_functions.php
index 826a927d..0943c4d9 100644
--- a/lang/chs/lang_functions.php
+++ b/lang/chs/lang_functions.php
@@ -320,6 +320,8 @@ $lang_functions = array
'text_technical_info_help_text' => 'MediaInfo 来自软件 MediaInfo,用该软件打开文件,点击菜单视图(View)->文件(Text),在框中右键->全选,再右键->复制,粘贴到这里来。',
'text_management_system' => '管理系统',
'text_seed_points' => '做种积分',
+ 'spoiler_expand_collapse' => '点击展开/收缩',
+ 'spoiler_default_title' => '折叠内容',
);
?>
diff --git a/lang/chs/lang_tags.php b/lang/chs/lang_tags.php
index fe3d7266..f9bb4135 100644
--- a/lang/chs/lang_tags.php
+++ b/lang/chs/lang_tags.php
@@ -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]',
);
?>
diff --git a/lang/cht/lang_functions.php b/lang/cht/lang_functions.php
index 4194b49b..0936fe9d 100644
--- a/lang/cht/lang_functions.php
+++ b/lang/cht/lang_functions.php
@@ -321,6 +321,8 @@ $lang_functions = array
'text_technical_info_help_text' => 'MediaInfo 來自軟件 MediaInfo,用該軟件打開文件,點擊菜單視圖(View)->文件(Text),在框中右鍵->全選,再右鍵->復制,粘貼到這裏來。',
'text_management_system' => '管理系統',
'text_seed_points' => '做種積分',
+ 'spoiler_expand_collapse' => '點擊展開/收縮',
+ 'spoiler_default_title' => '折疊內容',
);
?>
diff --git a/lang/cht/lang_tags.php b/lang/cht/lang_tags.php
index dadffada..ef9d6f3d 100644
--- a/lang/cht/lang_tags.php
+++ b/lang/cht/lang_tags.php
@@ -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]',
);
diff --git a/lang/en/lang_functions.php b/lang/en/lang_functions.php
index 9355ffa1..7a5a3690 100644
--- a/lang/en/lang_functions.php
+++ b/lang/en/lang_functions.php
@@ -322,6 +322,8 @@ $lang_functions = array
'text_technical_info_help_text' => 'MediaInfo comes from software MediaInfo,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',
);
?>
diff --git a/lang/en/lang_tags.php b/lang/en/lang_tags.php
index b96e7aa5..e3c01196 100644
--- a/lang/en/lang_tags.php
+++ b/lang/en/lang_tags.php
@@ -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]',
);
?>
diff --git a/nexus/Nexus.php b/nexus/Nexus.php
index 21d6e7b1..87598fd5 100644
--- a/nexus/Nexus.php
+++ b/nexus/Nexus.php
@@ -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('', $js);
} else {
$append = sprintf('', $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('', $css);
} else {
$append = sprintf('', $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");
}
diff --git a/public/styles/sprites.css b/public/styles/sprites.css
index 9da98db0..a266308e 100644
--- a/public/styles/sprites.css
+++ b/public/styles/sprites.css
@@ -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;
+}
diff --git a/public/tags.php b/public/tags.php
index 6715678d..a98bab17 100644
--- a/public/tags.php
+++ b/public/tags.php
@@ -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();
diff --git a/resources/lang/en/attendance.php b/resources/lang/en/attendance.php
new file mode 100644
index 00000000..6fc47cb6
--- /dev/null
+++ b/resources/lang/en/attendance.php
@@ -0,0 +1,8 @@
+ "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',
+];
diff --git a/resources/lang/en/medal.php b/resources/lang/en/medal.php
index eb712b18..bd5fd57c 100644
--- a/resources/lang/en/medal.php
+++ b/resources/lang/en/medal.php
@@ -1,6 +1,7 @@
'Wear',
'admin' => [
'list' => [
'page_title' => 'Medal list'
diff --git a/resources/lang/zh_CN/attendance.php b/resources/lang/zh_CN/attendance.php
new file mode 100644
index 00000000..f9c61531
--- /dev/null
+++ b/resources/lang/zh_CN/attendance.php
@@ -0,0 +1,8 @@
+ '还没有签过到',
+ 'target_date_can_no_be_retroactive' => '日期::date 无法补签',
+ 'already_attendance' => '已经签到',
+ 'card_not_enough' => '补签卡不足',
+];
diff --git a/resources/lang/zh_CN/medal.php b/resources/lang/zh_CN/medal.php
index 32cbbc7f..2a135cdf 100644
--- a/resources/lang/zh_CN/medal.php
+++ b/resources/lang/zh_CN/medal.php
@@ -1,6 +1,7 @@
'佩戴',
'admin' => [
'list' => [
'page_title' => '勋章列表'
diff --git a/resources/lang/zh_TW/attendance.php b/resources/lang/zh_TW/attendance.php
new file mode 100644
index 00000000..c0ee2363
--- /dev/null
+++ b/resources/lang/zh_TW/attendance.php
@@ -0,0 +1,9 @@
+ '還沒有簽過到',
+ 'target_date_can_no_be_retroactive' => '日期::date 無法補簽',
+ 'already_attendance' => '已經簽到',
+ 'card_not_enough' => '補簽卡不足',
+];
+
diff --git a/resources/lang/zh_TW/medal.php b/resources/lang/zh_TW/medal.php
index 492d0101..3de5b5f2 100644
--- a/resources/lang/zh_TW/medal.php
+++ b/resources/lang/zh_TW/medal.php
@@ -1,6 +1,7 @@
'佩戴',
'admin' => [
'list' => [
'page_title' => '勛章列表'