api, frontend, db: add comment sorting

Closes https://gitlab.com/commento/commento/issues/215
This commit is contained in:
Adhityaa Chandrasekar 2019-12-04 18:50:50 -08:00
parent 3101af8a5c
commit 3e1576d494
9 changed files with 185 additions and 27 deletions

View File

@ -191,6 +191,7 @@ func commentListHandler(w http.ResponseWriter, r *http.Request) {
"requireIdentification": d.RequireIdentification,
"isFrozen": d.State == "frozen",
"isModerator": isModerator,
"defaultSortPolicy": d.DefaultSortPolicy,
"attributes": p,
"configuredOauths": map[string]bool{
"commento": d.CommentoProvider,

View File

@ -25,4 +25,5 @@ type domain struct {
SsoProvider bool `json:"ssoProvider"`
SsoSecret string `json:"ssoSecret"`
SsoUrl string `json:"ssoUrl"`
DefaultSortPolicy string `json:"defaultSortPolicy"`
}

View File

@ -27,7 +27,8 @@ func domainGet(dmn string) (domain, error) {
gitlabProvider,
ssoProvider,
ssoSecret,
ssoUrl
ssoUrl,
defaultSortPolicy
FROM domains
WHERE domain = $1;
`
@ -54,7 +55,8 @@ func domainGet(dmn string) (domain, error) {
&d.GitlabProvider,
&d.SsoProvider,
&d.SsoSecret,
&d.SsoUrl); err != nil {
&d.SsoUrl,
&d.DefaultSortPolicy); err != nil {
return d, errorNoSuchDomain
}

View File

@ -29,7 +29,8 @@ func domainList(ownerHex string) ([]domain, error) {
gitlabProvider,
ssoProvider,
ssoSecret,
ssoUrl
ssoUrl,
defaultSortPolicy
FROM domains
WHERE ownerHex=$1;
`
@ -62,7 +63,8 @@ func domainList(ownerHex string) ([]domain, error) {
&d.GitlabProvider,
&d.SsoProvider,
&d.SsoSecret,
&d.SsoUrl); err != nil {
&d.SsoUrl,
&d.DefaultSortPolicy); err != nil {
logger.Errorf("cannot Scan domain: %v", err)
return nil, errorInternal
}

View File

@ -25,7 +25,8 @@ func domainUpdate(d domain) error {
githubProvider=$12,
gitlabProvider=$13,
ssoProvider=$14,
ssoUrl=$15
ssoUrl=$15,
defaultSortPolicy=$16
WHERE domain=$1;
`
@ -44,7 +45,8 @@ func domainUpdate(d domain) error {
d.GithubProvider,
d.GitlabProvider,
d.SsoProvider,
d.SsoUrl)
d.SsoUrl,
d.DefaultSortPolicy)
if err != nil {
logger.Errorf("cannot update non-moderators: %v", err)
return errorInternal

View File

@ -0,0 +1,10 @@
-- Default sort policy for each domain
CREATE TYPE sortPolicy AS ENUM (
'score-desc',
'creationdate-desc',
'creationdate-asc'
);
ALTER TABLE domains
ADD defaultSortPolicy sortPolicy NOT NULL DEFAULT 'score-desc';

View File

@ -204,6 +204,26 @@
</div>
</div>
<div class="question">
<div class="title">
Comment Sorting
</div>
<div class="answer">
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-score-desc" value="score-desc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-score-desc">Most upvoted first</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-creationdate-desc" value="creationdate-desc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-creationdate-desc">Newest first</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-creationdate-asc" value="creationdate-asc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-creationdate-asc">Oldest first</label>
</div>
</div>
</div>
<div class="center">
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
</div>
@ -320,6 +340,26 @@
</div>
</div>
<div class="question">
<div class="title">
Default Comment Sorting
</div>
<div class="answer">
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-score-desc" value="score-desc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-score-desc">Most upvoted first</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-creationdate-desc" value="creationdate-desc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-creationdate-desc">Newest first</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="defaultSortPolicy-creationdate-asc" value="creationdate-asc" v-model="domains[cd].defaultSortPolicy">
<label for="defaultSortPolicy-creationdate-asc">Oldest first</label>
</div>
</div>
</div>
<div class="center">
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
</div>

View File

@ -34,11 +34,13 @@
var ID_MOD_TOOLS_LOCK_BUTTON = "commento-mod-tools-lock-button";
var ID_ERROR = "commento-error";
var ID_LOGGED_CONTAINER = "commento-logged-container";
var ID_PRE_COMMENTS_AREA = "commento-pre-comments-area";
var ID_COMMENTS_AREA = "commento-comments-area";
var ID_SUPER_CONTAINER = "commento-textarea-super-container-";
var ID_TEXTAREA_CONTAINER = "commento-textarea-container-";
var ID_TEXTAREA = "commento-textarea-";
var ID_ANONYMOUS_CHECKBOX = "commento-anonymous-checkbox-";
var ID_SORT_POLICY = "commento-sort-policy-";
var ID_CARD = "commento-comment-card-";
var ID_BODY = "commento-comment-body-";
var ID_TEXT = "commento-comment-text-";
@ -85,6 +87,7 @@
var configuredOauths = {};
var popupBoxType = "login";
var oauthButtonsShown = false;
var sortPolicy = "score-desc";
var selfHex = undefined;
var mobileView = null;
@ -388,6 +391,8 @@
commenters = Object.assign({}, commenters, resp.commenters)
configuredOauths = resp.configuredOauths;
sortPolicy = resp.defaultSortPolicy;
call(callback);
});
}
@ -564,13 +569,62 @@
}
var sortPolicyNames = {
"score-desc": "Upvotes",
"creationdate-desc": "Newest",
"creationdate-asc": "Oldest",
};
function sortPolicyApply(policy) {
classRemove($(ID_SORT_POLICY + sortPolicy), "sort-policy-button-selected");
var commentsArea = $(ID_COMMENTS_AREA);
commentsArea.innerHTML = "";
sortPolicy = policy;
var cards = commentsRecurse(parentMap(comments), "root");
if (cards) {
append(commentsArea, cards);
}
classAdd($(ID_SORT_POLICY + policy), "sort-policy-button-selected");
}
function sortPolicyBox() {
var sortPolicyButtonsContainer = create("div");
var sortPolicyButtons = create("div");
classAdd(sortPolicyButtonsContainer, "sort-policy-buttons-container");
classAdd(sortPolicyButtons, "sort-policy-buttons");
for (var sp in sortPolicyNames) {
var sortPolicyButton = create("a");
sortPolicyButton.id = ID_SORT_POLICY + sp;
classAdd(sortPolicyButton, "sort-policy-button");
if (sp === sortPolicy) {
classAdd(sortPolicyButton, "sort-policy-button-selected");
}
sortPolicyButton.innerText = sortPolicyNames[sp];
onclick(sortPolicyButton, sortPolicyApply, sp);
append(sortPolicyButtons, sortPolicyButton)
}
append(sortPolicyButtonsContainer, sortPolicyButtons);
return sortPolicyButtonsContainer
}
function rootCreate(callback) {
var login = create("div");
var loginText = create("div");
var mainArea = $(ID_MAIN_AREA);
var preCommentsArea = create("div");
var commentsArea = create("div");
login.id = ID_LOGIN;
preCommentsArea.id = ID_PRE_COMMENTS_AREA;
commentsArea.id = ID_COMMENTS_AREA;
classAdd(login, "login");
@ -601,6 +655,12 @@
append(mainArea, textareaCreate("root"));
}
if (comments.length > 0) {
append(mainArea, sortPolicyBox());
}
append(mainArea, preCommentsArea);
append(mainArea, commentsArea);
append(root, mainArea);
@ -696,7 +756,7 @@
onclick(replyButton, global.replyShow, id)
} else {
textarea.value = "";
insertAfter(textareaSuperContainer, newCard);
insertAfter($(ID_PRE_COMMENTS_AREA), newCard);
}
call(callback);
@ -762,6 +822,27 @@
}
var sortPolicyFunctions = {
"score-desc": function(a, b) {
return b.score - a.score;
},
"creationdate-desc": function(a, b) {
if (a.creationDate < b.creationDate) {
return 1;
} else {
return -1;
}
},
"creationdate-asc": function(a, b) {
if (a.creationDate < b.creationDate) {
return -1;
} else {
return 1;
}
},
};
function commentsRecurse(parentMap, parentHex) {
var cur = parentMap[parentHex];
if (!cur || !cur.length) {
@ -775,15 +856,7 @@
return Infinity;
}
if (a.score !== b.score) {
return b.score - a.score;
}
if (a.creationDate < b.creationDate) {
return -1;
} else {
return 1;
}
return sortPolicyFunctions[sortPolicy](a, b);
});
var curTime = (new Date()).getTime();
@ -1325,28 +1398,31 @@
}
function commentsRender() {
var parentMap = {};
var parentHex;
var commentsArea = $(ID_COMMENTS_AREA);
function parentMap(comments) {
var m = {};
comments.forEach(function(comment) {
parentHex = comment.parentHex;
if (!(parentHex in parentMap)) {
parentMap[parentHex] = [];
var parentHex = comment.parentHex;
if (!(parentHex in m)) {
m[parentHex] = [];
}
comment.creationDate = new Date(comment.creationDate);
parentMap[parentHex].push(comment);
console.log(m, parentHex);
m[parentHex].push(comment);
commentsMap[comment.commentHex] = {
"html": comment.html,
"markdown": comment.markdown,
};
});
var cards = commentsRecurse(parentMap, "root");
return m;
}
function commentsRender() {
var commentsArea = $(ID_COMMENTS_AREA);
var cards = commentsRecurse(parentMap(comments), "root");
if (cards) {
append(commentsArea, cards);
}

View File

@ -57,6 +57,30 @@
font-weight: 700;
margin-top: 16px;
}
.commento-sort-policy-buttons-container {
padding: 12px 0px;
font-weight: 400;
.commento-sort-policy-buttons {
float: right;
.commento-sort-policy-button {
color: $gray-6;
font-size: 13px;
padding: 0px 7px;
}
.commento-sort-policy-button:hover {
cursor: pointer;
}
.commento-sort-policy-button-selected {
color: $blue-8;
font-weight: bold;
}
}
}
}
.commento-root-font {