frontend, api: allow disabling login methods individually

This commit is contained in:
Adhityaa Chandrasekar 2019-04-19 19:03:34 -04:00
parent 0e54739980
commit a455ff54bc
17 changed files with 258 additions and 56 deletions

View File

@ -167,6 +167,12 @@ func commentListHandler(w http.ResponseWriter, r *http.Request) {
"isFrozen": d.State == "frozen",
"isModerator": isModerator,
"attributes": p,
"configuredOauths": configuredOauths,
"configuredOauths": map[string]bool{
"commento": d.CommentoProvider,
"google": googleConfigured && d.GoogleProvider,
"twitter": twitterConfigured && d.TwitterProvider,
"github": githubConfigured && d.GithubProvider,
"gitlab": gitlabConfigured && d.GitlabProvider,
},
})
}

View File

@ -17,4 +17,9 @@ type domain struct {
ModerateAllAnonymous bool `json:"moderateAllAnonymous"`
Moderators []moderator `json:"moderators"`
EmailNotificationPolicy string `json:"emailNotificationPolicy"`
CommentoProvider bool `json:"commentoProvider"`
GoogleProvider bool `json:"googleProvider"`
TwitterProvider bool `json:"twitterProvider"`
GithubProvider bool `json:"githubProvider"`
GitlabProvider bool `json:"gitlabProvider"`
}

View File

