From 880a41023d1d7db934150745d6f5676afceb12bf Mon Sep 17 00:00:00 2001 From: movsb Date: Fri, 15 Nov 2024 22:07:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=B6=E5=8C=BA=E6=94=AF=E6=8C=81=EF=BC=88?= =?UTF-8?q?=E9=83=A8=E5=88=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server/main.go | 1 + modules/logs/request.go | 3 +- modules/utils/maintenance.go | 4 +- protocols/comment.proto | 4 ++ protocols/post.proto | 4 ++ service/comment.go | 11 +++++ service/main.go | 10 +++++ service/models/comment.go | 6 +++ service/models/post.go | 6 +++ service/post.go | 12 ++++++ setup/data/schemas.sqlite.sql | 4 ++ setup/migration/init.go | 5 +++ setup/migration/list.go | 1 + setup/migration/versions.go | 7 ++++ theme/blog/statics/scripts/comment.js | 60 ++++++++++++++++++++++++--- theme/data/post.go | 4 -- 16 files changed, 128 insertions(+), 14 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index d2560767..f6ddb68d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -92,6 +92,7 @@ func (s *Server) Serve(ctx context.Context, testing bool, cfg *config.Config, re }) log.Println(`DevMode:`, service.DevMode()) + log.Println(`Time.Now:`, time.Now().Format(time.RFC3339)) instantNotifier := notify.NewConsoleNotify() if token := cfg.Notify.Chanify.Token; token != "" { diff --git a/modules/logs/request.go b/modules/logs/request.go index 174356fc..3c0b9066 100644 --- a/modules/logs/request.go +++ b/modules/logs/request.go @@ -91,7 +91,6 @@ func (w *_ResponseWriter) Write(b []byte) (int, error) { } func (l *RequestLogger) Handler(h http.Handler) http.Handler { - tz := time.FixedZone(`China`, 8*60*60) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { takeOver := &_ResponseWriter{ ResponseWriter: w, @@ -102,7 +101,7 @@ func (l *RequestLogger) Handler(h http.Handler) http.Handler { l.counter.Store(0) l.lock.Lock() defer l.lock.Unlock() - now := time.Now().In(tz).Format(`2006-01-02 15:04:05`) + now := time.Now().Format(time.RFC3339) ac := auth.Context(r.Context()) fmt.Fprintf(l.f, "%s %-15s %3d %-8s %-32s %-32s %-32s\n", diff --git a/modules/utils/maintenance.go b/modules/utils/maintenance.go index 5541e1c3..102b8a0e 100644 --- a/modules/utils/maintenance.go +++ b/modules/utils/maintenance.go @@ -51,9 +51,7 @@ func (m *Maintenance) EstimatedString() string { if m.Estimated < 0 { return `(未知)` } - t := time.Now().Add(m.Estimated) - tz := time.FixedZone(`China`, 8*60*60) - return t.In(tz).Format(`2006-01-02 15:04:05 -0700`) + return time.Now().Add(m.Estimated).Format(time.RFC3339) } func (m *Maintenance) Handler(exception func(ctx context.Context) bool) func(http.Handler) http.Handler { diff --git a/protocols/comment.proto b/protocols/comment.proto index 7fab93b0..caf3316b 100644 --- a/protocols/comment.proto +++ b/protocols/comment.proto @@ -55,6 +55,10 @@ message Comment { int32 avatar = 18; int32 modified = 19; + + // 创建时间和修改时间所在的时区。 + string date_timezone = 20; + string modified_timezone = 21; } message GetCommentRequest { diff --git a/protocols/post.proto b/protocols/post.proto index 676d83e2..41faebb1 100644 --- a/protocols/post.proto +++ b/protocols/post.proto @@ -90,6 +90,10 @@ message Post { // 文章的链接。 string link = 19; + + // 创建时间和修改时间所在的时区。 + string date_timezone = 20; + string modified_timezone = 21; } enum LinkKind { diff --git a/service/comment.go b/service/comment.go index 10f0c7a6..fa0f4232 100644 --- a/service/comment.go +++ b/service/comment.go @@ -177,6 +177,9 @@ func (s *Service) UpdateComment(ctx context.Context, req *proto.UpdateCommentReq case `modified`: hasModified = true data[`modified`] = time.Now().Unix() + case `modified_timezone`: + // hasModified = true + data[mask] = req.Comment.ModifiedTimezone } } if !hasModified { @@ -385,13 +388,21 @@ func (s *Service) CreateComment(ctx context.Context, in *proto.Comment) (*proto. Source: in.Source, } + c.ModifiedTimezone = in.ModifiedTimezone if in.Modified > 0 { c.Modified = in.Modified } + + c.DateTimezone = in.DateTimezone + if c.ModifiedTimezone == `` && c.DateTimezone != `` { + c.ModifiedTimezone = c.DateTimezone + } + if in.Date > 0 { c.Date = in.Date if in.Modified == 0 { c.Modified = c.Date + c.ModifiedTimezone = c.DateTimezone } } else { c.Date = int32(now.Unix()) diff --git a/service/main.go b/service/main.go index 830393b6..1daff531 100644 --- a/service/main.go +++ b/service/main.go @@ -65,6 +65,9 @@ type Service struct { home *url.URL + // 服务器默认的时区。 + timeLocation *time.Location + cfg *config.Config postDataFS theme_fs.FS @@ -149,6 +152,9 @@ func newService(ctx context.Context, cancel context.CancelFunc, cfg *config.Conf cfg: cfg, postDataFS: &theme_fs.Empty{}, + // TODO 可配置使用的时区,而不是使用服务器当前时间或者硬编码成+8时区。 + timeLocation: time.Now().Location(), + db: db, tdb: taorm.NewDB(db), auth: auther, @@ -268,6 +274,10 @@ func newService(ctx context.Context, cancel context.CancelFunc, cfg *config.Conf // 从 Context 中取出用户并且必须为 Admin/System,否则 panic。 func (s *Service) MustBeAdmin(ctx context.Context) *auth.AuthContext { + return MustBeAdmin(ctx) +} + +func MustBeAdmin(ctx context.Context) *auth.AuthContext { ac := auth.Context(ctx) if ac == nil { panic("AuthContext 不应为 nil") diff --git a/service/models/comment.go b/service/models/comment.go index db4e1bdf..be6ef7a1 100644 --- a/service/models/comment.go +++ b/service/models/comment.go @@ -21,6 +21,9 @@ type Comment struct { Modified int32 `json:"modified"` SourceType string `json:"source_type"` Source string `json:"source"` + + DateTimezone string + ModifiedTimezone string } // TableName ... @@ -52,6 +55,9 @@ func (c *Comment) ToProto(redact func(c *proto.Comment)) *proto.Comment { SourceType: c.SourceType, Source: c.Source, DateFuzzy: timeago.Chinese.Format(time.Unix(int64(c.Date), 0)), + + DateTimezone: c.DateTimezone, + ModifiedTimezone: c.ModifiedTimezone, } redact(&comment) return &comment diff --git a/service/models/post.go b/service/models/post.go index e8c8d79b..6a408789 100644 --- a/service/models/post.go +++ b/service/models/post.go @@ -28,6 +28,9 @@ type Post struct { Metas PostMeta Source string SourceType string + + DateTimezone string + ModifiedTimezone string } // NOTE 如果要添加字段,记得同步 isEmpty 方法。 @@ -179,6 +182,9 @@ func (p *Post) ToProto(redact func(p *proto.Post) error) (*proto.Post, error) { SourceType: p.SourceType, LastCommentedAt: p.LastCommentedAt, + + DateTimezone: p.DateTimezone, + ModifiedTimezone: p.ModifiedTimezone, } err := redact(&out) return &out, err diff --git a/service/post.go b/service/post.go index dcb27966..e220db11 100644 --- a/service/post.go +++ b/service/post.go @@ -500,17 +500,24 @@ func (s *Service) CreatePost(ctx context.Context, in *proto.Post) (*proto.Post, return nil, status.Error(codes.InvalidArgument, "内容不应为空。") } + p.ModifiedTimezone = in.ModifiedTimezone if in.Modified > 0 { p.Modified = in.Modified } + + p.DateTimezone = in.DateTimezone if in.Date > 0 { p.Date = in.Date if in.Modified == 0 { p.Modified = p.Date + p.ModifiedTimezone = p.DateTimezone } } else { p.Date = now p.Modified = now + // TODO 设置时区。 + p.DateTimezone = `` + p.ModifiedTimezone = `` } if in.Status != "" { @@ -577,6 +584,7 @@ func (s *Service) UpdatePost(ctx context.Context, in *proto.UpdatePostRequest) ( // 适用于导入三方数据的时候更新导入。 if !in.DoNotTouch { m[`modified`] = now + // TODO 使用 now 的时区对应名修改 modified_timezone } var hasSourceType, hasSource bool @@ -608,6 +616,10 @@ func (s *Service) UpdatePost(ctx context.Context, in *proto.UpdatePostRequest) ( hasType = true case `date`: m[`date`] = in.Post.Date + case `date_timezone`: + m[path] = in.Post.DateTimezone + case `modified_timezone`: + m[path] = in.Post.ModifiedTimezone case `status`: m[`status`] = in.Post.Status default: diff --git a/setup/data/schemas.sqlite.sql b/setup/data/schemas.sqlite.sql index ea32cd39..28ae9b1b 100644 --- a/setup/data/schemas.sqlite.sql +++ b/setup/data/schemas.sqlite.sql @@ -11,7 +11,9 @@ CREATE TABLE IF NOT EXISTS `options` ( CREATE TABLE IF NOT EXISTS `posts` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `date` INTEGER NOT NULL, + `date_timezone` TEXT NOT NULL, `modified` INTEGER NOT NULL, + `modified_timezone` TEXT NOT NULL, `last_commented_at` INTEGER NOT NULL, `title` TEXT NOT NULL, `slug` TEXT NOT NULL, @@ -35,7 +37,9 @@ CREATE TABLE IF NOT EXISTS `comments` ( `url` TEXT NOT NULL, `ip` TEXT NOT NULL, `date` INTEGER NOT NULL, + `date_timezone` TEXT NOT NULL, `modified` INTEGER NOT NULL, + `modified_timezone` TEXT NOT NULL, `source_type` TEXT NOT NULL, `source` TEXT NOT NULL, `parent` INTEGER NOT NULL, diff --git a/setup/migration/init.go b/setup/migration/init.go index 33271122..ac73633d 100644 --- a/setup/migration/init.go +++ b/setup/migration/init.go @@ -51,6 +51,11 @@ func Init(db *sql.DB, path string) { Status: `public`, SourceType: `markdown`, Source: `你好,世界!这是您的第一篇文章。`, + + // TODO 用配置时区。 + DateTimezone: ``, + // TODO 用配置时区。 + ModifiedTimezone: ``, }).MustCreate() }) } diff --git a/setup/migration/list.go b/setup/migration/list.go index 613e7cd6..93640e7a 100644 --- a/setup/migration/list.go +++ b/setup/migration/list.go @@ -41,6 +41,7 @@ var gVersions = []VersionUpdater{ {27, v27}, {28, v28}, {29, v29}, + {30, v30}, } // MaxVersionNumber ... diff --git a/setup/migration/versions.go b/setup/migration/versions.go index 4f3b1fa2..3ec6b906 100644 --- a/setup/migration/versions.go +++ b/setup/migration/versions.go @@ -465,3 +465,10 @@ func v29(tx *sql.Tx) { mustExec(tx, `delete from comments where id=?`, id) } } + +func v30(tx *sql.Tx) { + mustExec(tx, "ALTER TABLE posts ADD COLUMN `date_timezone` TEXT NOT NULL DEFAULT ''") + mustExec(tx, "ALTER TABLE posts ADD COLUMN `modified_timezone` TEXT NOT NULL DEFAULT ''") + mustExec(tx, "ALTER TABLE comments ADD COLUMN `date_timezone` TEXT NOT NULL DEFAULT ''") + mustExec(tx, "ALTER TABLE comments ADD COLUMN `modified_timezone` TEXT NOT NULL DEFAULT ''") +} diff --git a/theme/blog/statics/scripts/comment.js b/theme/blog/statics/scripts/comment.js index e444d77a..07ed046a 100644 --- a/theme/blog/statics/scripts/comment.js +++ b/theme/blog/statics/scripts/comment.js @@ -54,6 +54,50 @@ document.write(function(){/* */}.toString().slice(14,-3)); +class TimeWithZone { + constructor(timestamp, zone) { + const now = new Date(); + if (typeof timestamp != 'number') { + timestamp = now.getTime() / 1000; + zone = TimeWithZone.getTimezone(); + } else if (typeof zone != 'string' || zone == '') { + zone = TimeWithZone.getTimezone(); + } + this._timestamp = timestamp; + this._zone = zone; + } + + get time() { return this._timestamp; } + get zone() { return this._zone; } + + format() { + const options = { + timeZone: this._zone, + timeZoneName: 'longOffset', + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + hourCycle: 'h24', + } + return new Intl.DateTimeFormat(navigator.language, options).format(new Date(this._timestamp)); + } + + toJSON() { + return new Date(this._timestamp).toJSON(); + } + + static getTimezone() { + try { + return Intl.DateTimeFormat().resolvedOptions().timeZone; + } catch { + return ''; + } + } +} + class CommentAPI { constructor(postID) { @@ -90,6 +134,8 @@ class CommentAPI c.date = +(c.date ?? 0); c.modified = +(c.modified ?? 0); c.date_fuzzy = c.date_fuzzy ?? ''; + c.date_timezone = c.date_timezone ?? ''; + c.modified_timezone = c.modified_timezone ?? ''; c.is_admin = c.is_admin ?? false; c.geo_location = c.geo_location ?? ''; @@ -131,7 +177,8 @@ class CommentAPI comment: { source_type: 'markdown', source: source, - modified: modified, + modified: modified.time, + modified_timezone: modified.zone, }, update_mask: 'source,sourceType,modified' }) @@ -681,7 +728,7 @@ class Comment { }; let loggedin = cmt.ip != ''; - let date = new Date(cmt.date * 1000); + let date = new TimeWithZone(cmt.date, cmt.date_timezone); // 登录后可以显示评论者的详细信息 let info = ''; @@ -692,7 +739,7 @@ class Comment { 网址:${cmt.url} 地址:${cmt.ip} 位置:${cmt.geo_location} -日期:${date.toLocaleString()} +日期:${date.format()} `; } @@ -720,7 +767,7 @@ class Comment {
${h2t(cmt.author)} ${urlContent} - +
${cmt.source_type === 'markdown' ? `
${cmt.content}
` @@ -897,7 +944,7 @@ class Comment { let id = this.being_edited; let raw = this.list.comments[id]; - let updated = await this.api.updateComment(id, raw.modified, source); + let updated = await this.api.updateComment(id, new TimeWithZone(raw.modified), source); this.list.update(updated); this.clearContent(); @@ -920,6 +967,9 @@ class Comment { } async createComment() { let body = this.formData(); + + body.date_timezone = TimeWithZone.getTimezone(); + let cmt = await this.api.createComment(body); this.list.insert(cmt); this.toggle_post_comment_button(); diff --git a/theme/data/post.go b/theme/data/post.go index 9c41b11f..de7f91ad 100644 --- a/theme/data/post.go +++ b/theme/data/post.go @@ -13,7 +13,6 @@ import ( "github.com/movsb/taoblog/cmd/config" "github.com/movsb/taoblog/modules/auth" "github.com/movsb/taoblog/protocols/go/proto" - "github.com/xeonx/timeago" ) // PostData ... @@ -105,9 +104,6 @@ func (p *Post) DateString() string { y, m, d := t.Date() return fmt.Sprintf("%d年%02d月%02d日", y, m, d) } -func (p *Post) ShortDateString() string { - return timeago.Chinese.Format(time.Unix(int64(p.Date), 0)) -} func (p *Post) CommentString() string { if p.Comments == 0 { return `没有评论`