api, frontend: allow editing profile information

Closes https://gitlab.com/commento/commento/issues/235
This commit is contained in:
Adhityaa Chandrasekar 2019-12-04 21:57:10 -08:00
parent 3e1576d494
commit 918a691ba3
10 changed files with 239 additions and 22 deletions

View File

@ -1,6 +1,8 @@
package main
import ()
import (
"net/http"
)
func commenterUpdate(commenterHex string, email string, name string, link string, photo string, provider string) error {
if email == "" || name == "" || link == "" || photo == "" || provider == "" {
@ -27,3 +29,38 @@ func commenterUpdate(commenterHex string, email string, name string, link string
return nil
}
func commenterUpdateHandler(w http.ResponseWriter, r *http.Request) {
type request struct {
CommenterToken *string `json:"commenterToken"`
Name *string `json:"name"`
Email *string `json:"email"`
Link *string `json:"link"`
Photo *string `json:"photo"`
}
var x request
if err := bodyUnmarshal(r, &x); err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
c, err := commenterGetByCommenterToken(*x.CommenterToken)
if err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
if c.Provider == "commento" {
*x.Link = c.Link
*x.Photo = c.Photo
}
*x.Email = c.Email
if err = commenterUpdate(c.CommenterHex, *x.Email, *x.Name, *x.Link, *x.Photo, c.Provider); err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
bodyMarshal(w, response{"success": true})
}

View File

@ -27,6 +27,7 @@ func apiRouterInit(router *mux.Router) error {
router.HandleFunc("/api/commenter/new", commenterNewHandler).Methods("POST")
router.HandleFunc("/api/commenter/login", commenterLoginHandler).Methods("POST")
router.HandleFunc("/api/commenter/self", commenterSelfHandler).Methods("POST")
router.HandleFunc("/api/commenter/update", commenterUpdateHandler).Methods("POST")
router.HandleFunc("/api/commenter/photo", commenterPhotoHandler).Methods("GET")
router.HandleFunc("/api/forgot", forgotHandler).Methods("POST")

View File

@ -102,6 +102,7 @@ func staticRouterInit(router *mux.Router) error {
"/unsubscribe",
"/dashboard",
"/logout",
"/profile",
}
for _, page := range pages {

View File

@ -83,6 +83,12 @@ const jsCompileMap = {
"js/http.js",
"js/unsubscribe.js",
],
"js/profile.js": [
"js/constants.js",
"js/utils.js",
"js/http.js",
"js/profile.js",
],
};
gulp.task("scss-devel", function (done) {

View File

@ -246,7 +246,18 @@
refreshAll();
}
function selfLoad(commenter) {
function profileEdit() {
window.open(origin + "/profile?commenterToken=" + commenterTokenGet(), "_blank");
}
function notificationSettings(unsubscribeSecretHex) {
window.open(origin + "/unsubscribe?unsubscribeSecretHex=" + unsubscribeSecretHex, "_blank");
}
function selfLoad(commenter, email) {
commenters[commenter.commenterHex] = commenter;
selfHex = commenter.commenterHex;
@ -259,7 +270,9 @@
name = create("div");
}
var avatar;
var logout = create("div");
var notificationSettingsButton = create("div");
var profileEditButton = create("div");
var logoutButton = create("div");
var color = colorGet(commenter.commenterHex + "-" + commenter.name);
loggedContainer.id = ID_LOGGED_CONTAINER;
@ -267,12 +280,19 @@
classAdd(loggedContainer, "logged-container");
classAdd(loggedInAs, "logged-in-as");
classAdd(name, "name");
classAdd(logout, "logout");
classAdd(notificationSettingsButton, "profile-button");
classAdd(profileEditButton, "profile-button");
classAdd(logoutButton, "profile-button");
name.innerText = commenter.name;
logout.innerText = "Logout";
notificationSettingsButton.innerText = "Notification Settings";
profileEditButton.innerText = "Edit Profile";
logoutButton.innerText = "Logout";
onclick(logout, global.logout);
onclick(logoutButton, global.logout);
console.log(commenter);
onclick(notificationSettingsButton, notificationSettings, email.unsubscribeSecretHex);
onclick(profileEditButton, profileEdit);
attrSet(loggedContainer, "style", "display: none");
if (commenter.link !== "undefined") {
@ -292,7 +312,9 @@
append(loggedInAs, avatar);
append(loggedInAs, name);
append(loggedContainer, loggedInAs);
append(loggedContainer, logout);
append(loggedContainer, logoutButton);
append(loggedContainer, profileEditButton);
append(loggedContainer, notificationSettingsButton);
prepend(root, loggedContainer);
isAuthenticated = true;
@ -318,7 +340,7 @@
return;
}
selfLoad(resp.commenter);
selfLoad(resp.commenter, resp.email);
global.allShow();
call(callback);
@ -1087,7 +1109,6 @@
append(card, header);
append(card, contents);
console.log(children);
if (comment.deleted && (hideDeleted === "true" || children === null)) {
return;
}
@ -1408,7 +1429,6 @@
comment.creationDate = new Date(comment.creationDate);
console.log(m, parentHex);
m[parentHex].push(comment);
commentsMap[comment.commentHex] = {
"html": comment.html,
@ -1730,7 +1750,7 @@
cookieSet("commentoCommenterToken", resp.commenterToken);
selfLoad(resp.commenter);
selfLoad(resp.commenter, resp.email);
global.allShow();
remove($(ID_LOGIN));

76
frontend/js/profile.js Normal file
View File

@ -0,0 +1,76 @@
(function (global, document) {
"use strict";
(document);
// Update the email records.
global.update = function(event) {
event.preventDefault();
$(".err").text("");
$(".msg").text("");
var allOk = global.unfilledMark(["#name", "#email"], function(el) {
el.css("border-bottom", "1px solid red");
});
if (!allOk) {
global.textSet("#err", "Please make sure all fields are filled");
return;
}
var json = {
"commenterToken": global.paramGet("commenterToken"),
"name": $("#name").val(),
"email": $("#email").val(),
"link": $("#link").val(),
"photo": $("#photo").val(),
};
global.buttonDisable("#save-button");
global.post(global.origin + "/api/commenter/update", json, function(resp) {
global.buttonEnable("#save-button");
if (!resp.success) {
$(".err").text(resp.message);
return;
}
$(".msg").text("Successfully updated!");
});
}
global.profilePrefill = function() {
$(".err").text("");
$(".msg").text("");
var json = {
"commenterToken": global.paramGet("commenterToken"),
};
global.post(global.origin + "/api/commenter/self", json, function(resp) {
$("#loading").hide();
$("#form").show();
if (!resp.success) {
$(".err").text(resp.message);
return;
}
$("#name").val(resp.commenter.name);
$("#email").val(resp.commenter.email);
$("#unsubscribe").attr("href", global.origin + "/unsubscribe?unsubscribeSecretHex=" + resp.email.unsubscribeSecretHex);
if (resp.commenter.provider === "commento") {
$("#link-row").attr("style", "")
if (resp.commenter.link !== "undefined") {
$("#link").val(resp.commenter.link);
}
$("#photo-row").attr("style", "")
$("#photo-subtitle").attr("style", "")
if (resp.commenter.photo !== "undefined") {
$("#photo").val(resp.commenter.photo);
}
}
});
};
} (window.commento, document));

66
frontend/profile.html Normal file
View File

@ -0,0 +1,66 @@
<html>
<head>
<meta name="viewport" content="user-scalable=no, initial-scale=1.0">
<script src="[[[.CdnPrefix]]]/js/jquery.js"></script>
<script src="[[[.CdnPrefix]]]/js/profile.js"></script>
<link rel="icon" href="[[[.CdnPrefix]]]/images/120x120.png">
<link rel="stylesheet" href="[[[.CdnPrefix]]]/css/auth.css">
<title>Commento: Edit Profile</title>
</head>
<div class="navbar">
<a href="[[[.Origin]]]/" class="navbar-item navbar-logo-text"><img src="[[[.CdnPrefix]]]/images/logo.svg" class="navbar-logo">Commento</a>
</div>
<script>
window.onload = function() {
window.commento.profilePrefill();
};
</script>
<div class="auth-form-container">
<div class="auth-form">
<div id="loading">
Loading...
</div>
<form onsubmit="window.commento.update(event)" id="form" style="display: none">
<div class="form-title">
Edit Profile
</div>
<div class="row">
<div class="label">Name</div>
<input class="input" type="text" name="name" id="name" placeholder="Name">
</div>
<div class="row no-margin-bottom-row">
<div class="label">Email Address</div>
<input class="input" type="text" name="email" id="email" placeholder="example@example.com" disabled>
</div>
<div class="small-subtitle">
Since your identity is directly tied to your email address, changing your email address is not possible. <a href="" id="unsubscribe">Want to change your notification settings?</a>
</div>
<div id="link-row" class="row" style="display: none">
<div class="label">Website</div>
<input class="input" type="text" name="link" id="link" placeholder="https://example.com">
</div>
<div id="photo-row" class="row no-margin-bottom-row" style="display: none">
<div class="label">Photo</div>
<input class="input" type="text" name="photo" id="photo" placeholder="https://i.imgur.com/BCKlYFQ.jpg">
</div>
<div class="small-subtitle" style="display: none" id="photo-subtitle">
Use an external image hosting service such as <a href="https://imgur.com" rel="nofollow">Imgur</a> and enter the direct link to the image here. Changes to your profile photo may take a few hours to reflect.
</div>
<div class="err" id="err"></div>
<div class="msg" id="msg"></div>
<button id="button" class="button" type="submit">Update Profile</button>
</form>
</div>
</div>
[[[.Footer]]]
</html>

View File

@ -36,6 +36,12 @@ body {
padding-bottom: 24px;
}
.small-subtitle {
font-size: 12px;
color: $gray-6;
padding: 0px 12px 20px 12px;
}
.row {
padding-left: 8px;
padding-right: 8px;
@ -74,6 +80,10 @@ body {
}
}
.no-margin-bottom-row {
margin-bottom: 6px;
}
.button {
@extend .shadow;
border: 1px solid $blue-6;

View File

@ -21,12 +21,12 @@
position: relative;
height: 38px;
.commento-logout {
.commento-profile-button {
float: right;
cursor: pointer;
position: absolute;
top: 6px;
right: 16px;
color: $gray-5;
color: $gray-6;
margin: 6px 12px;
font-size: 13px;
}
.commento-logged-in-as {

View File

@ -5,7 +5,7 @@
<script src="[[[.CdnPrefix]]]/js/unsubscribe.js"></script>
<link rel="icon" href="[[[.CdnPrefix]]]/images/120x120.png">
<link rel="stylesheet" href="[[[.CdnPrefix]]]/css/unsubscribe.css">
<title>Commento: Unsubscribe</title>
<title>Commento: Email Notification Settings</title>
</head>
<div class="navbar">