@ -8,7 +8,23 @@ func domainGet(dmn string) (domain, error) {
}
statement := `
SELECT domain, ownerHex, name, creationDate, state, importedComments, autoSpamFilter, requireModeration, requireIdentification, moderateAllAnonymous, emailNotificationPolicy
SELECT
domain,
ownerHex,
name,
creationDate,
state,
importedComments,
autoSpamFilter,
requireModeration,
requireIdentification,
moderateAllAnonymous,
emailNotificationPolicy,
commentoProvider,
googleProvider,
twitterProvider,
githubProvider,
gitlabProvider
FROM domains
WHERE domain = $1;
`
@ -16,7 +32,23 @@ func domainGet(dmn string) (domain, error) {
var err error
d := domain{}
if err = row.Scan(&d.Domain, &d.OwnerHex, &d.Name, &d.CreationDate, &d.State, &d.ImportedComments, &d.AutoSpamFilter, &d.RequireModeration, &d.RequireIdentification, &d.ModerateAllAnonymous, &d.EmailNotificationPolicy); err != nil {
if err = row.Scan(
&d.Domain,
&d.OwnerHex,
&d.Name,
&d.CreationDate,
&d.State,
&d.ImportedComments,
&d.AutoSpamFilter,
&d.RequireModeration,
&d.RequireIdentification,
&d.ModerateAllAnonymous,
&d.EmailNotificationPolicy,
&d.CommentoProvider,
&d.GoogleProvider,
&d.TwitterProvider,
&d.GithubProvider,
&d.GitlabProvider); err != nil {
return d, errorNoSuchDomain
}

View File

@ -10,7 +10,23 @@ func domainList(ownerHex string) ([]domain, error) {
}
statement := `
SELECT domain, ownerHex, name, creationDate, state, importedComments, autoSpamFilter, requireModeration, requireIdentification, moderateAllAnonymous, emailNotificationPolicy
SELECT
domain,
ownerHex,
name,
creationDate,
state,
importedComments,
autoSpamFilter,
requireModeration,
requireIdentification,
moderateAllAnonymous,
emailNotificationPolicy,
commentoProvider,
googleProvider,
twitterProvider,
githubProvider,
gitlabProvider
FROM domains
WHERE ownerHex=$1;
`
@ -24,7 +40,23 @@ func domainList(ownerHex string) ([]domain, error) {
domains := []domain{}
for rows.Next() {
d := domain{}
if err = rows.Scan(&d.Domain, &d.OwnerHex, &d.Name, &d.CreationDate, &d.State, &d.ImportedComments, &d.AutoSpamFilter, &d.RequireModeration, &d.RequireIdentification, &d.ModerateAllAnonymous, &d.EmailNotificationPolicy); err != nil {
if err = rows.Scan(
&d.Domain,
&d.OwnerHex,
&d.Name,
&d.CreationDate,
&d.State,
&d.ImportedComments,
&d.AutoSpamFilter,
&d.RequireModeration,
&d.RequireIdentification,
&d.ModerateAllAnonymous,
&d.EmailNotificationPolicy,
&d.CommentoProvider,
&d.GoogleProvider,
&d.TwitterProvider,
&d.GithubProvider,
&d.GitlabProvider); err != nil {
logger.Errorf("cannot Scan domain: %v", err)
return nil, errorInternal
}
@ -63,5 +95,14 @@ func domainListHandler(w http.ResponseWriter, r *http.Request) {
return
}
bodyMarshal(w, response{"success": true, "domains": domains})
bodyMarshal(w, response{
"success": true,
"domains": domains,
"configuredOauths": map[string]bool{
"google": googleConfigured,
"twitter": twitterConfigured,
"github": githubConfigured,
"gitlab": gitlabConfigured,
},
})
}

View File

@ -7,11 +7,36 @@ import (
func domainUpdate(d domain) error {
statement := `
UPDATE domains
SET name=$2, state=$3, autoSpamFilter=$4, requireModeration=$5, requireIdentification=$6, moderateAllAnonymous=$7, emailNotificationPolicy=$8
SET
name=$2,
state=$3,
autoSpamFilter=$4,
requireModeration=$5,
requireIdentification=$6,
moderateAllAnonymous=$7,
emailNotificationPolicy=$8,
commentoProvider=$9,
googleProvider=$10,
twitterProvider=$11,
githubProvider=$12,
gitlabProvider=$13
WHERE domain=$1;
`
_, err := db.Exec(statement, d.Domain, d.Name, d.State, d.AutoSpamFilter, d.RequireModeration, d.RequireIdentification, d.ModerateAllAnonymous, d.EmailNotificationPolicy)
_, err := db.Exec(statement,
d.Domain,
d.Name,
d.State,
d.AutoSpamFilter,
d.RequireModeration,
d.RequireIdentification,
d.ModerateAllAnonymous,
d.EmailNotificationPolicy,
d.CommentoProvider,
d.GoogleProvider,
d.TwitterProvider,
d.GithubProvider,
d.GitlabProvider)
if err != nil {
logger.Errorf("cannot update non-moderators: %v", err)
return errorInternal

View File

@ -2,11 +2,12 @@ package main
import ()
var configuredOauths []string
var googleConfigured bool
var twitterConfigured bool
var githubConfigured bool
var gitlabConfigured bool
func oauthConfigure() error {
configuredOauths = []string{}
if err := googleOauthConfigure(); err != nil {
return err
}

View File

@ -37,7 +37,7 @@ func githubOauthConfigure() error {
Endpoint: github.Endpoint,
}
configuredOauths = append(configuredOauths, "github")
githubConfigured = true
return nil
}

View File

@ -36,7 +36,7 @@ func gitlabOauthConfigure() error {
Endpoint: gitlab.Endpoint,
}
configuredOauths = append(configuredOauths, "gitlab")
gitlabConfigured = true
return nil
}

View File

@ -37,7 +37,7 @@ func googleOauthConfigure() error {
Endpoint: google.Endpoint,
}
configuredOauths = append(configuredOauths, "google")
googleConfigured = true
return nil
}

View File

@ -43,9 +43,9 @@ func twitterOauthConfigure() error {
},
}
configuredOauths = append(configuredOauths, "twitter")
twitterCredMap = make(map[string]twitterOauthState, 1e3)
twitterConfigured = true
return nil
}

View File

@ -0,0 +1,16 @@
-- Make all login providers optional (but enabled by default)
ALTER TABLE domains
ADD commentoProvider BOOLEAN NOT NULL DEFAULT true;
ALTER TABLE domains
ADD googleProvider BOOLEAN NOT NULL DEFAULT true;
ALTER TABLE domains
ADD twitterProvider BOOLEAN NOT NULL DEFAULT true;
ALTER TABLE domains
ADD githubProvider BOOLEAN NOT NULL DEFAULT true;
ALTER TABLE domains
ADD gitlabProvider BOOLEAN NOT NULL DEFAULT true;

View File

@ -181,14 +181,6 @@
</div>
<div class="row no-border commento-round-check">
<input type="checkbox" v-model="domains[cd].allowAnonymous" id="allow-anonymous">
<label for="allow-anonymous">Allow anonymous comments</label>
<div class="pitch">
Enabling this would allow your readers to comment anonymously. Disabling would require the to authenticate themselves (using their Google account, for example). Recommended.
</div>
</div>
<div class="row no-border commento-round-check indent" v-if="domains[cd].allowAnonymous">
<input type="checkbox" v-model="domains[cd].moderateAllAnonymous" id="moderate-all-anonymous">
<label for="moderate-all-anonymous">Require anonymous comments to be approved manually</label>
<div class="pitch">
@ -228,21 +220,27 @@
<div class="normal-text">
You can enable email notifications to notify your moderators when a new comment is posted or when a comment is pending moderation. Commento tries to be smart about how often an email is sent. Emails will be delayed and batched until you go 10 minutes without one. This requires valid SMTP settings in order to send emails.<br><br>
</div>
<div class="question">
When do you want emails sent to moderators?
</div>
<div class="row no-border commento-round-check indent">
<input type="radio" id="email-all" value="all" v-model="domains[cd].emailNotificationPolicy">
<label for="email-all">Whenever a new comment is created</label>
</div>
<div class="row no-border commento-round-check indent">
<input type="radio" id="email-pending-moderation" value="pending-moderation" v-model="domains[cd].emailNotificationPolicy">
<label for="email-pending-moderation">Only for comments pending moderation</label>
</div>
<div class="row no-border commento-round-check indent">
<input type="radio" id="email-none" value="none" v-model="domains[cd].emailNotificationPolicy">
<label for="email-none">Do not email moderators</label>
<div class="title">
Email Schedule
</div>
<div class="answer">
<div class="row no-border commento-round-check">
<input type="radio" id="email-all" value="all" v-model="domains[cd].emailNotificationPolicy">
<label for="email-all">Whenever a new comment is created</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="email-pending-moderation" value="pending-moderation" v-model="domains[cd].emailNotificationPolicy">
<label for="email-pending-moderation">Only for comments pending moderation</label>
</div>
<div class="row no-border commento-round-check">
<input type="radio" id="email-none" value="none" v-model="domains[cd].emailNotificationPolicy">
<label for="email-none">Do not email moderators</label>
</div>
</div>
</div>
<br>
<div class="center">
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
@ -272,6 +270,48 @@
<input class="input gray-input" id="cur-domain-name" type="text" :placeholder="domains[cd].origName" v-model="domains[cd].name">
</div>
</div>
<div class="question">
<div class="title">
Authentication Options
</div>
<div class="answer">
<div class="row no-border commento-round-check">
<input type="checkbox" v-model="domains[cd].allowAnonymous" id="allow-anonymous">
<label for="allow-anonymous">Anonymous comments</label>
</div>
<div class="row no-border commento-round-check">
<input type="checkbox" v-model="domains[cd].commentoProvider" id="commento-provider">
<label for="commento-provider">Email address login</label>
</div>
<div class="row no-border commento-round-check" v-if="configuredOauths.google">
<input type="checkbox" v-model="domains[cd].googleProvider" id="google-provider">
<label for="google-provider">Google login</label>
</div>
<div class="row no-border commento-round-check" v-if="configuredOauths.twitter">
<input type="checkbox" v-model="domains[cd].twitterProvider" id="twitter-provider">
<label for="twitter-provider">Twitter login</label>
</div>
<div class="row no-border commento-round-check" v-if="configuredOauths.github">
<input type="checkbox" v-model="domains[cd].githubProvider" id="github-provider">
<label for="github-provider">GitHub login</label>
</div>
<div class="row no-border commento-round-check" v-if="configuredOauths.gitlab">
<input type="checkbox" v-model="domains[cd].gitlabProvider" id="gitlab-provider">
<label for="gitlab-provider">GitLab login</label>
</div>
<div class="warning" v-if="!domains[cd].allowAnonymous && !domains[cd].commentoProvider && !domains[cd].googleProvider && !domains[cd].twitterProvider && !domains[cd].githubProvider && !domains[cd].gitlabProvider">
You have disabled all authentication options. Your readers will not be able to login, create comments, or vote.
</div>
</div>
</div>
<div class="center">
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
</div>

View File

@ -73,7 +73,7 @@
var isLocked = false;
var stickyCommentHex = "none";
var shownReply = {};
var configuredOauths = [];
var configuredOauths = {};
var popupBoxType = "login";
var oauthButtonsShown = false;
var selfHex = undefined;
@ -1266,37 +1266,49 @@
attrSet(emailInput, "placeholder", "Email address");
attrSet(emailInput, "type", "text");
for (var i = 0; i < configuredOauths.length; i++) {
var button = create("button");
var numOauthConfigured = 0;
var oauthProviders = ["google", "twitter", "github", "gitlab"];
oauthProviders.forEach(function(provider) {
console.log(provider);
if (configuredOauths[provider]) {
var button = create("button");
classAdd(button, "button");
classAdd(button, configuredOauths[i] + "-button");
classAdd(button, "button");
classAdd(button, provider+ "-button");
button.innerText = configuredOauths[i];
button.innerText = provider;
onclick(button, global.commentoAuth, {"provider": configuredOauths[i], "id": id});
onclick(button, global.commentoAuth, {"provider": provider, "id": id});
append(oauthButtons, button);
}
append(oauthButtons, button);
numOauthConfigured++;
}
});
if (configuredOauths.length > 0) {
if (numOauthConfigured > 0) {
append(loginBox, oauthSubtitle);
append(oauthButtonsContainer, oauthButtons);
append(loginBox, oauthButtonsContainer);
append(loginBox, hr);
oauthButtonsShown = true;
} else {
oauthButtonsShown = false;
}
append(loginBox, emailSubtitle);
append(email, emailInput);
append(email, emailButton);
append(emailContainer, email);
append(loginBox, emailContainer);
append(loginLinkContainer, loginLink);
append(loginBox, loginLinkContainer);
if (numOauthConfigured > 0 && configuredOauths["commento"]) {
append(loginBox, hr);
}
if (configuredOauths["commento"]) {
append(loginBox, emailSubtitle);
append(loginBox, emailContainer);
append(loginBox, loginLinkContainer);
}
append(loginBox, close);

View File

@ -102,6 +102,8 @@
global.vs("domains", resp.domains);
global.vs("configuredOauths", resp.configuredOauths);
if (callback !== undefined) {
callback();
}

View File

@ -31,7 +31,7 @@
{
"id": "general",
"text": "General",
"meaning": "Email settings, data export",
"meaning": "Names, authentication, and export",
"selected": false,
"open": global.generalOpen,
},
@ -72,6 +72,9 @@
// list of domains dynamically loaded; obviously mutable
domains: [{show: false, viewsLast30Days: global.numberify(0), commentsLast30Days: global.numberify(0), moderators: []}],
// configured oauth providers that will be filled in after a backend request
configuredOauths: {},
// whether or not to show the settings column; mutable because we do not
// show the column until a domain has been selected
showSettings: false,

View File

@ -11,7 +11,7 @@
.commento-login-box {
width: 90%;
max-width: 500px;
min-height: 125px;
min-height: 100px;
background: $gray-1;
box-shadow: 0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08);
border: 1px solid transparent;

View File

@ -372,9 +372,28 @@ body {
}
.question {
font-size: 15px;
color: $gray-7;
margin-bottom: 10px;
padding: 8px 0px 8px 0px;
margin: 8px 0px 8px 0px;
display: flex;
width: 100%;
.title {
font-weight: bold;
color: $gray-7;
font-size: 14px;
width: 35%;
padding-top: 12px;
}
.answer {
font-size: 14px;
width: 100%;
}
}
.warning {
color: $orange-8;
font-weight: bold;
}
.float-right {