frontend, api: allow custom emails as commenters
I'm really sorry this came out as one huge commit, but I'm afraid I can't split this up. Closes https://gitlab.com/commento/commento-ce/issues/9
This commit is contained in:
		@@ -8,7 +8,7 @@ import (
 | 
			
		||||
func TestCommentApproveBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	commentHex, _ := commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -151,5 +151,6 @@ func commentListHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		"requireIdentification": d.RequireIdentification,
 | 
			
		||||
		"isFrozen":              d.State == "frozen",
 | 
			
		||||
		"isModerator":           isModerator,
 | 
			
		||||
		"configuredOauths":      configuredOauths,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import (
 | 
			
		||||
func TestCommentListBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
 | 
			
		||||
	commentNew(commenterHex, "example.com", "/path.html", "root", "**bar**", "approved", time.Now().UTC())
 | 
			
		||||
@@ -65,7 +65,7 @@ func TestCommentListEmpty(t *testing.T) {
 | 
			
		||||
func TestCommentListSelfUnapproved(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "http://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "unapproved", time.Now().UTC())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -116,5 +116,5 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writeBody(w, response{"success": true, "commentHex": commentHex})
 | 
			
		||||
	writeBody(w, response{"success": true, "commentHex": commentHex, "approved": state == "approved"})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,9 @@ import (
 | 
			
		||||
func TestCommentVoteBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	cr0, _ := commenterNew("test1@example.com", "Test1", "undefined", "http://example.com/photo.jpg", "google")
 | 
			
		||||
	cr1, _ := commenterNew("test2@example.com", "Test2", "undefined", "http://example.com/photo.jpg", "google")
 | 
			
		||||
	cr2, _ := commenterNew("test3@example.com", "Test3", "undefined", "http://example.com/photo.jpg", "google")
 | 
			
		||||
	cr0, _ := commenterNew("test1@example.com", "Test1", "undefined", "http://example.com/photo.jpg", "google", "")
 | 
			
		||||
	cr1, _ := commenterNew("test2@example.com", "Test2", "undefined", "http://example.com/photo.jpg", "google", "")
 | 
			
		||||
	cr2, _ := commenterNew("test3@example.com", "Test3", "undefined", "http://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	c0, _ := commentNew(cr0, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import (
 | 
			
		||||
func TestCommenterGetByHexBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	c, err := commenterGetByHex(commenterHex)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -33,7 +33,7 @@ func TestCommenterGetByHexEmpty(t *testing.T) {
 | 
			
		||||
func TestCommenterGetBySession(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	session, _ := commenterSessionNew()
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +63,7 @@ func TestCommenterGetBySessionEmpty(t *testing.T) {
 | 
			
		||||
func TestCommenterGetByName(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	session, _ := commenterSessionNew()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								api/commenter_login.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								api/commenter_login.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func commenterLogin(email string, password string) (string, error) {
 | 
			
		||||
	if email == "" || password == "" {
 | 
			
		||||
		return "", errorMissingField
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	statement := `
 | 
			
		||||
		SELECT commenterHex, passwordHash
 | 
			
		||||
		FROM commenters
 | 
			
		||||
		WHERE email = $1 AND provider = 'commento';
 | 
			
		||||
	`
 | 
			
		||||
	row := db.QueryRow(statement, email)
 | 
			
		||||
 | 
			
		||||
	var commenterHex string
 | 
			
		||||
	var passwordHash string
 | 
			
		||||
	if err := row.Scan(&commenterHex, &passwordHash); err != nil {
 | 
			
		||||
		return "", errorInvalidEmailPassword
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(password)); err != nil {
 | 
			
		||||
		// TODO: is this the only possible error?
 | 
			
		||||
		return "", errorInvalidEmailPassword
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session, err := randomHex(32)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorf("cannot create session hex: %v", err)
 | 
			
		||||
		return "", errorInternal
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	statement = `
 | 
			
		||||
		INSERT INTO
 | 
			
		||||
		commenterSessions (session, commenterHex, creationDate)
 | 
			
		||||
		VALUES            ($1,      $2,           $3          );
 | 
			
		||||
	`
 | 
			
		||||
	_, err = db.Exec(statement, session, commenterHex, time.Now().UTC())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorf("cannot insert session token: %v\n", err)
 | 
			
		||||
		return "", errorInternal
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func commenterLoginHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	type request struct {
 | 
			
		||||
		Email    *string `json:"email"`
 | 
			
		||||
		Password *string `json:"password"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var x request
 | 
			
		||||
	if err := unmarshalBody(r, &x); err != nil {
 | 
			
		||||
		writeBody(w, response{"success": false, "message": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session, err := commenterLogin(*x.Email, *x.Password)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		writeBody(w, response{"success": false, "message": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writeBody(w, response{"success": true, "session": session})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								api/commenter_login_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								api/commenter_login_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestCommenterLoginBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", "hunter2"); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found when logging in without creating an account")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commenterNew("test@example.com", "Test", "undefined", "undefined", "commento", "hunter2")
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", "hunter2"); err != nil {
 | 
			
		||||
		t.Errorf("unexpected error when logging in: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", "h******"); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found when given wrong password")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session, err := commenterLogin("test@example.com", "hunter2"); session == "" {
 | 
			
		||||
		t.Errorf("empty session on successful login: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCommenterLoginEmpty(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", ""); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found when passing empty password")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commenterNew("test@example.com", "Test", "undefined", "", "commenter", "hunter2")
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", ""); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found when passing empty password")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCommenterLoginNonCommento(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterNew("test@example.com", "Test", "undefined", "undefined", "google", "")
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterLogin("test@example.com", "hunter2"); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found logging into a non-Commento account")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +1,74 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func commenterNew(email string, name string, link string, photo string, provider string) (string, error) {
 | 
			
		||||
func commenterNew(email string, name string, link string, photo string, provider string, password string) (string, error) {
 | 
			
		||||
	if email == "" || name == "" || link == "" || photo == "" || provider == "" {
 | 
			
		||||
		return "", errorMissingField
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if provider == "commento" && password == "" {
 | 
			
		||||
		return "", errorMissingField
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterGetByEmail(provider, email); err == nil {
 | 
			
		||||
		return "", errorEmailAlreadyExists
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commenterHex, err := randomHex(32)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", errorInternal
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	passwordHash := []byte{}
 | 
			
		||||
	if (password != "") {
 | 
			
		||||
		passwordHash, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logger.Errorf("cannot generate hash from password: %v\n", err)
 | 
			
		||||
			return "", errorInternal
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	statement := `
 | 
			
		||||
		INSERT INTO
 | 
			
		||||
		commenters (commenterHex, email, name, link, photo, provider, joinDate)
 | 
			
		||||
		VALUES     ($1,           $2,    $3,   $4,   $5,    $6,       $7      );
 | 
			
		||||
		commenters (commenterHex, email, name, link, photo, provider, passwordHash, joinDate)
 | 
			
		||||
		VALUES     ($1,           $2,    $3,   $4,   $5,    $6,       $7,           $8      );
 | 
			
		||||
	`
 | 
			
		||||
	_, err = db.Exec(statement, commenterHex, email, name, link, photo, provider, time.Now().UTC())
 | 
			
		||||
	_, err = db.Exec(statement, commenterHex, email, name, link, photo, provider, string(passwordHash), time.Now().UTC())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorf("cannot insert commenter: %v", err)
 | 
			
		||||
		return "", errorInternal
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return commenterHex, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func commenterNewHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	type request struct {
 | 
			
		||||
		Email    *string `json:"email"`
 | 
			
		||||
		Name     *string `json:"name"`
 | 
			
		||||
		Website  *string `json:"website"`
 | 
			
		||||
		Password *string `json:"password"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var x request
 | 
			
		||||
	if err := unmarshalBody(r, &x); err != nil {
 | 
			
		||||
		writeBody(w, response{"success": false, "message": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: add gravatar?
 | 
			
		||||
	// TODO: email confirmation if provider = commento?
 | 
			
		||||
	// TODO: email confirmation if provider = commento?
 | 
			
		||||
	if _, err := commenterNew(*x.Email, *x.Name, *x.Website, "undefined", "commento", *x.Password); err != nil {
 | 
			
		||||
		writeBody(w, response{"success": false, "message": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writeBody(w, response{"success": true, "confirmEmail": smtpConfigured})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import (
 | 
			
		||||
func TestCommenterNewBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google"); err != nil {
 | 
			
		||||
	if _, err := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", ""); err != nil {
 | 
			
		||||
		t.Errorf("unexpected error creating new commenter: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -16,13 +16,22 @@ func TestCommenterNewBasics(t *testing.T) {
 | 
			
		||||
func TestCommenterNewEmpty(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterNew("", "Test", "undefined", "https://example.com/photo.jpg", "google"); err == nil {
 | 
			
		||||
	if _, err := commenterNew("", "Test", "undefined", "https://example.com/photo.jpg", "google", ""); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found creating new commenter with empty email")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterNew("", "", "", "", ""); err == nil {
 | 
			
		||||
	if _, err := commenterNew("", "", "", "", "", ""); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found creating new commenter with empty everything")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCommenterNewCommento(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	if _, err := commenterNew("test@example.com", "Test", "undefined", "", "commento", ""); err == nil {
 | 
			
		||||
		t.Errorf("expected error not found creating new commento account with empty password")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import (
 | 
			
		||||
func TestCommenterSessionGetBasics(t *testing.T) {
 | 
			
		||||
	failTestOnError(t, setupTestEnv())
 | 
			
		||||
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google")
 | 
			
		||||
	commenterHex, _ := commenterNew("test@example.com", "Test", "undefined", "https://example.com/photo.jpg", "google", "")
 | 
			
		||||
 | 
			
		||||
	session, _ := commenterSessionNew()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,8 @@ func parseConfig() error {
 | 
			
		||||
		"SMTP_PORT":         "",
 | 
			
		||||
		"SMTP_FROM_ADDRESS": "",
 | 
			
		||||
 | 
			
		||||
		"OAUTH_GOOGLE_KEY":    "",
 | 
			
		||||
		"OAUTH_GOOGLE_SECRET": "",
 | 
			
		||||
		"GOOGLE_KEY":        "",
 | 
			
		||||
		"GOOGLE_SECRET":     "",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for key, value := range defaults {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,11 @@ package main
 | 
			
		||||
 | 
			
		||||
import ()
 | 
			
		||||
 | 
			
		||||
var configuredOauths []string
 | 
			
		||||
 | 
			
		||||
func oauthConfigure() error {
 | 
			
		||||
	configuredOauths = []string{}
 | 
			
		||||
 | 
			
		||||
	if err := googleOauthConfigure(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,5 +37,7 @@ func googleOauthConfigure() error {
 | 
			
		||||
		Endpoint: google.Endpoint,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	configuredOauths = append(configuredOauths, "google");
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ func googleCallbackHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			link = "undefined"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		commenterHex, err = commenterNew(email, user["name"].(string), link, user["picture"].(string), "google")
 | 
			
		||||
		commenterHex, err = commenterNew(email, user["name"].(string), link, user["picture"].(string), "google", "")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "Error: %s", err.Error())
 | 
			
		||||
			return
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,8 @@ func initAPIRouter(router *mux.Router) error {
 | 
			
		||||
	router.HandleFunc("/api/domain/statistics", domainStatisticsHandler).Methods("POST")
 | 
			
		||||
 | 
			
		||||
	router.HandleFunc("/api/commenter/session/new", commenterSessionNewHandler).Methods("GET")
 | 
			
		||||
	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/oauth/google/redirect", googleRedirectHandler).Methods("GET")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								db/20180610215858-commenter-password.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								db/20180610215858-commenter-password.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
ALTER TABLE commenters
 | 
			
		||||
  ADD passwordHash TEXT NOT NULL DEFAULT '';
 | 
			
		||||
@@ -153,10 +153,10 @@
 | 
			
		||||
                  <div class="pitch">
 | 
			
		||||
                    Moderators have the power to approve and delete comments. To make someone a moderator, add their email address down below. Once added, shiny new moderation buttons will appear on each comment for that person on each page on this domain.
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="email-container">
 | 
			
		||||
                    <div class="email">
 | 
			
		||||
                      <input class="input" type="text" id="new-mod" placeholder="Email">
 | 
			
		||||
                      <button id="new-mod-button" class="email-button" onclick="window.moderatorNewHandler()">Add moderator</button>
 | 
			
		||||
                  <div class="commento-email-container">
 | 
			
		||||
                    <div class="commento-email">
 | 
			
		||||
                      <input class="commento-input" type="text" id="new-mod" placeholder="Email">
 | 
			
		||||
                      <button id="new-mod-button" class="commento-email-button" onclick="window.moderatorNewHandler()">Add moderator</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="mod-emails-container">
 | 
			
		||||
@@ -244,10 +244,10 @@
 | 
			
		||||
 | 
			
		||||
                        <br><br>
 | 
			
		||||
 | 
			
		||||
                        <div class="email-container">
 | 
			
		||||
                          <div class="email">
 | 
			
		||||
                            <input class="input" type="text" id="new-mod" placeholder="https://media.disqus.com/uploads/...">
 | 
			
		||||
                            <button class="email-button">Import</button>
 | 
			
		||||
                        <div class="commento-email-container">
 | 
			
		||||
                          <div class="commento-email">
 | 
			
		||||
                            <input class="commento-input" type="text" id="new-mod" placeholder="https://media.disqus.com/uploads/...">
 | 
			
		||||
                            <button class="commento-email-button">Import</button>
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="subtext-container">
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,43 @@
 | 
			
		||||
  //     override that.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  var ID_ROOT = "commento";
 | 
			
		||||
  var ID_MAIN_AREA = "commento-main-area";
 | 
			
		||||
  var ID_LOGIN_BOX_CONTAINER = "commento-login-box-container";
 | 
			
		||||
  var ID_LOGIN_BOX = "commento-login-box";
 | 
			
		||||
  var ID_LOGIN_BOX_HEADER = "commento-login-box-header";
 | 
			
		||||
  var ID_LOGIN_BOX_SUBTITLE = "commento-login-box-subtitle";
 | 
			
		||||
  var ID_LOGIN_BOX_EMAIL_INPUT = "commento-login-box-email-input";
 | 
			
		||||
  var ID_LOGIN_BOX_PASSWORD_INPUT = "commento-login-box-password-input";
 | 
			
		||||
  var ID_LOGIN_BOX_NAME_INPUT = "commento-login-box-name-input";
 | 
			
		||||
  var ID_LOGIN_BOX_WEBSITE_INPUT = "commento-login-box-website-input";
 | 
			
		||||
  var ID_LOGIN_BOX_EMAIL_BUTTON = "commento-login-box-email-button";
 | 
			
		||||
  var ID_LOGIN_BOX_LOGIN_LINK_CONTAINER = "commento-login-box-login-link-container";
 | 
			
		||||
  var ID_LOGIN_BOX_LOGIN_LINK = "commento-login-box-login-link";
 | 
			
		||||
  var ID_LOGIN_BOX_HR = "commento-login-box-hr";
 | 
			
		||||
  var ID_LOGIN_BOX_OAUTH_PRETEXT = "commento-login-box-oauth-pretext";
 | 
			
		||||
  var ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER = "commento-login-box-oauth-buttons-container";
 | 
			
		||||
  var ID_ERROR = "commento-error";
 | 
			
		||||
  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_CARD = "commento-comment-card-";
 | 
			
		||||
  var ID_BODY = "commento-comment-body-";
 | 
			
		||||
  var ID_SUBTITLE = "commento-comment-subtitle-";
 | 
			
		||||
  var ID_SCORE = "commento-comment-score-";
 | 
			
		||||
  var ID_OPTIONS = "commento-comment-options-";
 | 
			
		||||
  var ID_EDIT = "commento-comment-edit-";
 | 
			
		||||
  var ID_REPLY = "commento-comment-reply-";
 | 
			
		||||
  var ID_COLLAPSE = "commento-comment-collapse-";
 | 
			
		||||
  var ID_UPVOTE = "commento-comment-upvote-";
 | 
			
		||||
  var ID_DOWNVOTE = "commento-comment-downvote-";
 | 
			
		||||
  var ID_APPROVE = "commento-comment-approve-";
 | 
			
		||||
  var ID_REMOVE = "commento-comment-remove-";
 | 
			
		||||
  var ID_CONTENTS = "commento-comment-contents-";
 | 
			
		||||
  var ID_SUBMIT_BUTTON = "commento-submit-button-";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  var origin = global.commento_origin;
 | 
			
		||||
  var cdn = global.commento_cdn;
 | 
			
		||||
  var root = null;
 | 
			
		||||
@@ -24,6 +61,8 @@
 | 
			
		||||
  var chosenAnonymous = false;
 | 
			
		||||
  var shownSubmitButton = {"root": false};
 | 
			
		||||
  var shownReply = {};
 | 
			
		||||
  var configuredOauths = [];
 | 
			
		||||
  var loginBoxType = "signup";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  function $(id) {
 | 
			
		||||
@@ -169,27 +208,37 @@
 | 
			
		||||
      var loggedContainer = create("div");
 | 
			
		||||
      var loggedInAs = create("div");
 | 
			
		||||
      var name = create("a");
 | 
			
		||||
      var photo = create("img");
 | 
			
		||||
      var avatar;
 | 
			
		||||
      var logout = create("div");
 | 
			
		||||
      var color = colorGet(resp.commenter.name);
 | 
			
		||||
 | 
			
		||||
      classAdd(loggedContainer, "logged-container");
 | 
			
		||||
      classAdd(loggedInAs, "logged-in-as");
 | 
			
		||||
      classAdd(name, "name");
 | 
			
		||||
      classAdd(photo, "photo");
 | 
			
		||||
      classAdd(logout, "logout");
 | 
			
		||||
 | 
			
		||||
      name.innerText = resp.commenter.name;
 | 
			
		||||
      logout.innerText = "Logout";
 | 
			
		||||
 | 
			
		||||
      attr(name, "href", resp.commenter.link);
 | 
			
		||||
      if (resp.commenter.provider == "google") {
 | 
			
		||||
        attr(photo, "src", resp.commenter.photo + "?sz=50");
 | 
			
		||||
      } else {
 | 
			
		||||
        attr(photo, "src", resp.commenter.photo);
 | 
			
		||||
      }
 | 
			
		||||
      attr(logout, "onclick", "logout()");
 | 
			
		||||
      attr(name, "href", resp.commenter.link);
 | 
			
		||||
      if (resp.commenter.photo == "undefined") {
 | 
			
		||||
        avatar = create("div");
 | 
			
		||||
        avatar.style["background"] = color;
 | 
			
		||||
        avatar.style["boxShadow"] = "0px 0px 0px 2px " + color;
 | 
			
		||||
        avatar.innerHTML = resp.commenter.name[0].toUpperCase();
 | 
			
		||||
        classAdd(avatar, "avatar");
 | 
			
		||||
      } else {
 | 
			
		||||
        avatar = create("img");
 | 
			
		||||
        if (resp.commenter.provider == "google") {
 | 
			
		||||
          attr(avatar, "src", resp.commenter.photo + "?sz=50");
 | 
			
		||||
        } else {
 | 
			
		||||
          attr(avatar, "src", resp.commenter.photo);
 | 
			
		||||
        }
 | 
			
		||||
        classAdd(avatar, "avatar-img");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      append(loggedInAs, photo);
 | 
			
		||||
      append(loggedInAs, avatar);
 | 
			
		||||
      append(loggedInAs, name);
 | 
			
		||||
      append(loggedContainer, loggedInAs);
 | 
			
		||||
      append(loggedContainer, logout);
 | 
			
		||||
@@ -280,6 +329,10 @@
 | 
			
		||||
      isFrozen = resp.isFrozen;
 | 
			
		||||
      comments = resp.comments;
 | 
			
		||||
      commenters = resp.commenters;
 | 
			
		||||
      configuredOauths = resp.configuredOauths;
 | 
			
		||||
 | 
			
		||||
      if (!resp.requireModeration)
 | 
			
		||||
        configuredOauths.push("anonymous");
 | 
			
		||||
 | 
			
		||||
      cssLoad(cdn + "/css/commento.css");
 | 
			
		||||
 | 
			
		||||
@@ -335,43 +388,25 @@
 | 
			
		||||
 | 
			
		||||
    if (!isAuthenticated && !chosenAnonymous) {
 | 
			
		||||
      var buttonsContainer = create("div");
 | 
			
		||||
      var createButton = create("div");
 | 
			
		||||
 | 
			
		||||
      if (!isMobile()) {
 | 
			
		||||
        classAdd(buttonsContainer, "buttons-container");
 | 
			
		||||
        classAdd(textarea, "blurred-textarea");
 | 
			
		||||
      } else {
 | 
			
		||||
        classAdd(textarea, "hidden");
 | 
			
		||||
        classAdd(buttonsContainer, "mobile-buttons-container");
 | 
			
		||||
        classAdd(buttonsContainer, "opaque");
 | 
			
		||||
      }
 | 
			
		||||
      classAdd(buttonsContainer, "create-container");
 | 
			
		||||
 | 
			
		||||
      var oauths = ["google"];
 | 
			
		||||
      if (!requireIdentification)
 | 
			
		||||
        oauths.push("anonymous");
 | 
			
		||||
 | 
			
		||||
      for (var i = 0; i < oauths.length; i++) {
 | 
			
		||||
        var oauthButton = create("button");
 | 
			
		||||
 | 
			
		||||
        classAdd(oauthButton, "button");
 | 
			
		||||
        classAdd(oauthButton, oauths[i] + "-button");
 | 
			
		||||
 | 
			
		||||
        if (isMobile())
 | 
			
		||||
          classAdd(oauthButton, "opaque");
 | 
			
		||||
 | 
			
		||||
        attr(oauthButton, "onclick", "commentoAuth('" + oauths[i] + "', '" + id + "')");
 | 
			
		||||
 | 
			
		||||
        oauthButton.innerText = oauths[i][0].toUpperCase() + oauths[i].slice(1);
 | 
			
		||||
 | 
			
		||||
        append(buttonsContainer, oauthButton);
 | 
			
		||||
      }
 | 
			
		||||
      classAdd(createButton, "button");
 | 
			
		||||
      classAdd(createButton, "create-button");
 | 
			
		||||
 | 
			
		||||
      attr(createButton, "onclick", "loginBoxShow()");
 | 
			
		||||
      attr(textarea, "disabled", true);
 | 
			
		||||
 | 
			
		||||
      createButton.innerText = "Create an Account";
 | 
			
		||||
 | 
			
		||||
      append(buttonsContainer, createButton);
 | 
			
		||||
      append(textareaContainer, buttonsContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    attr(textarea, "placeholder", "Join the discussion!");
 | 
			
		||||
    attr(textarea, "onclick", "showSubmitButton('" + id + "')");
 | 
			
		||||
    else {
 | 
			
		||||
      attr(textarea, "placeholder", "Join the discussion!");
 | 
			
		||||
      attr(textarea, "onclick", "showSubmitButton('" + id + "')");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    textarea.oninput = autoExpander(textarea);
 | 
			
		||||
 | 
			
		||||
@@ -382,6 +417,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function rootCreate(callback) {
 | 
			
		||||
    var mainArea = $(ID_MAIN_AREA);
 | 
			
		||||
    var commentsArea = create("div");
 | 
			
		||||
 | 
			
		||||
    commentsArea.id = ID_COMMENTS_AREA;
 | 
			
		||||
@@ -390,8 +426,9 @@
 | 
			
		||||
 | 
			
		||||
    commentsArea.innerHTML = "";
 | 
			
		||||
 | 
			
		||||
    append(root, textareaCreate("root"));
 | 
			
		||||
    append(root, commentsArea);
 | 
			
		||||
    append(mainArea, textareaCreate("root"));
 | 
			
		||||
    append(mainArea, commentsArea);
 | 
			
		||||
    append(root, mainArea);
 | 
			
		||||
 | 
			
		||||
    call(callback);
 | 
			
		||||
  }
 | 
			
		||||
@@ -439,7 +476,7 @@
 | 
			
		||||
        $(ID_COMMENTS_AREA).innerHTML = "";
 | 
			
		||||
        commentsRender();
 | 
			
		||||
 | 
			
		||||
        if (requireModeration && !isModerator) {
 | 
			
		||||
        if (!resp.approved) {
 | 
			
		||||
          if (id == "root") {
 | 
			
		||||
            var body = $(ID_SUPER_CONTAINER + id);
 | 
			
		||||
            prepend(body, messageCreate("Your comment is under moderation."));
 | 
			
		||||
@@ -511,26 +548,6 @@
 | 
			
		||||
      return score + " point";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var ID_ERROR = "commento-error";
 | 
			
		||||
  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_CARD = "commento-comment-card-";
 | 
			
		||||
  var ID_BODY = "commento-comment-body-";
 | 
			
		||||
  var ID_SUBTITLE = "commento-comment-subtitle-";
 | 
			
		||||
  var ID_SCORE = "commento-comment-score-";
 | 
			
		||||
  var ID_OPTIONS = "commento-comment-options-";
 | 
			
		||||
  var ID_EDIT = "commento-comment-edit-";
 | 
			
		||||
  var ID_REPLY = "commento-comment-reply-";
 | 
			
		||||
  var ID_COLLAPSE = "commento-comment-collapse-";
 | 
			
		||||
  var ID_UPVOTE = "commento-comment-upvote-";
 | 
			
		||||
  var ID_DOWNVOTE = "commento-comment-downvote-";
 | 
			
		||||
  var ID_APPROVE = "commento-comment-approve-";
 | 
			
		||||
  var ID_REMOVE = "commento-comment-remove-";
 | 
			
		||||
  var ID_CONTENTS = "commento-comment-contents-";
 | 
			
		||||
  var ID_SUBMIT_BUTTON = "commento-submit-button-";
 | 
			
		||||
 | 
			
		||||
  function commentsRecurse(parentMap, parentHex) {
 | 
			
		||||
    var cur = parentMap[parentHex];
 | 
			
		||||
    if (!cur || !cur.length) {
 | 
			
		||||
@@ -639,7 +656,6 @@
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      attr(edit, "onclick", "startEdit('" + comment.commentHex + "')");
 | 
			
		||||
      attr(reply, "onclick", "replyShow('" + comment.commentHex + "')");
 | 
			
		||||
      attr(collapse, "onclick", "commentCollapse('" + comment.commentHex + "')");
 | 
			
		||||
      attr(approve, "onclick", "commentApprove('" + comment.commentHex + "')");
 | 
			
		||||
      attr(remove, "onclick", "commentDelete('" + comment.commentHex + "')");
 | 
			
		||||
@@ -657,9 +673,16 @@
 | 
			
		||||
          attr(upvote, "onclick", "vote('" + comment.commentHex + "', 0, 1)");
 | 
			
		||||
          attr(downvote, "onclick", "vote('" + comment.commentHex + "', 0, -1)");
 | 
			
		||||
        }
 | 
			
		||||
      } else if (!chosenAnonymous) {
 | 
			
		||||
        attr(upvote, "onclick", "replyShow('" + comment.commentHex + "')");
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        attr(upvote, "onclick", "loginBoxShow()");
 | 
			
		||||
        attr(downvote, "onclick", "loginBoxShow()");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (isAuthenticated || chosenAnonymous)
 | 
			
		||||
        attr(reply, "onclick", "replyShow('" + comment.commentHex + "')");
 | 
			
		||||
      else
 | 
			
		||||
        attr(reply, "onclick", "loginBoxShow()");
 | 
			
		||||
 | 
			
		||||
      if (isAuthenticated) {
 | 
			
		||||
        if (isModerator) {
 | 
			
		||||
@@ -680,11 +703,9 @@
 | 
			
		||||
      if (false) // replace when edit is implemented
 | 
			
		||||
        append(options, edit);
 | 
			
		||||
 | 
			
		||||
      if (isAuthenticated) {
 | 
			
		||||
        append(options, upvote);
 | 
			
		||||
        append(options, downvote);
 | 
			
		||||
        append(options, reply);
 | 
			
		||||
      }
 | 
			
		||||
      append(options, upvote);
 | 
			
		||||
      append(options, downvote);
 | 
			
		||||
      append(options, reply);
 | 
			
		||||
 | 
			
		||||
      if (isModerator) {
 | 
			
		||||
        if (comment.state == "unapproved")
 | 
			
		||||
@@ -906,16 +927,11 @@
 | 
			
		||||
    append(el, submit);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.commentoAuth = function(provider, id) {
 | 
			
		||||
  global.commentoAuth = function(provider) {
 | 
			
		||||
    if (provider == "anonymous") {
 | 
			
		||||
      cookieSet("session", "anonymous");
 | 
			
		||||
      chosenAnonymous = true;
 | 
			
		||||
      refreshAll(function() {
 | 
			
		||||
        if (id != "root")
 | 
			
		||||
          global.replyShow(id);
 | 
			
		||||
        $(ID_TEXTAREA + id).click();
 | 
			
		||||
        $(ID_TEXTAREA + id).focus();
 | 
			
		||||
      });
 | 
			
		||||
      refreshAll();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -933,12 +949,7 @@
 | 
			
		||||
 | 
			
		||||
      var interval = setInterval(function() {
 | 
			
		||||
        if (popup.closed) {
 | 
			
		||||
          refreshAll(function() {
 | 
			
		||||
            if (id != "root")
 | 
			
		||||
              global.replyShow(id);
 | 
			
		||||
            $(ID_TEXTAREA + id).click();
 | 
			
		||||
            $(ID_TEXTAREA + id).focus();
 | 
			
		||||
          });
 | 
			
		||||
          refreshAll();
 | 
			
		||||
          clearInterval(interval);
 | 
			
		||||
        }
 | 
			
		||||
      }, 250);
 | 
			
		||||
@@ -946,17 +957,305 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function refreshAll(callback) {
 | 
			
		||||
    $("commento").innerHTML = "";
 | 
			
		||||
    $(ID_ROOT).innerHTML = "";
 | 
			
		||||
    shownSubmitButton = {"root": false};
 | 
			
		||||
    shownReply = {};
 | 
			
		||||
    main(callback);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function loginBoxCreate() {
 | 
			
		||||
    var loginBoxContainer = create("div");
 | 
			
		||||
 | 
			
		||||
    loginBoxContainer.id = ID_LOGIN_BOX_CONTAINER;
 | 
			
		||||
 | 
			
		||||
    append(root, loginBoxContainer);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.signupRender = function() {
 | 
			
		||||
    var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
 | 
			
		||||
    var loginBox = create("div");
 | 
			
		||||
    var header = create("div");
 | 
			
		||||
    var subtitle = create("div");
 | 
			
		||||
    var emailContainer = create("div");
 | 
			
		||||
    var email = create("div");
 | 
			
		||||
    var emailInput = create("input");
 | 
			
		||||
    var emailButton = create("button");
 | 
			
		||||
    var loginLinkContainer = create("div");
 | 
			
		||||
    var loginLink = create("a");
 | 
			
		||||
    var hr = create("hr");
 | 
			
		||||
    var oauthPretext = create("div");
 | 
			
		||||
    var oauthButtonsContainer = create("div");
 | 
			
		||||
    var oauthButtons = create("div");
 | 
			
		||||
    var close = create("div");
 | 
			
		||||
 | 
			
		||||
    loginBox.id = ID_LOGIN_BOX;
 | 
			
		||||
    header.id = ID_LOGIN_BOX_HEADER;
 | 
			
		||||
    subtitle.id = ID_LOGIN_BOX_SUBTITLE;
 | 
			
		||||
    emailInput.id = ID_LOGIN_BOX_EMAIL_INPUT;
 | 
			
		||||
    emailButton.id = ID_LOGIN_BOX_EMAIL_BUTTON;
 | 
			
		||||
    loginLink.id = ID_LOGIN_BOX_LOGIN_LINK;
 | 
			
		||||
    loginLinkContainer.id = ID_LOGIN_BOX_LOGIN_LINK_CONTAINER;
 | 
			
		||||
    hr.id = ID_LOGIN_BOX_HR;
 | 
			
		||||
    oauthPretext.id = ID_LOGIN_BOX_OAUTH_PRETEXT;
 | 
			
		||||
    oauthButtonsContainer.id = ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER;
 | 
			
		||||
 | 
			
		||||
    header.innerText = "Create an account to join the discussion!";
 | 
			
		||||
 | 
			
		||||
    classAdd(loginBoxContainer, "login-box-container");
 | 
			
		||||
    classAdd(loginBox, "login-box");
 | 
			
		||||
    classAdd(header, "login-box-header");
 | 
			
		||||
    classAdd(subtitle, "login-box-subtitle");
 | 
			
		||||
    classAdd(emailContainer, "email-container");
 | 
			
		||||
    classAdd(email, "email");
 | 
			
		||||
    classAdd(emailInput, "input");
 | 
			
		||||
    classAdd(emailButton, "email-button");
 | 
			
		||||
    classAdd(loginLinkContainer, "login-link-container");
 | 
			
		||||
    classAdd(loginLink, "login-link");
 | 
			
		||||
    classAdd(oauthPretext, "login-box-subtitle");
 | 
			
		||||
    classAdd(oauthButtonsContainer, "oauth-buttons-container");
 | 
			
		||||
    classAdd(oauthButtons, "oauth-buttons");
 | 
			
		||||
    classAdd(close, "login-box-close");
 | 
			
		||||
 | 
			
		||||
    emailButton.innerText = "Continue";
 | 
			
		||||
    loginLink.innerText = "Already have an account? Log in.";
 | 
			
		||||
    subtitle.innerText = "Sign up with your email to vote and comment.";
 | 
			
		||||
    oauthPretext.innerText = "Or proceed with social login.";
 | 
			
		||||
 | 
			
		||||
    attr(loginBoxContainer, "style", "display: none; opacity: 0;");
 | 
			
		||||
    attr(emailInput, "name", "email");
 | 
			
		||||
    attr(emailInput, "placeholder", "Email address");
 | 
			
		||||
    attr(emailInput, "type", "text");
 | 
			
		||||
    attr(emailButton, "onclick", "passwordAsk()");
 | 
			
		||||
    attr(loginLink, "onclick", "loginSwitch()");
 | 
			
		||||
    attr(close, "onclick", "loginBoxClose()");
 | 
			
		||||
 | 
			
		||||
    for (var i = 0; i < configuredOauths.length; i++) {
 | 
			
		||||
      var button = create("button");
 | 
			
		||||
 | 
			
		||||
      classAdd(button, "button");
 | 
			
		||||
      classAdd(button, configuredOauths[i] + "-button");
 | 
			
		||||
 | 
			
		||||
      button.innerText = configuredOauths[i];
 | 
			
		||||
 | 
			
		||||
      attr(button, "onclick", "commentoAuth('" + configuredOauths[i] + "')");
 | 
			
		||||
 | 
			
		||||
      append(oauthButtons, button);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    append(loginBox, header);
 | 
			
		||||
    append(loginBox, subtitle);
 | 
			
		||||
 | 
			
		||||
    append(email, emailInput);
 | 
			
		||||
    append(email, emailButton);
 | 
			
		||||
    append(emailContainer, email);
 | 
			
		||||
    append(loginBox, emailContainer);
 | 
			
		||||
 | 
			
		||||
    append(loginLinkContainer, loginLink);
 | 
			
		||||
    append(loginBox, loginLinkContainer);
 | 
			
		||||
 | 
			
		||||
    append(loginBox, hr);
 | 
			
		||||
 | 
			
		||||
    if (configuredOauths.length > 0) {
 | 
			
		||||
      append(loginBox, oauthPretext);
 | 
			
		||||
      append(oauthButtonsContainer, oauthButtons);
 | 
			
		||||
      append(loginBox, oauthButtonsContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    append(loginBox, close);
 | 
			
		||||
 | 
			
		||||
    loginBoxType = "signup";
 | 
			
		||||
    loginBoxContainer.innerHTML = "";
 | 
			
		||||
    append(loginBoxContainer, loginBox);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.loginSwitch = function() {
 | 
			
		||||
    var header = $(ID_LOGIN_BOX_HEADER);
 | 
			
		||||
    var subtitle = $(ID_LOGIN_BOX_SUBTITLE);
 | 
			
		||||
    var loginLink = $(ID_LOGIN_BOX_LOGIN_LINK);
 | 
			
		||||
    var hr = $(ID_LOGIN_BOX_HR);
 | 
			
		||||
    var oauthButtonsContainer = $(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER);
 | 
			
		||||
    var oauthPretext = $(ID_LOGIN_BOX_OAUTH_PRETEXT);
 | 
			
		||||
 | 
			
		||||
    header.innerText = "Login to continue";
 | 
			
		||||
    loginLink.innerText = "Don't have an account? Sign up.";
 | 
			
		||||
    subtitle.innerText = "Enter your email address to start with.";
 | 
			
		||||
 | 
			
		||||
    attr(loginLink, "onclick", "signupSwitch()");
 | 
			
		||||
 | 
			
		||||
    loginBoxType = "login";
 | 
			
		||||
 | 
			
		||||
    remove(hr);
 | 
			
		||||
    remove(oauthPretext);
 | 
			
		||||
    remove(oauthButtonsContainer);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.signupSwitch = function() {
 | 
			
		||||
    loginBoxClose();
 | 
			
		||||
    loginBoxShow();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function loginUP(username, password) {
 | 
			
		||||
    var json = {
 | 
			
		||||
      email: username,
 | 
			
		||||
      password: password,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    post(origin + "/api/commenter/login", json, function(resp) {
 | 
			
		||||
      if (!resp.success) {
 | 
			
		||||
        loginBoxClose();
 | 
			
		||||
        errorShow(resp.message);
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      cookieSet("session", resp.session);
 | 
			
		||||
      refreshAll();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.login = function() {
 | 
			
		||||
    var email = $(ID_LOGIN_BOX_EMAIL_INPUT);
 | 
			
		||||
    var password = $(ID_LOGIN_BOX_PASSWORD_INPUT);
 | 
			
		||||
 | 
			
		||||
    loginUP(email.value, password.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.signup = function() {
 | 
			
		||||
    var email = $(ID_LOGIN_BOX_EMAIL_INPUT);
 | 
			
		||||
    var name = $(ID_LOGIN_BOX_NAME_INPUT);
 | 
			
		||||
    var website = $(ID_LOGIN_BOX_WEBSITE_INPUT);
 | 
			
		||||
    var password = $(ID_LOGIN_BOX_PASSWORD_INPUT);
 | 
			
		||||
 | 
			
		||||
    var json = {
 | 
			
		||||
      email: email.value,
 | 
			
		||||
      name: name.value,
 | 
			
		||||
      website: website.value,
 | 
			
		||||
      password: password.value,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    post(origin + "/api/commenter/new", json, function(resp) {
 | 
			
		||||
      if (!resp.success) {
 | 
			
		||||
        loginBoxClose();
 | 
			
		||||
        errorShow(resp.message);
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      loginUP(email.value, password.value);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.passwordAsk = function() {
 | 
			
		||||
    var loginBox = $(ID_LOGIN_BOX);
 | 
			
		||||
    var subtitle = $(ID_LOGIN_BOX_SUBTITLE);
 | 
			
		||||
    var emailInput = $(ID_LOGIN_BOX_EMAIL_INPUT);
 | 
			
		||||
    var emailButton = $(ID_LOGIN_BOX_EMAIL_BUTTON);
 | 
			
		||||
    var loginLinkContainer = $(ID_LOGIN_BOX_LOGIN_LINK_CONTAINER);
 | 
			
		||||
    var hr = $(ID_LOGIN_BOX_HR);
 | 
			
		||||
    var oauthButtonsContainer = $(ID_LOGIN_BOX_OAUTH_BUTTONS_CONTAINER);
 | 
			
		||||
    var oauthPretext = $(ID_LOGIN_BOX_OAUTH_PRETEXT);
 | 
			
		||||
    
 | 
			
		||||
    remove(emailButton);
 | 
			
		||||
    remove(loginLinkContainer);
 | 
			
		||||
    if (loginBoxType == "signup") {
 | 
			
		||||
      remove(hr);
 | 
			
		||||
      remove(oauthPretext);
 | 
			
		||||
      remove(oauthButtonsContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var order, id, type, placeholder;
 | 
			
		||||
 | 
			
		||||
    if (loginBoxType == "signup") {
 | 
			
		||||
      var order = ["name", "website", "password"];
 | 
			
		||||
      var id = [ID_LOGIN_BOX_NAME_INPUT, ID_LOGIN_BOX_WEBSITE_INPUT, ID_LOGIN_BOX_PASSWORD_INPUT];
 | 
			
		||||
      var type = ["text", "text", "password"];
 | 
			
		||||
      var placeholder = ["Real Name", "Website (Optional)", "Password"];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      var order = ["password"];
 | 
			
		||||
      var id = [ID_LOGIN_BOX_PASSWORD_INPUT];
 | 
			
		||||
      var type = ["password"];
 | 
			
		||||
      var placeholder = ["Password"];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    subtitle.innerText = "Finish the rest of your profile to complete."
 | 
			
		||||
 | 
			
		||||
    for (var i = 0; i < order.length; i++) {
 | 
			
		||||
      var fieldContainer = create("div");
 | 
			
		||||
      var field = create("div");
 | 
			
		||||
      var fieldInput = create("input");
 | 
			
		||||
 | 
			
		||||
      fieldInput.id = id[i];
 | 
			
		||||
 | 
			
		||||
      classAdd(fieldContainer, "email-container");
 | 
			
		||||
      classAdd(field, "email");
 | 
			
		||||
      classAdd(fieldInput, "input");
 | 
			
		||||
 | 
			
		||||
      attr(fieldInput, "name", order[i]);
 | 
			
		||||
      attr(fieldInput, "type", type[i]);
 | 
			
		||||
      attr(fieldInput, "placeholder", placeholder[i]);
 | 
			
		||||
 | 
			
		||||
      append(field, fieldInput);
 | 
			
		||||
      append(fieldContainer, field);
 | 
			
		||||
 | 
			
		||||
      if (order[i] == "password") {
 | 
			
		||||
        var fieldButton = create("button");
 | 
			
		||||
        classAdd(fieldButton, "email-button");
 | 
			
		||||
        fieldButton.innerText = loginBoxType;
 | 
			
		||||
 | 
			
		||||
        if (loginBoxType == "signup")
 | 
			
		||||
          attr(fieldButton, "onclick", "signup()");
 | 
			
		||||
        else
 | 
			
		||||
          attr(fieldButton, "onclick", "login()");
 | 
			
		||||
 | 
			
		||||
        append(field, fieldButton);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      append(loginBox, fieldContainer);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function mainAreaCreate() {
 | 
			
		||||
    var mainArea = create("div");
 | 
			
		||||
 | 
			
		||||
    mainArea.id = ID_MAIN_AREA;
 | 
			
		||||
 | 
			
		||||
    classAdd(mainArea, "main-area");
 | 
			
		||||
 | 
			
		||||
    append(root, mainArea);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.loginBoxClose = function() {
 | 
			
		||||
    var mainArea = $(ID_MAIN_AREA);
 | 
			
		||||
    var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
 | 
			
		||||
 | 
			
		||||
    classRemove(mainArea, "blurred");
 | 
			
		||||
 | 
			
		||||
    attr(loginBoxContainer, "style", "display: none");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  global.loginBoxShow = function() {
 | 
			
		||||
    var mainArea = $(ID_MAIN_AREA);
 | 
			
		||||
    var loginBoxContainer = $(ID_LOGIN_BOX_CONTAINER);
 | 
			
		||||
 | 
			
		||||
    global.signupRender();
 | 
			
		||||
 | 
			
		||||
    classAdd(mainArea, "blurred");
 | 
			
		||||
    
 | 
			
		||||
    attr(loginBoxContainer, "style", "");
 | 
			
		||||
 | 
			
		||||
    window.location.hash = ID_LOGIN_BOX_CONTAINER;
 | 
			
		||||
 | 
			
		||||
    $(ID_LOGIN_BOX_EMAIL_INPUT).focus();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function main(callback) {
 | 
			
		||||
    root = $("commento");
 | 
			
		||||
    root = $(ID_ROOT);
 | 
			
		||||
 | 
			
		||||
    loginBoxCreate();
 | 
			
		||||
 | 
			
		||||
    errorElementCreate();
 | 
			
		||||
 | 
			
		||||
    mainAreaCreate();
 | 
			
		||||
 | 
			
		||||
    selfGet(function() {
 | 
			
		||||
      commentsGet(function() {
 | 
			
		||||
        rootCreate(function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ input[type=text]::placeholder {
 | 
			
		||||
 | 
			
		||||
textarea::placeholder {
 | 
			
		||||
  color: #aaa;
 | 
			
		||||
  font-size: 22px;
 | 
			
		||||
  padding-top: 13px;
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  line-height: 80px;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
@@ -28,7 +28,7 @@ textarea {
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  outline: none;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  min-height: 75px;
 | 
			
		||||
  min-height: 100px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -41,65 +41,42 @@ textarea {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
 | 
			
		||||
  &:hover {
 | 
			
		||||
    .commento-button, .commento-buttons-container::before {
 | 
			
		||||
      opacity: 1;
 | 
			
		||||
      transform: translate(0px,-3px);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-submit-button {
 | 
			
		||||
      transform: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-blurred-textarea {
 | 
			
		||||
      opacity: .7;
 | 
			
		||||
      transform: scale(.95);
 | 
			
		||||
      filter: blur(4px);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @media only screen and (max-width: 550px) {
 | 
			
		||||
      .commento-buttons-container::before {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  .commento-submit-button {
 | 
			
		||||
    transform: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-buttons-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
.commento-oauth-buttons-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-mobile-buttons-container::before,
 | 
			
		||||
.commento-buttons-container::before {
 | 
			
		||||
  content: "Authenticate with";
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
.commento-oauth-buttons,
 | 
			
		||||
.commento-create-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-oauth-buttons {
 | 
			
		||||
  display: contents;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-create-container::before {
 | 
			
		||||
  content: "Want to add to the discussion?";
 | 
			
		||||
  display: block;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  line-height: 24px;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  padding: 6px;
 | 
			
		||||
  color: $gray-8;
 | 
			
		||||
  transition: all 0.3s;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
  outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-mobile-buttons-container::before {
 | 
			
		||||
  content: "To join the discussion, authenticate with";;
 | 
			
		||||
  display: block;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media only screen and (max-width: 550px) {
 | 
			
		||||
  .commento-buttons-container::before {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-button {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
@@ -118,31 +95,25 @@ textarea {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  margin-left: 5px;
 | 
			
		||||
  margin-left: 5px;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-opaque {
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-opaque::before {
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
  margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-google-button {
 | 
			
		||||
  transition: all 0.3s;
 | 
			
		||||
  background: #dd4b39;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-github-button {
 | 
			
		||||
  transition: all 0.3s;
 | 
			
		||||
  background: #000000;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-anonymous-button {
 | 
			
		||||
  transition: all 0.3s;
 | 
			
		||||
  background: #096fa6;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-blurred-textarea {
 | 
			
		||||
@@ -152,7 +123,6 @@ textarea {
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  transition: 0.3s all;
 | 
			
		||||
  will-change: transform;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -160,7 +130,6 @@ textarea {
 | 
			
		||||
.commento-delete-button,
 | 
			
		||||
.commento-submit-button {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  width: -moz-fit-content;
 | 
			
		||||
  width: -webkit-fit-content;
 | 
			
		||||
@@ -169,6 +138,11 @@ textarea {
 | 
			
		||||
  width: fit-content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-create-button {
 | 
			
		||||
  width: 150px;
 | 
			
		||||
  background: $pink-9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commento-submit-button {
 | 
			
		||||
  float: right;
 | 
			
		||||
  background: $indigo-7;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  margin-bottom: 16px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 38px;
 | 
			
		||||
 | 
			
		||||
  .commento-logout {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
@@ -23,15 +24,7 @@
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: 6px;
 | 
			
		||||
      left: 64px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-photo {
 | 
			
		||||
      width: 32px;
 | 
			
		||||
      height: 32px;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      margin-left: 16px;
 | 
			
		||||
      margin-right: 16px;
 | 
			
		||||
      left: 48px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										92
									
								
								frontend/sass/commento-login.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								frontend/sass/commento-login.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
@import "colors-main.scss";
 | 
			
		||||
 | 
			
		||||
.commento-login-box-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 0px;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
 | 
			
		||||
  .commento-login-box {
 | 
			
		||||
    width: 90%;
 | 
			
		||||
    max-width: 500px;
 | 
			
		||||
    min-height: 125px;
 | 
			
		||||
    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;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    z-index: 100;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 8px;
 | 
			
		||||
    padding: 16px;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    transition: opacity 0.2s;
 | 
			
		||||
 | 
			
		||||
    hr {
 | 
			
		||||
      border: none;
 | 
			
		||||
      background: $gray-2;
 | 
			
		||||
      height: 1px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-header {
 | 
			
		||||
      font-size: 20px;
 | 
			
		||||
      font-weight: 200;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      color: $pink-8;
 | 
			
		||||
      margin: 16px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-subtitle {
 | 
			
		||||
      color: $gray-6;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-size: 15px;
 | 
			
		||||
      margin: 12px 0px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @import "email-main.scss";
 | 
			
		||||
 | 
			
		||||
    .commento-login-link-container {
 | 
			
		||||
      margin: 16px;
 | 
			
		||||
      width: calc(100% - 32px);
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      .commento-login-link {
 | 
			
		||||
        font-size: 15px;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        border-bottom: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-close {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      right: 16px;
 | 
			
		||||
      top: 16px;
 | 
			
		||||
      width: 16px;
 | 
			
		||||
      height: 16px;
 | 
			
		||||
      opacity: 0.3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-close:hover {
 | 
			
		||||
      opacity: 1;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-close:before, .commento-login-box-close:after {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: 7px;
 | 
			
		||||
      content: ' ';
 | 
			
		||||
      height: 17px;
 | 
			
		||||
      width: 2px;
 | 
			
		||||
      background-color: $gray-7;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-close:before {
 | 
			
		||||
      transform: rotate(45deg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-login-box-close:after {
 | 
			
		||||
      transform: rotate(-45deg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');
 | 
			
		||||
 | 
			
		||||
#commento {
 | 
			
		||||
  font-family: "Source Sans Pro", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  font-size: 15px;
 | 
			
		||||
  line-height: 1.5;
 | 
			
		||||
  color: #50596c;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  text-rendering: optimizeLegibility;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  min-height: 350px;
 | 
			
		||||
 | 
			
		||||
  @import "colors-main.scss";
 | 
			
		||||
  @import "common-main.scss";
 | 
			
		||||
@@ -15,11 +18,20 @@
 | 
			
		||||
  @import "commento-input.scss";
 | 
			
		||||
  @import "commento-logged.scss";
 | 
			
		||||
  @import "commento-buttons.scss";
 | 
			
		||||
  @import "commento-login.scss";
 | 
			
		||||
 | 
			
		||||
  .commento-hidden {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-blurred {
 | 
			
		||||
    filter: blur(4px);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-main-area {
 | 
			
		||||
    transition: filter 0.2s;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-error-box {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
@@ -43,6 +55,32 @@
 | 
			
		||||
    background: $blue-1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-avatar {
 | 
			
		||||
    width: 34px;
 | 
			
		||||
    height: 34px;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    color: white;
 | 
			
		||||
    font-size: 22px;
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-right: 10px;
 | 
			
		||||
    border: 1px solid #fff;
 | 
			
		||||
    box-shadow: 0px 0px 0px 2px #f00;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-avatar-img {
 | 
			
		||||
    width: 38px;
 | 
			
		||||
    height: 38px;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-right: 10px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .commento-card {
 | 
			
		||||
    padding: 12px 0px 0px 12px;
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
@@ -52,32 +90,6 @@
 | 
			
		||||
      padding-bottom: 12px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-avatar {
 | 
			
		||||
      width: 34px;
 | 
			
		||||
      height: 34px;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      color: white;
 | 
			
		||||
      font-size: 22px;
 | 
			
		||||
      float: left;
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
      border: 1px solid #fff;
 | 
			
		||||
      box-shadow: 0px 0px 0px 2px #f00;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-avatar-img {
 | 
			
		||||
      width: 38px;
 | 
			
		||||
      height: 38px;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      float: left;
 | 
			
		||||
      margin-right: 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-avatar::after {
 | 
			
		||||
      content:"";
 | 
			
		||||
      display:block;
 | 
			
		||||
 
 | 
			
		||||
@@ -105,60 +105,7 @@ body {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.email-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
 | 
			
		||||
  .email {
 | 
			
		||||
    @extend .shadow;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    background: $white;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    max-width: 400px;
 | 
			
		||||
 | 
			
		||||
    .input {
 | 
			
		||||
      height: 40px;
 | 
			
		||||
      background: $white;
 | 
			
		||||
      border: none;
 | 
			
		||||
      outline: none;
 | 
			
		||||
      padding: 5px;
 | 
			
		||||
      padding-left: 10px;
 | 
			
		||||
      width: 250px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .input::placeholder {
 | 
			
		||||
      color: $gray-5;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .email-button {
 | 
			
		||||
      height: 40px;
 | 
			
		||||
      min-width: 110px;
 | 
			
		||||
      float: right;
 | 
			
		||||
      background: $white;
 | 
			
		||||
      border: none;
 | 
			
		||||
      outline: none;
 | 
			
		||||
      padding: 0px 10px 0px 10px;
 | 
			
		||||
      border-left: 1px solid $gray-1;
 | 
			
		||||
      font-size: 12px;
 | 
			
		||||
      text-transform: uppercase;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      color: $blue-7;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      transition: all 0.2s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .email-button:hover {
 | 
			
		||||
      color: $blue-6;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .email-button:disabled {
 | 
			
		||||
      cursor: default;
 | 
			
		||||
      color: $gray-6;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@import "email-main.scss";
 | 
			
		||||
 | 
			
		||||
.mod-emails-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								frontend/sass/email-main.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								frontend/sass/email-main.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
@import "colors-main.scss";
 | 
			
		||||
@import "common-main.scss";
 | 
			
		||||
 | 
			
		||||
.commento-email-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  margin: 8px 0px;
 | 
			
		||||
 | 
			
		||||
  .commento-email {
 | 
			
		||||
    @extend .shadow;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    background: $white;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    max-width: 400px;
 | 
			
		||||
 | 
			
		||||
    .commento-input {
 | 
			
		||||
      height: 40px;
 | 
			
		||||
      background: $white;
 | 
			
		||||
      border: none;
 | 
			
		||||
      outline: none;
 | 
			
		||||
      padding: 5px;
 | 
			
		||||
      padding-left: 10px;
 | 
			
		||||
      width: calc(100% - 120px);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-input::placeholder {
 | 
			
		||||
      color: $gray-5;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-email-button {
 | 
			
		||||
      height: 40px;
 | 
			
		||||
      min-width: 110px;
 | 
			
		||||
      float: right;
 | 
			
		||||
      background: $white;
 | 
			
		||||
      border: none;
 | 
			
		||||
      outline: none;
 | 
			
		||||
      padding: 0px 10px 0px 10px;
 | 
			
		||||
      border-left: 1px solid $gray-1;
 | 
			
		||||
      font-size: 12px;
 | 
			
		||||
      text-transform: uppercase;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      color: $blue-7;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      transition: all 0.2s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-email-button:hover {
 | 
			
		||||
      color: $blue-6;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .commento-email-button:disabled {
 | 
			
		||||
      cursor: default;
 | 
			
		||||
      color: $gray-6;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user