Skip to content

Commit

Permalink
Merge pull request #20 from CMU-313/verify-message
Browse files Browse the repository at this point in the history
Instructors can verify message
  • Loading branch information
KesterTan authored Sep 25, 2024
2 parents ba5e266 + 8fde2f4 commit 0de0dac
Show file tree
Hide file tree
Showing 18 changed files with 404 additions and 6 deletions.
146 changes: 146 additions & 0 deletions nodebb-theme-slackers/templates/partials/topic/post-menu-list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{{{ if posts.display_moderator_tools }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/edit" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-pencil"></i></span> [[topic:edit]]
</a>
</li>
<li {{{ if posts.deleted }}}hidden{{{ end }}}>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/delete" role="menuitem" href="#" class="{{{ if posts.deleted }}}hidden{{{ end }}}">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-trash-o"></i></span> [[topic:delete]]
</a>
</li>
<li {{{ if !posts.deleted }}}hidden{{{ end }}}>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/restore" role="menuitem" href="#" class="{{{ if !posts.deleted }}}hidden{{{ end }}}">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-history"></i></span> [[topic:restore]]
</a>
</li>
{{{ if posts.display_purge_tools }}}
<li {{{ if !posts.deleted }}}hidden{{{ end }}}>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/purge" role="menuitem" href="#" class="{{{ if !posts.deleted }}}hidden{{{ end }}}">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-eraser"></i></span> [[topic:purge]]
</a>
</li>
{{{ end }}}

{{{ if posts.display_move_tools }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/move" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-arrows"></i></span> [[topic:move]]
</a>
</li>
{{{ end }}}

{{{ if !posts.verify }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/verify" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-check"></i></span> Verify Message
</a>
</li>
{{{ else }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/unverify" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-check"></i></span> Un-Verify Message
</a>
</li>
{{{ end }}}

{{{ if posts.display_change_owner_tools }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/change-owner" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-user"></i></span> [[topic:change-owner]]
</a>
</li>
{{{ end }}}

{{{ if posts.ip }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/copy-ip" role="menuitem" href="#" data-clipboard-text="{posts.ip}">
<span class="menu-icon" ><i class="fa fa-fw text-secondary fa-copy"></i></span> [[topic:copy-ip]] {posts.ip}
</a>
</li>
{{{ if posts.display_ip_ban }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/ban-ip" role="menuitem" href="#" data-ip="{posts.ip}">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-ban"></i></span> [[topic:ban-ip]] {posts.ip}
</a>
</li>
{{{ end }}}
{{{ end }}}
{{{ end }}}

{{{ each posts.tools }}}
<li {{{ if ./disabled }}}class="disabled" {{{ end }}}>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" {{{ if ./action}}}component="{./action}"{{{ end }}} role="menuitem" href="{{{ if ./href }}}{./href}{{{ else }}}#{{{ end }}}">
<span class="menu-icon"><i class="fa fa-fw text-secondary {./icon}"></i></span> {{./html}}
</a>
</li>
{{{ end }}}

{{{ if !posts.deleted }}}
{{{ if posts.display_history}}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/view-history" role="menuitem" href="#">
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-history"></i></span> [[topic:view-history]]
</a>
</li>
{{{ end }}}

{{{ if config.loggedIn }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/bookmark" role="menuitem" href="#" data-bookmarked="{posts.bookmarked}">
<span class="menu-icon">
<i component="post/bookmark/on" class="fa fa-fw text-secondary fa-bookmark {{{ if !posts.bookmarked }}}hidden{{{ end }}}"></i>
<i component="post/bookmark/off" class="fa fa-fw text-secondary fa-bookmark-o {{{ if posts.bookmarked }}}hidden{{{ end }}}"></i>
</span>
<span class="bookmark-text">[[topic:bookmark]]</span>
<span component="post/bookmark-count" class="bookmarkCount badge bg-secondary" data-bookmarks="{posts.bookmarks}">{posts.bookmarks}</span>&nbsp;
</a>
</li>
{{{ end }}}

<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" role="menuitem" href="#" data-clipboard-text="{posts.absolute_url}">
<i class="fa fa-fw text-secondary fa-link"></i> [[topic:copy-permalink]]
</a>
</li>

{{{ if postSharing.length }}}
{{{ if config.loggedIn }}}<li class="dropdown-divider"></li>{{{ end }}}
<li class="dropdown-header">[[topic:share-this-post]]</li>
{{{ end }}}
<li class="d-flex gap-2 px-3">
{{{ each postSharing }}}
<a class="dropdown-item rounded-1 d-flex align-items-center px-1 py-2 w-auto" role="menuitem" component="share/{./id}" href="#" title="{./name}"><i class="fa-fw text-secondary {./class}"></i></a>
{{{ end }}}
</li>
{{{ end }}}

{{{ if posts.display_flag_tools }}}
<li class="dropdown-divider"></li>

<li {{{ if posts.flags.flagged }}}hidden{{{ end }}}>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/flag" role="menuitem" href="#"><i class="fa fa-fw text-secondary fa-flag"></i> [[topic:flag-post]]</a>
</li>
<li {{{ if !posts.flags.flagged }}}hidden{{{ end }}} class="disabled text-secondary">
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/already-flagged" role="menuitem" href="#"><i class="fa fa-fw text-secondary fa-flag"></i> [[topic:already-flagged]]</a>
</li>

{{{ if (!posts.selfPost && posts.uid) }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/flagUser" role="menuitem" href="#"><i class="fa fa-fw text-secondary fa-flag"></i> [[topic:flag-user]]</a>
</li>
{{{ end }}}
{{{ end }}}

{{{ if posts.display_moderator_tools }}}
{{{ if posts.flags.exists }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" role="menuitem" href="{config.relative_path}/flags/{posts.flags.flagId}"><i class="fa fa-fw text-secondary fa-exclamation-circle"></i> [[topic:view-flag-report]]</a>
</li>
{{{ if (posts.flags.state == "open") }}}
<li>
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/flagResolve" data-flagId="{posts.flags.flagId}" role="menuitem" href="#"><i class="fa fa-fw text-secondary fa-check"></i> [[topic:resolve-flag]]</a>
</li>
{{{ end }}}
{{{ end }}}
{{{ end }}}
130 changes: 130 additions & 0 deletions nodebb-theme-slackers/templates/partials/topic/post.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{{{ if (!./index && widgets.mainpost-header.length) }}}
<div data-widget-area="mainpost-header">
{{{ each widgets.mainpost-header }}}
{widgets.mainpost-header.html}
{{{ end }}}
</div>
{{{ end }}}
<div class="d-flex align-items-start gap-3">
<div class="bg-body d-none d-sm-block rounded-circle" style="outline: 2px solid var(--bs-body-bg);">
<a class="d-inline-block position-relative text-decoration-none" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" aria-label="[[aria:user-avatar-for, {./user.username}]]">
{buildAvatar(posts.user, "48px", true, "", "user/picture")}
<span component="user/status" class="position-absolute translate-middle-y border border-white border-2 rounded-circle status {posts.user.status}"><span class="visually-hidden">[[global:{posts.user.status}]]</span></span>
</a>
</div>
<div class="post-container d-flex flex-grow-1 flex-column w-100" style="min-width:0;">
<div class="d-flex align-items-center gap-1 flex-wrap w-100 post-header mt-1" itemprop="author" itemscope itemtype="https://schema.org/Person">
<meta itemprop="name" content="{./user.username}">
{{{ if ./user.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{./user.userslug}">{{{ end }}}

<div class="bg-body d-sm-none">
<a class="d-inline-block position-relative text-decoration-none" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">
{buildAvatar(posts.user, "20px", true, "", "user/picture")}
<span component="user/status" class="position-absolute translate-middle-y border border-white border-2 rounded-circle status {posts.user.status}"><span class="visually-hidden">[[global:{posts.user.status}]]</span></span>
</a>
</div>

<a class="fw-bold text-nowrap" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" data-username="{posts.user.username}" data-uid="{posts.user.uid}">{posts.user.displayname}</a>

{{{ each posts.user.selectedGroups }}}
{{{ if posts.user.selectedGroups.slug }}}
<!-- IMPORT partials/groups/badge.tpl -->
{{{ end }}}
{{{ end }}}

{{{ if posts.user.banned }}}
<span class="badge bg-danger rounded-1">[[user:banned]]</span>
{{{ end }}}

<div class="d-flex gap-1 align-items-center">
<span class="text-muted">{generateWroteReplied(@value, config.timeagoCutoff)}</span>

<i component="post/edit-indicator" class="fa fa-edit text-muted{{{ if privileges.posts:history }}} pointer{{{ end }}} edit-icon {{{ if !posts.editor.username }}}hidden{{{ end }}}" title="[[global:edited-timestamp, {isoTimeToLocaleString(./editedISO, config.userLang)}]]"></i>
<span data-editor="{posts.editor.userslug}" component="post/editor" class="visually-hidden">[[global:last-edited-by, {posts.editor.username}]] <span class="timeago" title="{isoTimeToLocaleString(posts.editedISO, config.userLang)}"></span></span>
</div>

{{{ if posts.user.custom_profile_info.length }}}
<div>
<span>
&#124;
{{{ each posts.user.custom_profile_info }}}
{posts.user.custom_profile_info.content}
{{{ end }}}
</span>
</div>
{{{ end }}}
<div class="d-flex align-items-center gap-1 flex-grow-1 justify-content-end">
{{{ if posts.verify }}}
<span class="menu-icon"><i class="fa fa-fw text-secondary fa-check"></i></span>
{{{ end }}}
<span class="bookmarked opacity-0 text-primary"><i class="fa fa-bookmark-o"></i></span>
<a href="{config.relative_path}/post/{./pid}" class="post-index text-muted d-none d-md-inline">#{increment(./index, "1")}</a>
</div>
</div>

<div class="content mt-2 text-break" component="post/content" itemprop="text">
{posts.content}
</div>
</div>
</div>

<div component="post/footer" class="post-footer border-bottom pb-2">
{{{ if posts.user.signature }}}
<div component="post/signature" data-uid="{posts.user.uid}" class="text-xs text-muted mt-2">{posts.user.signature}</div>
{{{ end }}}

<div class="d-flex">
{{{ if !hideReplies }}}
<a component="post/reply-count" data-target-component="post/replies/container" href="#" class="d-flex gap-2 align-items-center mt-2 btn-ghost ff-secondary border rounded-1 p-1 text-muted text-decoration-none text-xs {{{ if (!./replies || shouldHideReplyContainer(@value)) }}}hidden{{{ end }}}">
<span component="post/reply-count/avatars" class="d-flex gap-1 {{{ if posts.replies.hasMore }}}hasMore{{{ end }}}">
{{{each posts.replies.users}}}
<span>{buildAvatar(posts.replies.users, "20px", true, "avatar-tooltip")}</span>
{{{end}}}
{{{ if posts.replies.hasMore}}}
<span><i class="fa fa-ellipsis"></i></span>
{{{ end }}}
</span>

<span class="ms-2 replies-count fw-semibold" component="post/reply-count/text" data-replies="{posts.replies.count}">{posts.replies.text}</span>
<span class="ms-2 replies-last hidden-xs fw-semibold">[[topic:last-reply-time]] <span class="timeago" title="{posts.replies.timestampISO}"></span></span>

<i class="fa fa-fw fa-chevron-down" component="post/replies/open"></i>
</a>
{{{ end }}}
</div>

<div component="post/replies/container" class="my-2 col-11 border rounded-1 p-3 hidden-empty"></div>

<div component="post/actions" class="d-flex justify-content-end gap-1 post-tools">
<!-- IMPORT partials/topic/reactions.tpl -->
<a component="post/reply" href="#" class="btn-ghost-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:reply]]"><i class="fa fa-fw fa-reply text-primary"></i></a>
<a component="post/quote" href="#" class="btn-ghost-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:quote]]"><i class="fa fa-fw fa-quote-right text-primary"></i></a>

{{{ if !reputation:disabled }}}
<div class="d-flex votes align-items-center">
<a component="post/upvote" href="#" class="btn-ghost-sm{{{ if posts.upvoted }}} upvoted{{{ end }}}" title="[[topic:upvote-post]]">
<i class="fa fa-fw fa-chevron-up text-primary"></i>
</a>

<meta itemprop="upvoteCount" content="{posts.upvotes}">
<meta itemprop="downvoteCount" content="{posts.downvotes}">
<a href="#" class="px-2 mx-1 btn-ghost-sm" component="post/vote-count" data-votes="{posts.votes}" title="[[global:voters]]">{posts.votes}</a>

{{{ if !downvote:disabled }}}
<a component="post/downvote" href="#" class="btn-ghost-sm{{{ if posts.downvoted }}} downvoted{{{ end }}}" title="[[topic:downvote-post]]">
<i class="fa fa-fw fa-chevron-down text-primary"></i>
</a>
{{{ end }}}
</div>
{{{ end }}}

<!-- IMPORT partials/topic/post-menu.tpl -->
</div>
</div>
{{{ if (!./index && widgets.mainpost-footer.length) }}}
<div data-widget-area="mainpost-footer">
{{{ each widgets.mainpost-footer }}}
{widgets.mainpost-footer.html}
{{{ end }}}
</div>
{{{ end }}}
4 changes: 3 additions & 1 deletion public/openapi/components/schemas/PostObject.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ PostObject:
type: number
deleted:
type: boolean
verify:
type: number
answered:
type: number
upvotes:
Expand Down Expand Up @@ -141,4 +143,4 @@ PostObject:
isMainPost:
type: boolean
replies:
type: number
type: number
6 changes: 5 additions & 1 deletion public/openapi/read/topic/topic_id.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ get:
type: number
deleted:
type: number
verify:
type: number
verifyUid:
type: number
answered:
type: number
upvotes:
Expand Down Expand Up @@ -447,4 +451,4 @@ get:
- tid
- $ref: ../../components/schemas/Pagination.yaml#/Pagination
- $ref: ../../components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: ../../components/schemas/CommonProps.yaml#/CommonProps
- $ref: ../../components/schemas/CommonProps.yaml#/CommonProps
4 changes: 3 additions & 1 deletion public/openapi/write.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ paths:
$ref: 'write/posts/pid/upvoters.yaml'
/posts/{pid}/bookmark:
$ref: 'write/posts/pid/bookmark.yaml'
/posts/{pid}/verify:
$ref: 'write/posts/pid/verify.yaml'
/posts/{pid}/diffs:
$ref: 'write/posts/pid/diffs.yaml'
/posts/{pid}/diffs/{since}:
Expand Down Expand Up @@ -261,4 +263,4 @@ paths:
/files/:
$ref: 'write/files.yaml'
/files/folder:
$ref: 'write/files/folder.yaml'
$ref: 'write/files/folder.yaml'
6 changes: 5 additions & 1 deletion public/openapi/write/posts/pid.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ get:
type: number
deleted:
type: number
verify:
type: number
verifyUid:
type: number
answered:
type: number
upvotes:
Expand Down Expand Up @@ -142,4 +146,4 @@ delete:
$ref: ../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}
properties: {}
2 changes: 2 additions & 0 deletions public/openapi/write/posts/pid/replies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ get:
type: number
deleted:
type: number
verify:
type: number
answered:
type: number
upvotes:
Expand Down
26 changes: 26 additions & 0 deletions public/openapi/write/posts/pid/verify.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
put:
tags:
- posts
summary: verifies a post
description: This operation verifies a post.
parameters:
- in: path
name: pid
schema:
type: string
required: true
description: a valid post id
example: 2
responses:
'200':
description: Post successfully verified
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}
Loading

0 comments on commit 0de0dac

Please sign in to comment.