Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f9a39c330 | ||
|
|
633ccf427c | ||
|
|
51e4608c19 | ||
|
|
612e620ffc | ||
|
|
642076a231 | ||
|
|
f63639782c | ||
|
|
02615088ff | ||
|
|
5aa3bc86eb | ||
|
|
d5769d56c1 | ||
|
|
8eb0bc147c | ||
|
|
96589a2658 | ||
|
|
34e39edcda | ||
|
|
6d00a8e3aa | ||
|
|
c29b3a7a25 | ||
|
|
a99bf15332 | ||
|
|
7074800ecc | ||
|
|
80fb09d941 | ||
|
|
afabc25037 | ||
|
|
c9e7a3f40a | ||
|
|
4d82106aff | ||
|
|
4c0e261a8e | ||
|
|
9e3935b3b2 | ||
|
|
e4f71fe402 | ||
|
|
06c71f4e65 | ||
|
|
9fcf67d667 | ||
|
|
d1318daaca | ||
|
|
87a0c577bb | ||
|
|
bcc81e1ad8 | ||
|
|
1f8f3b3a36 | ||
|
|
610b61831d | ||
|
|
cf0b394b05 | ||
|
|
a36b11f07d | ||
|
|
93c9ce0cad | ||
|
|
af88db42b2 | ||
|
|
0c6ccdc0a1 | ||
|
|
6d3f8171e5 | ||
|
|
3f1c570e84 | ||
|
|
cd88ae264e | ||
|
|
b2abcae319 |
@@ -3,6 +3,7 @@ stages:
|
||||
- go-fmt
|
||||
- go-test
|
||||
- build-src
|
||||
- aws-upload-tags
|
||||
- build-docker
|
||||
- docker-registry-master
|
||||
- docker-registry-tags
|
||||
@@ -21,22 +22,37 @@ check-dco:
|
||||
build-src:
|
||||
stage: build-src
|
||||
image: debian:buster
|
||||
variables:
|
||||
GOPATH: $CI_PROJECT_DIR
|
||||
except:
|
||||
- master
|
||||
- tags
|
||||
before_script:
|
||||
- bash $CI_PROJECT_DIR/scripts/gitlab-ci-build-prescript
|
||||
script:
|
||||
- apt update
|
||||
- apt install -y curl gnupg git make golang
|
||||
- curl -sL https://deb.nodesource.com/setup_10.x | bash -
|
||||
- apt update
|
||||
- apt install -y nodejs
|
||||
- npm install -g html-minifier@3.5.7 uglify-js@3.4.1 sass@1.5.1
|
||||
- mkdir -p src/gitlab.com/commento && cd src/gitlab.com/commento && ln -s $CI_PROJECT_DIR && cd $CI_PROJECT_NAME
|
||||
- export GOPATH=/go
|
||||
- export PATH=$PATH:/go/bin
|
||||
- cd /go/src/$CI_PROJECT_NAME
|
||||
- make devel
|
||||
- make prod
|
||||
|
||||
aws-upload-tags:
|
||||
stage: aws-upload-tags
|
||||
image: debian:buster
|
||||
environment: aws-upload-tags
|
||||
variables:
|
||||
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
|
||||
only:
|
||||
- tags
|
||||
before_script:
|
||||
- bash $CI_PROJECT_DIR/scripts/gitlab-ci-build-prescript
|
||||
script:
|
||||
- export GOPATH=/go
|
||||
- export PATH=$PATH:/go/bin
|
||||
- cd /go/src/$CI_PROJECT_NAME
|
||||
- make prod
|
||||
- cd build/prod && tar -zcvf /commento-linux-amd64-$(git describe --tags).tgz .
|
||||
- aws s3 cp /commento-linux-amd64-$(git describe --tags).tgz s3://commento-release/
|
||||
|
||||
build-docker:
|
||||
stage: build-docker
|
||||
image: docker:stable
|
||||
@@ -46,7 +62,7 @@ build-docker:
|
||||
- master
|
||||
- tags
|
||||
script:
|
||||
- docker build -t commento-ce .
|
||||
- docker build -t commento .
|
||||
|
||||
go-test:
|
||||
stage: go-test
|
||||
@@ -58,12 +74,17 @@ go-test:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: commento_test
|
||||
COMMENTO_POSTGRES: postgres://postgres:postgres@postgres/commento_test?sslmode=disable
|
||||
GOPATH: $CI_PROJECT_DIR
|
||||
except:
|
||||
- master
|
||||
- tags
|
||||
before_script:
|
||||
- mkdir -p /go/src /go/bin /go/pkg
|
||||
- export GOPATH=/go
|
||||
- export PATH=$PATH:/go/bin
|
||||
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
- ln -s $CI_PROJECT_DIR /go/src/$CI_PROJECT_NAME
|
||||
script:
|
||||
- mkdir -p src/gitlab.com/commento && cd src/gitlab.com/commento && ln -s $CI_PROJECT_DIR && cd $CI_PROJECT_NAME
|
||||
- cd /go/src/$CI_PROJECT_NAME
|
||||
- make test
|
||||
|
||||
go-fmt:
|
||||
@@ -82,13 +103,13 @@ docker-registry-master:
|
||||
services:
|
||||
- docker:dind
|
||||
only:
|
||||
- master@commento/commento-ce
|
||||
- master@commento/commento
|
||||
before_script:
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
|
||||
script:
|
||||
- docker pull registry.gitlab.com/commento/commento-ce:latest || true
|
||||
- docker build --cache-from registry.gitlab.com/commento/commento-ce:latest --tag registry.gitlab.com/commento/commento-ce:latest .
|
||||
- docker push registry.gitlab.com/commento/commento-ce:latest
|
||||
- docker pull registry.gitlab.com/commento/commento:latest || true
|
||||
- docker build --cache-from registry.gitlab.com/commento/commento:latest --tag registry.gitlab.com/commento/commento:latest .
|
||||
- docker push registry.gitlab.com/commento/commento:latest
|
||||
|
||||
docker-registry-tags:
|
||||
stage: docker-registry-tags
|
||||
@@ -101,5 +122,5 @@ docker-registry-tags:
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
|
||||
script:
|
||||
- apk add git
|
||||
- docker build --tag registry.gitlab.com/commento/commento-ce:$(git describe --tags) .
|
||||
- docker push registry.gitlab.com/commento/commento-ce:$(git describe --tags)
|
||||
- docker build --tag registry.gitlab.com/commento/commento:$(git describe --tags) .
|
||||
- docker push registry.gitlab.com/commento/commento:$(git describe --tags)
|
||||
|
||||
37
Dockerfile
37
Dockerfile
@@ -1,10 +1,11 @@
|
||||
# backend build (api server)
|
||||
FROM golang:1.10.2-alpine AS api-build
|
||||
|
||||
COPY ./api /go/src/commento-ce/api
|
||||
WORKDIR /go/src/commento-ce/api
|
||||
COPY ./api /go/src/commento/api
|
||||
WORKDIR /go/src/commento/api
|
||||
|
||||
RUN apk update && apk add bash make git
|
||||
RUN apk update && apk add bash make git curl
|
||||
RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
|
||||
RUN make prod -j$(($(nproc) + 1))
|
||||
|
||||
@@ -12,8 +13,8 @@ RUN make prod -j$(($(nproc) + 1))
|
||||
# frontend build (html, js, css, images)
|
||||
FROM node:10.3.0-alpine AS frontend-build
|
||||
|
||||
COPY ./frontend /commento-ce/frontend/
|
||||
WORKDIR /commento-ce/frontend/
|
||||
COPY ./frontend /commento/frontend/
|
||||
WORKDIR /commento/frontend/
|
||||
|
||||
RUN apk update && apk add bash make
|
||||
RUN npm install -g html-minifier@3.5.7 uglify-js@3.4.1 sass@1.5.1
|
||||
@@ -24,8 +25,8 @@ RUN make prod -j$(($(nproc) + 1))
|
||||
# templates build
|
||||
FROM alpine:3.7 AS templates-build
|
||||
|
||||
COPY ./templates /commento-ce/templates
|
||||
WORKDIR /commento-ce/templates
|
||||
COPY ./templates /commento/templates
|
||||
WORKDIR /commento/templates
|
||||
|
||||
RUN apk update && apk add bash make
|
||||
|
||||
@@ -35,8 +36,8 @@ RUN make prod -j$(($(nproc) + 1))
|
||||
# db build
|
||||
FROM alpine:3.7 AS db-build
|
||||
|
||||
COPY ./db /commento-ce/db
|
||||
WORKDIR /commento-ce/db
|
||||
COPY ./db /commento/db
|
||||
WORKDIR /commento/db
|
||||
|
||||
RUN apk update && apk add bash make
|
||||
|
||||
@@ -46,19 +47,19 @@ RUN make prod -j$(($(nproc) + 1))
|
||||
# final image
|
||||
FROM alpine:3.7
|
||||
|
||||
COPY --from=api-build /go/src/commento-ce/api/build/prod/commento-ce /commento-ce/commento-ce
|
||||
COPY --from=frontend-build /commento-ce/frontend/build/prod/*.html /commento-ce/
|
||||
COPY --from=frontend-build /commento-ce/frontend/build/prod/css/*.css /commento-ce/css/
|
||||
COPY --from=frontend-build /commento-ce/frontend/build/prod/js/*.js /commento-ce/js/
|
||||
COPY --from=frontend-build /commento-ce/frontend/build/prod/images/* /commento-ce/images/
|
||||
COPY --from=templates-build /commento-ce/templates/build/prod/templates/ /commento-ce/templates/
|
||||
COPY --from=db-build /commento-ce/db/build/prod/db/ /commento-ce/db/
|
||||
COPY --from=api-build /go/src/commento/api/build/prod/commento /commento/commento
|
||||
COPY --from=frontend-build /commento/frontend/build/prod/*.html /commento/
|
||||
COPY --from=frontend-build /commento/frontend/build/prod/css/*.css /commento/css/
|
||||
COPY --from=frontend-build /commento/frontend/build/prod/js/*.js /commento/js/
|
||||
COPY --from=frontend-build /commento/frontend/build/prod/images/* /commento/images/
|
||||
COPY --from=templates-build /commento/templates/build/prod/templates/ /commento/templates/
|
||||
COPY --from=db-build /commento/db/build/prod/db/ /commento/db/
|
||||
|
||||
RUN apk update && apk add ca-certificates --no-cache
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR /commento-ce/
|
||||
WORKDIR /commento/
|
||||
|
||||
ENV COMMENTO_BIND_ADDRESS="0.0.0.0"
|
||||
ENTRYPOINT ["/commento-ce/commento-ce"]
|
||||
ENTRYPOINT ["/commento/commento"]
|
||||
|
||||
10
README.md
10
README.md
@@ -38,6 +38,16 @@ Commento is possible only because of its community. If this is your first contri
|
||||
|
||||
Help will always be given to those who ask for it. We use IRC for chat to collaborate with other developers. You're invited to [hang out with us](https://irc.commento.io) in the `#commento-dev` channel on freenode if you want to contribute to Commento!
|
||||
|
||||
### Sponsors
|
||||
|
||||
Commento CE development is sponsored by [Mozilla](https://mozilla.org) and [DigitalOcean](https://www.digitalocean.com/) independently.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.mozilla.org/en-US/"><img src="https://user-images.githubusercontent.com/7521600/32265838-d05b2d08-bf0a-11e7-92e1-2cb183eae616.png" title="Mozilla" height="40"></a>
|
||||
|
||||
<a href="https://www.digitalocean.com"><img src="https://user-images.githubusercontent.com/7521600/32265839-d093c7da-bf0a-11e7-8d99-96a940041d06.png" title="DigitalOcean" height="40"></a>
|
||||
</p>
|
||||
|
||||
#### License
|
||||
|
||||
```
|
||||
|
||||
9
Gopkg.lock → api/Gopkg.lock
generated
9
Gopkg.lock → api/Gopkg.lock
generated
@@ -9,6 +9,14 @@
|
||||
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
|
||||
version = "v0.26.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9769b231d8f5ff406a012aa7f293e45ed69d11617832a1c3c7b8c6ce1558a2a1"
|
||||
name = "github.com/adtac/go-akismet"
|
||||
packages = ["akismet"]
|
||||
pruneopts = "UT"
|
||||
revision = "0ca9e1023047c869ecd4bd3c20780511597a4a77"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
|
||||
name = "github.com/golang/protobuf"
|
||||
@@ -143,6 +151,7 @@
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/adtac/go-akismet/akismet",
|
||||
"github.com/gorilla/handlers",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/lib/pq",
|
||||
10
api/Makefile
10
api/Makefile
@@ -7,9 +7,9 @@ PROD_BUILD_DIR = $(BUILD_DIR)/prod
|
||||
GO_SRC_DIR = .
|
||||
GO_SRC_FILES = $(wildcard $(GO_SRC_DIR)/*.go)
|
||||
GO_DEVEL_BUILD_DIR = $(DEVEL_BUILD_DIR)
|
||||
GO_DEVEL_BUILD_BINARY = $(GO_DEVEL_BUILD_DIR)/commento-ce
|
||||
GO_DEVEL_BUILD_BINARY = $(GO_DEVEL_BUILD_DIR)/commento
|
||||
GO_PROD_BUILD_DIR = $(PROD_BUILD_DIR)
|
||||
GO_PROD_BUILD_BINARY = $(GO_PROD_BUILD_DIR)/commento-ce
|
||||
GO_PROD_BUILD_BINARY = $(GO_PROD_BUILD_DIR)/commento
|
||||
|
||||
devel: devel-go
|
||||
|
||||
@@ -25,15 +25,15 @@ clean:
|
||||
# later down the line).
|
||||
|
||||
devel-go:
|
||||
go get -v .
|
||||
dep ensure
|
||||
go build -i -v -o $(GO_DEVEL_BUILD_BINARY)
|
||||
|
||||
prod-go:
|
||||
go get -v .
|
||||
dep ensure
|
||||
go build -i -v -o $(GO_PROD_BUILD_BINARY)
|
||||
|
||||
test-go:
|
||||
go get -v .
|
||||
dep ensure
|
||||
go test -v .
|
||||
|
||||
$(shell mkdir -p $(GO_DEVEL_BUILD_DIR) $(GO_PROD_BUILD_DIR))
|
||||
|
||||
31
api/akismet.go
Normal file
31
api/akismet.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/adtac/go-akismet/akismet"
|
||||
"os"
|
||||
)
|
||||
|
||||
func isSpam(domain string, userIp string, userAgent string, name string, email string, url string, markdown string) bool {
|
||||
akismetKey := os.Getenv("AKISMET_KEY")
|
||||
if akismetKey == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
res, err := akismet.Check(&akismet.Comment{
|
||||
Blog: domain,
|
||||
UserIP: userIp,
|
||||
UserAgent: userAgent,
|
||||
CommentType: "comment",
|
||||
CommentAuthor: name,
|
||||
CommentAuthorEmail: email,
|
||||
CommentAuthorURL: url,
|
||||
CommentContent: markdown,
|
||||
}, akismetKey)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("error: cannot validate commenet using Akismet: %v", err)
|
||||
return true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
@@ -89,8 +89,12 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var state string
|
||||
|
||||
if *x.CommenterToken == "anonymous" {
|
||||
state = "unapproved"
|
||||
commenterHex = "anonymous"
|
||||
if isSpam(*x.Domain, getIp(r), getUserAgent(r), "Anonymous", "", "", *x.Markdown) {
|
||||
state = "flagged"
|
||||
} else {
|
||||
state = "unapproved"
|
||||
}
|
||||
} else {
|
||||
c, err := commenterGetByCommenterToken(*x.CommenterToken)
|
||||
if err != nil {
|
||||
@@ -111,6 +115,9 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if isModerator {
|
||||
state = "approved"
|
||||
} else {
|
||||
if isSpam(*x.Domain, getIp(r), getUserAgent(r), c.Name, c.Email, c.Link, *x.Markdown) {
|
||||
state = "flagged"
|
||||
} else {
|
||||
if d.RequireModeration {
|
||||
state = "unapproved"
|
||||
@@ -119,6 +126,7 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commentHex, err := commentNew(commenterHex, domain, path, *x.ParentHex, *x.Markdown, state, time.Now().UTC())
|
||||
if err != nil {
|
||||
@@ -126,5 +134,5 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bodyMarshal(w, response{"success": true, "commentHex": commentHex, "approved": state == "approved"})
|
||||
bodyMarshal(w, response{"success": true, "commentHex": commentHex, "state": state})
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ func configParse() error {
|
||||
"SMTP_PORT": "",
|
||||
"SMTP_FROM_ADDRESS": "",
|
||||
|
||||
"AKISMET_KEY": "",
|
||||
|
||||
"GOOGLE_KEY": "",
|
||||
"GOOGLE_SECRET": "",
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
package main
|
||||
|
||||
var edition = "ce"
|
||||
var version = "v1.1.3"
|
||||
var version = "v1.4.0"
|
||||
|
||||
@@ -60,6 +60,16 @@ func domainDelete(domain string) error {
|
||||
return errorInternal
|
||||
}
|
||||
|
||||
statement = `
|
||||
DELETE FROM pages
|
||||
WHERE pages.domain = $1;
|
||||
`
|
||||
_, err = db.Exec(statement, domain)
|
||||
if err != nil {
|
||||
logger.Errorf(statement, domain)
|
||||
return errorInternal
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ func ownerGetByOwnerToken(ownerToken string) (owner, error) {
|
||||
statement := `
|
||||
SELECT ownerHex, email, name, confirmedEmail, joinDate
|
||||
FROM owners
|
||||
WHERE email IN (
|
||||
SELECT email FROM ownerSessions
|
||||
WHERE ownerHex IN (
|
||||
SELECT ownerHex FROM ownerSessions
|
||||
WHERE ownerToken = $1
|
||||
);
|
||||
`
|
||||
|
||||
@@ -7,4 +7,5 @@ type page struct {
|
||||
Path string `json:"path"`
|
||||
IsLocked bool `json:"isLocked"`
|
||||
CommentCount int `json:"commentCount"`
|
||||
StickyCommentHex string `json:"stickyCommentHex"`
|
||||
}
|
||||
|
||||
@@ -11,20 +11,21 @@ func pageGet(domain string, path string) (page, error) {
|
||||
}
|
||||
|
||||
statement := `
|
||||
SELECT isLocked, commentCount
|
||||
SELECT isLocked, commentCount, stickyCommentHex
|
||||
FROM pages
|
||||
WHERE domain=$1 AND path=$2;
|
||||
`
|
||||
row := db.QueryRow(statement, domain, path)
|
||||
|
||||
p := page{Domain: domain, Path: path}
|
||||
if err := row.Scan(&p.IsLocked, &p.CommentCount); err != nil {
|
||||
if err := row.Scan(&p.IsLocked, &p.CommentCount, &p.StickyCommentHex); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// If there haven't been any comments, there won't be a record for this
|
||||
// page. The sane thing to do is return defaults.
|
||||
// TODO: the defaults are hard-coded in two places: here and the schema
|
||||
p.IsLocked = false
|
||||
p.CommentCount = 0
|
||||
p.StickyCommentHex = "none"
|
||||
} else {
|
||||
logger.Errorf("error scanning page: %v", err)
|
||||
return page{}, errorInternal
|
||||
|
||||
@@ -13,12 +13,12 @@ func pageUpdate(p page) error {
|
||||
// commentCount
|
||||
statement := `
|
||||
INSERT INTO
|
||||
pages (domain, path, isLocked)
|
||||
VALUES ($1, $2, $3 )
|
||||
pages (domain, path, isLocked, stickyCommentHex)
|
||||
VALUES ($1, $2, $3, $4 )
|
||||
ON CONFLICT (domain, path) DO
|
||||
UPDATE SET isLocked = $3;
|
||||
UPDATE SET isLocked = $3, stickyCommentHex = $4;
|
||||
`
|
||||
_, err := db.Exec(statement, p.Domain, p.Path, p.IsLocked)
|
||||
_, err := db.Exec(statement, p.Domain, p.Path, p.IsLocked, p.StickyCommentHex)
|
||||
if err != nil {
|
||||
logger.Errorf("error setting page attributes: %v", err)
|
||||
return errorInternal
|
||||
|
||||
@@ -1,41 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func redirectLogin(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, os.Getenv("ORIGIN")+"/login", 301)
|
||||
}
|
||||
|
||||
type staticAssetPlugs struct {
|
||||
Origin string
|
||||
}
|
||||
|
||||
type staticHtmlPlugs struct {
|
||||
type staticPlugs struct {
|
||||
Origin string
|
||||
CdnPrefix string
|
||||
Footer template.HTML
|
||||
Footer string
|
||||
}
|
||||
|
||||
var asset map[string][]byte = make(map[string][]byte)
|
||||
var contentType map[string]string = make(map[string]string)
|
||||
var footer string
|
||||
var compress bool
|
||||
|
||||
func fileDetemplate(f string) ([]byte, error) {
|
||||
contents, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot read file %s: %v", f, err)
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
x := string(contents)
|
||||
x = strings.Replace(x, "[[[.Origin]]]", os.Getenv("ORIGIN"), -1)
|
||||
x = strings.Replace(x, "[[[.CdnPrefix]]]", os.Getenv("CDN_PREFIX"), -1)
|
||||
x = strings.Replace(x, "[[[.Footer]]]", footer, -1)
|
||||
|
||||
return []byte(x), nil
|
||||
}
|
||||
|
||||
func footerInit() error {
|
||||
contents, err := fileDetemplate(os.Getenv("STATIC") + "/footer.html")
|
||||
if err != nil {
|
||||
logger.Errorf("cannot init footer: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
footer = string(contents)
|
||||
return nil
|
||||
}
|
||||
|
||||
func fileLoad(f string) ([]byte, error) {
|
||||
b, err := fileDetemplate(f)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot load file %s: %v", f, err)
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
if !compress {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
return gzipStatic(b)
|
||||
}
|
||||
|
||||
func staticRouterInit(router *mux.Router) error {
|
||||
var err error
|
||||
|
||||
subdir := pathStrip(os.Getenv("ORIGIN"))
|
||||
|
||||
asset := make(map[string][]byte)
|
||||
gzippedAsset := make(map[string][]byte)
|
||||
|
||||
for _, dir := range []string{"js", "css", "images"} {
|
||||
sl := string(os.PathSeparator)
|
||||
dir = sl + dir
|
||||
if err = footerInit(); err != nil {
|
||||
logger.Errorf("error initialising static router: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dir := range []string{"/js", "/css", "/images"} {
|
||||
files, err := ioutil.ReadDir(os.Getenv("STATIC") + dir)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot read directory %s%s: %v", os.Getenv("STATIC"), dir, err)
|
||||
@@ -43,108 +83,47 @@ func staticRouterInit(router *mux.Router) error {
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
p := dir + sl + file.Name()
|
||||
|
||||
contents, err := ioutil.ReadFile(os.Getenv("STATIC") + p)
|
||||
f := dir + "/" + file.Name()
|
||||
asset[subdir+f], err = fileLoad(os.Getenv("STATIC") + f)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot read file %s%s: %v", os.Getenv("STATIC"), p, err)
|
||||
return err
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if dir == "/js" {
|
||||
prefix = "window.commentoOrigin='" + os.Getenv("ORIGIN") + "';\n"
|
||||
prefix += "window.commentoCdn='" + os.Getenv("CDN_PREFIX") + "';\n"
|
||||
}
|
||||
|
||||
gzip := (os.Getenv("GZIP_STATIC") == "true")
|
||||
|
||||
asset[subdir+p] = []byte(prefix + string(contents))
|
||||
if gzip {
|
||||
gzippedAsset[subdir+p], err = gzipStatic(asset[subdir+p])
|
||||
if err != nil {
|
||||
logger.Errorf("error gzipping %s: %v", p, err)
|
||||
logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// faster than checking inside the handler
|
||||
if !gzip {
|
||||
router.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(path.Ext(r.URL.Path)))
|
||||
w.Write(asset[r.URL.Path])
|
||||
})
|
||||
} else {
|
||||
router.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(path.Ext(r.URL.Path)))
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Write(gzippedAsset[r.URL.Path])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer, err := ioutil.ReadFile(os.Getenv("STATIC") + string(os.PathSeparator) + "footer.html")
|
||||
if err != nil {
|
||||
logger.Errorf("cannot read file footer.html: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
pages := []string{
|
||||
"login",
|
||||
"forgot",
|
||||
"reset-password",
|
||||
"signup",
|
||||
"confirm-email",
|
||||
"dashboard",
|
||||
"logout",
|
||||
}
|
||||
|
||||
html := make(map[string]string)
|
||||
for _, page := range pages {
|
||||
html[subdir+page] = ""
|
||||
"/login",
|
||||
"/forgot",
|
||||
"/reset-password",
|
||||
"/signup",
|
||||
"/confirm-email",
|
||||
"/dashboard",
|
||||
"/logout",
|
||||
}
|
||||
|
||||
for _, page := range pages {
|
||||
sl := string(os.PathSeparator)
|
||||
page = sl + page
|
||||
file := page + ".html"
|
||||
|
||||
contents, err := ioutil.ReadFile(os.Getenv("STATIC") + file)
|
||||
f := page + ".html"
|
||||
asset[subdir+page], err = fileLoad(os.Getenv("STATIC") + f)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot read file %s%s: %v", os.Getenv("STATIC"), file, err)
|
||||
logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
|
||||
return err
|
||||
}
|
||||
|
||||
result := string(contents)
|
||||
|
||||
for {
|
||||
t, err := template.New(page).Delims("[[[", "]]]").Parse(result)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot parse %s%s template: %v", os.Getenv("STATIC"), file, err)
|
||||
return err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
t.Execute(&buf, &staticHtmlPlugs{
|
||||
Origin: os.Getenv("ORIGIN"),
|
||||
CdnPrefix: os.Getenv("CDN_PREFIX"),
|
||||
Footer: template.HTML(string(footer)),
|
||||
})
|
||||
|
||||
result = buf.String()
|
||||
if result == html[subdir+page] {
|
||||
break
|
||||
for p, _ := range asset {
|
||||
if path.Ext(p) != "" {
|
||||
contentType[p] = mime.TypeByExtension(path.Ext(p))
|
||||
} else {
|
||||
html[subdir+page] = result
|
||||
continue
|
||||
}
|
||||
}
|
||||
contentType[p] = mime.TypeByExtension("html")
|
||||
}
|
||||
|
||||
for _, page := range pages {
|
||||
router.HandleFunc("/"+page, func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, html[r.URL.Path])
|
||||
router.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", contentType[r.URL.Path])
|
||||
if compress {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
}
|
||||
w.Write(asset[r.URL.Path])
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -43,3 +43,16 @@ func bodyMarshal(w http.ResponseWriter, x map[string]interface{}) error {
|
||||
w.Write(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIp(r *http.Request) string {
|
||||
ip := r.RemoteAddr
|
||||
if r.Header.Get("X-Forwarded-For") != "" {
|
||||
ip = r.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
|
||||
func getUserAgent(r *http.Request) string {
|
||||
return r.Header.Get("User-Agent")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -14,13 +13,12 @@ func versionCheckStart() error {
|
||||
go func() {
|
||||
printedError := false
|
||||
errorCount := 0
|
||||
latestSeen := ""
|
||||
|
||||
for {
|
||||
time.Sleep(5 * time.Minute)
|
||||
|
||||
data := url.Values{
|
||||
"origin": {os.Getenv("ORIGIN")},
|
||||
"edition": {edition},
|
||||
"version": {version},
|
||||
}
|
||||
|
||||
@@ -65,8 +63,9 @@ func versionCheckStart() error {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.NewUpdate {
|
||||
if r.NewUpdate && r.Latest != latestSeen {
|
||||
logger.Infof("New update available! Latest version: %s", r.Latest)
|
||||
latestSeen = r.Latest
|
||||
}
|
||||
|
||||
errorCount = 0
|
||||
|
||||
7
db/20181007230906-store-version.sql
Normal file
7
db/20181007230906-store-version.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
version TEXT NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
config (version)
|
||||
VALUES ('v1.1.3');
|
||||
2
db/20181007231407-v1.1.4.sql
Normal file
2
db/20181007231407-v1.1.4.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
UPDATE config
|
||||
SET version = 'v1.2.0';
|
||||
2
db/20181218183803-sticky-comments.sql
Normal file
2
db/20181218183803-sticky-comments.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE pages
|
||||
ADD stickyCommentHex TEXT NOT NULL DEFAULT 'none';
|
||||
2
db/20181228114101-v1.4.0.sql
Normal file
2
db/20181228114101-v1.4.0.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
UPDATE config
|
||||
SET version = 'v1.4.0';
|
||||
@@ -2,7 +2,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
server:
|
||||
image: registry.gitlab.com/commento/commento-ce
|
||||
image: registry.gitlab.com/commento/commento
|
||||
ports:
|
||||
- 8080:8080
|
||||
environment:
|
||||
|
||||
28
etc/bsd-rc/commento
Executable file
28
etc/bsd-rc/commento
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
# PROVIDE: commento
|
||||
# REQUIRE: LOGIN postgresql
|
||||
# KEYWORD: shutdown
|
||||
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
desc="Commento daemon"
|
||||
name=commento
|
||||
rcvar=commento_enable
|
||||
|
||||
load_rc_config $name
|
||||
|
||||
: ${commento_enable:=NO}
|
||||
|
||||
commento_env="COMMENTO_ORIGIN=https://commento.example.com \
|
||||
COMMENTO_PORT=8080 \
|
||||
COMMENTO_POSTGRES=postgres://commento:commento@db:5432/commento?sslmode=disable \
|
||||
COMMENTO_STATIC=/usr/local/share/commento"
|
||||
commento_user=www
|
||||
|
||||
command="/usr/local/bin/commento"
|
||||
command_args=" >> /var/log/commento/${name}.log 2>&1 &"
|
||||
|
||||
run_rc_command "$1"
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# PROVIDE: commento_ce
|
||||
# REQUIRE: LOGIN postgresql
|
||||
# KEYWORD: shutdown
|
||||
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
desc="Commento CE daemon"
|
||||
name=commento_ce
|
||||
rcvar=commento_ce_enable
|
||||
|
||||
load_rc_config $name
|
||||
|
||||
: ${commento_ce_enable:=NO}
|
||||
|
||||
commento_ce_env="COMMENTO_ORIGIN=https://commento.example.com \
|
||||
COMMENTO_PORT=8080 \
|
||||
COMMENTO_POSTGRES=postgres://commento:commento@db:5432/commento?sslmode=disable \
|
||||
COMMENTO_STATIC=/usr/local/share/commento-ce"
|
||||
commento_ce_user=www
|
||||
|
||||
command="/usr/local/bin/commento-ce"
|
||||
command_args=" >> /var/log/commento_ce/${name}.log 2>&1 &"
|
||||
|
||||
run_rc_command "$1"
|
||||
@@ -1,14 +1,14 @@
|
||||
[Unit]
|
||||
Description=Commento-CE daemon service
|
||||
Description=Commento daemon service
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/commento-ce
|
||||
ExecStart=/usr/bin/commento
|
||||
Environment=COMMENTO_ORIGIN=https://commento.example.com
|
||||
Environment=COMMENTO_PORT=8080
|
||||
Environment=COMMENTO_POSTGRES=postgres://commento:commento@db:5432/commento?sslmode=disable
|
||||
Environment=COMMENTO_STATIC=/usr/share/commento-ce
|
||||
Environment=COMMENTO_STATIC=/usr/share/commento
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
33
frontend/.eslintrc
Normal file
33
frontend/.eslintrc
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"$": true
|
||||
},
|
||||
"rules": {
|
||||
"no-bitwise": 2,
|
||||
"camelcase": 2,
|
||||
"brace-style": ["error", "1tbs"],
|
||||
"curly": ["error", "all"],
|
||||
"eqeqeq": ["error", "smart"],
|
||||
"indent": ["error", 2],
|
||||
"no-use-before-define": [
|
||||
2,
|
||||
{
|
||||
"functions": false
|
||||
}
|
||||
],
|
||||
"new-cap": 2,
|
||||
"no-caller": 2,
|
||||
"quotes": [
|
||||
2,
|
||||
"double"
|
||||
],
|
||||
"no-unused-vars": 2,
|
||||
"strict": [
|
||||
2,
|
||||
"function"
|
||||
]
|
||||
}
|
||||
}
|
||||
1
frontend/.gitignore
vendored
1
frontend/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.sass-cache
|
||||
node_modules/
|
||||
|
||||
@@ -1,117 +1,13 @@
|
||||
SHELL = bash
|
||||
|
||||
# list of JS files to be built
|
||||
JS_BUILD = jquery.js vue.js highlight.js chartist.js login.js forgot.js reset.js signup.js dashboard.js logout.js commento.js
|
||||
|
||||
jquery.js = jquery.js
|
||||
vue.js = vue.js
|
||||
highlight.js = highlight.js
|
||||
chartist.js = chartist.js
|
||||
login.js = utils.js http.js auth-common.js login.js
|
||||
forgot.js = utils.js http.js forgot.js
|
||||
reset.js = utils.js http.js reset.js
|
||||
signup.js = utils.js http.js auth-common.js signup.js
|
||||
dashboard.js = utils.js http.js errors.js self.js dashboard.js dashboard-setting.js dashboard-domain.js dashboard-installation.js dashboard-general.js dashboard-moderation.js dashboard-statistics.js dashboard-import.js dashboard-danger.js
|
||||
logout.js = utils.js logout.js
|
||||
commento.js = commento.js
|
||||
|
||||
# for each file in $(JS_BUILD), list its composition
|
||||
|
||||
BUILD_DIR = build
|
||||
DEVEL_BUILD_DIR = $(BUILD_DIR)/devel
|
||||
PROD_BUILD_DIR = $(BUILD_DIR)/prod
|
||||
GULP = node_modules/.bin/gulp
|
||||
|
||||
HTML_SRC_DIR = .
|
||||
HTML_SRC_FILES = $(wildcard $(HTML_SRC_DIR)/*.html)
|
||||
HTML_DEVEL_BUILD_DIR = $(DEVEL_BUILD_DIR)
|
||||
HTML_DEVEL_BUILD_FILES = $(patsubst $(HTML_SRC_DIR)/%, $(HTML_DEVEL_BUILD_DIR)/%, $(HTML_SRC_FILES))
|
||||
HTML_PROD_BUILD_DIR = $(PROD_BUILD_DIR)
|
||||
HTML_PROD_BUILD_FILES = $(patsubst $(HTML_SRC_DIR)/%, $(HTML_PROD_BUILD_DIR)/%, $(HTML_SRC_FILES))
|
||||
devel:
|
||||
yarn install
|
||||
$(GULP) devel
|
||||
|
||||
HTML_MINIFIER = html-minifier
|
||||
HTML_MINIFIER_FLAGS = --collapse-whitespace --remove-comments
|
||||
|
||||
JS_SRC_DIR = js
|
||||
JS_SRC_FILES = $(wildcard $(JS_SRC_DIR)/*.js)
|
||||
JS_DEVEL_BUILD_DIR = $(DEVEL_BUILD_DIR)/js
|
||||
JS_DEVEL_BUILD_FILES = $(addprefix $(JS_DEVEL_BUILD_DIR)/, $(JS_BUILD))
|
||||
JS_PROD_BUILD_DIR = $(PROD_BUILD_DIR)/js
|
||||
JS_PROD_BUILD_FILES = $(addprefix $(JS_PROD_BUILD_DIR)/, $(JS_BUILD))
|
||||
|
||||
JS_MINIFIER = uglifyjs
|
||||
JS_MINIFIER_FLAGS = --compress --mangle
|
||||
|
||||
SASS_SRC_DIR = sass
|
||||
SASS_SRC_FILES = $(wildcard $(SASS_SRC_DIR)/*.scss)
|
||||
CSS_DEVEL_BUILD_DIR = $(DEVEL_BUILD_DIR)/css
|
||||
CSS_DEVEL_BUILD_FILES = $(patsubst $(SASS_SRC_DIR)/%.scss, $(CSS_DEVEL_BUILD_DIR)/%.css, $(SASS_SRC_FILES))
|
||||
CSS_PROD_BUILD_DIR = $(PROD_BUILD_DIR)/css
|
||||
CSS_PROD_BUILD_FILES = $(patsubst $(SASS_SRC_DIR)/%.scss, $(CSS_PROD_BUILD_DIR)/%.css, $(SASS_SRC_FILES))
|
||||
|
||||
CSS = sass
|
||||
CSS_DEVEL_FLAGS =
|
||||
CSS_PROD_FLAGS = $(CSS_DEVEL_FLAGS) --style compressed
|
||||
|
||||
IMGS_SRC_DIR = images
|
||||
IMGS_SRC_FILES = $(wildcard $(IMGS_SRC_DIR)/*)
|
||||
IMGS_DEVEL_BUILD_DIR = $(DEVEL_BUILD_DIR)/images
|
||||
IMGS_DEVEL_BUILD_FILES = $(patsubst $(IMGS_SRC_DIR)/%, $(IMGS_DEVEL_BUILD_DIR)/%, $(IMGS_SRC_FILES))
|
||||
IMGS_PROD_BUILD_DIR = $(PROD_BUILD_DIR)/images
|
||||
IMGS_PROD_BUILD_FILES = $(patsubst $(IMGS_SRC_DIR)/%, $(IMGS_PROD_BUILD_DIR)/%, $(IMGS_SRC_FILES))
|
||||
|
||||
devel: devel-html devel-js devel-css devel-imgs
|
||||
|
||||
prod: devel prod-html prod-js prod-css prod-imgs
|
||||
prod:
|
||||
yarn install
|
||||
$(GULP) prod
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILD_DIR);
|
||||
|
||||
devel-html: $(HTML_DEVEL_BUILD_FILES)
|
||||
|
||||
$(HTML_DEVEL_BUILD_FILES): $(HTML_DEVEL_BUILD_DIR)/%.html: $(HTML_SRC_DIR)/%.html
|
||||
cp $^ $@;
|
||||
|
||||
prod-html: $(HTML_PROD_BUILD_FILES)
|
||||
|
||||
$(HTML_PROD_BUILD_FILES): $(HTML_PROD_BUILD_DIR)/%.html: $(HTML_DEVEL_BUILD_DIR)/%.html
|
||||
$(HTML_MINIFIER) $(HTML_MINIFIER_FLAGS) -o $@ $^;
|
||||
|
||||
devel-js: $(JS_DEVEL_BUILD_FILES)
|
||||
|
||||
.SECONDEXPANSION:
|
||||
$(JS_DEVEL_BUILD_FILES): $(JS_DEVEL_BUILD_DIR)/%.js: $$(addprefix $$(JS_SRC_DIR)/, $$(%.js))
|
||||
>$@; \
|
||||
for f in $^; do \
|
||||
printf "// %s\n" "$$f" >>$@; \
|
||||
cat $$f >>$@; \
|
||||
printf "\n" >>$@; \
|
||||
done;
|
||||
|
||||
prod-js: $(JS_PROD_BUILD_FILES)
|
||||
|
||||
$(JS_PROD_BUILD_FILES): $(JS_PROD_BUILD_DIR)/%.js: $(JS_DEVEL_BUILD_DIR)/%.js
|
||||
$(JS_MINIFIER) $(JS_MINIFIER_FLAGS) -o $@ $^;
|
||||
|
||||
devel-css: $(CSS_DEVEL_BUILD_FILES)
|
||||
|
||||
$(CSS_DEVEL_BUILD_FILES): $(CSS_DEVEL_BUILD_DIR)/%.css: $(SASS_SRC_DIR)/%.scss $(SASS_SRC_FILES)
|
||||
$(CSS) $(CSS_DEVEL_FLAGS) $< $@;
|
||||
|
||||
prod-css: $(CSS_PROD_BUILD_FILES)
|
||||
|
||||
$(CSS_PROD_BUILD_FILES): $(CSS_PROD_BUILD_DIR)/%.css: $(SASS_SRC_DIR)/%.scss
|
||||
$(CSS) $(CSS_PROD_FLAGS) $^ $@;
|
||||
|
||||
$(shell mkdir -p $(HTML_DEVEL_BUILD_DIR) $(JS_DEVEL_BUILD_DIR) $(CSS_DEVEL_BUILD_DIR) $(HTML_PROD_BUILD_DIR) $(JS_PROD_BUILD_DIR) $(CSS_PROD_BUILD_DIR))
|
||||
|
||||
devel-imgs: $(IMGS_DEVEL_BUILD_FILES)
|
||||
|
||||
$(IMGS_DEVEL_BUILD_FILES): $(IMGS_DEVEL_BUILD_DIR)/%: $(IMGS_SRC_DIR)/%
|
||||
cp $^ $@;
|
||||
|
||||
prod-imgs: $(IMGS_PROD_BUILD_FILES)
|
||||
|
||||
$(IMGS_PROD_BUILD_FILES): $(IMGS_PROD_BUILD_DIR)/%: $(IMGS_SRC_DIR)/%
|
||||
cp $^ $@
|
||||
|
||||
$(shell mkdir -p $(HTML_DEVEL_BUILD_DIR) $(JS_DEVEL_BUILD_DIR) $(CSS_DEVEL_BUILD_DIR) $(IMGS_DEVEL_BUILD_DIR) $(HTML_PROD_BUILD_DIR) $(JS_PROD_BUILD_DIR) $(CSS_PROD_BUILD_DIR) $(IMGS_PROD_BUILD_DIR))
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.selfGet(function() {
|
||||
window.vueConstruct(function() {
|
||||
window.navbarFill();
|
||||
window.domainRefresh();
|
||||
window.commento.selfGet(function() {
|
||||
window.commento.vueConstruct(function() {
|
||||
window.commento.navbarFill();
|
||||
window.commento.domainRefresh();
|
||||
$(document).ready(function(){
|
||||
$("ul.tabs li").click(function(){
|
||||
var tab_id = $(this).attr("data-tab");
|
||||
@@ -51,13 +51,13 @@
|
||||
It's so quiet in here.
|
||||
</div>
|
||||
|
||||
<div class="pane-setting" v-for="domain in domains" v-on:click="window.domainSelect(domain.domain)" id="{{domain.hex}}" v-bind:class="{selected: domain.selected}" v-if="domain.show">
|
||||
<div class="pane-setting" v-for="domain in domains" v-on:click="window.commento.domainSelect(domain.domain)" id="{{domain.hex}}" v-bind:class="{selected: domain.selected}" v-if="domain.show">
|
||||
<div class="pane-setting-inside">
|
||||
<div class="setting-title">{{domain.name}}</div>
|
||||
<div class="setting-subtitle">{{domain.domain}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-setting" id="domain-add" onclick="window.location.hash='#new-domain-modal'">
|
||||
<div class="pane-setting" id="domain-add" onclick="document.location.hash='#new-domain-modal'">
|
||||
<div class="pane-setting-inside super-setting">
|
||||
<div class="super-setting-title">+</div>
|
||||
<div class="super-setting-text">New Domain</div>
|
||||
@@ -66,7 +66,7 @@
|
||||
</div>
|
||||
|
||||
<div class="pane-middle">
|
||||
<div v-if="showSettings" class="pane-setting" v-for="setting in settings" v-on:click="window.settingSelect(setting.id)" id="{{setting.id}}" v-bind:class="{selected: setting.selected}">
|
||||
<div v-if="showSettings" class="pane-setting" v-for="setting in settings" v-on:click="window.commento.settingSelect(setting.id)" id="{{setting.id}}" v-bind:class="{selected: setting.selected}">
|
||||
<div class="pane-setting-inside">
|
||||
<div class="setting-title">{{setting.text}}</div>
|
||||
<div class="setting-subtitle">{{setting.meaning}}</div>
|
||||
@@ -156,14 +156,14 @@
|
||||
<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>
|
||||
<button id="new-mod-button" class="commento-email-button" onclick="window.commento.moderatorNewHandler()">Add moderator</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mod-emails-container">
|
||||
<div class="content">
|
||||
<div class="mod-email" v-for="email in domains[cd].moderators" v-if="domains[cd].moderators.length > 0">
|
||||
<div class="email">{{email.email}}</div>
|
||||
<div class="delete" v-on:click="window.moderatorDeleteHandler(email.email)">Delete</div>
|
||||
<div class="delete" v-on:click="window.commento.moderatorDeleteHandler(email.email)">Delete</div>
|
||||
<div class="date">added {{email.timeAgo}}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -215,7 +215,7 @@
|
||||
<div id="new-domain-error" class="modal-error-box"></div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<button id="save-general-button" onclick="window.generalSaveHandler()" class="button">Save Changes</button>
|
||||
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -247,7 +247,7 @@
|
||||
<div class="commento-email-container">
|
||||
<div class="commento-email">
|
||||
<input class="commento-input" type="text" id="disqus-url" placeholder="https://media.disqus.com/uploads/...">
|
||||
<button id="disqus-import-button" class="commento-email-button" onclick="importDisqus()">Import</button>
|
||||
<button id="disqus-import-button" class="commento-email-button" onclick="window.commento.importDisqus()">Import</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="subtext-container">
|
||||
@@ -286,7 +286,7 @@
|
||||
If you desire to re-allow comments again on your website, you can do so. You can, of course, freeze the site again in the future.
|
||||
</div>
|
||||
|
||||
<button onclick="window.location.hash='#unfreeze-domain-modal'" class="button green-button">Unfreeze Domain</button>
|
||||
<button onclick="document.location.hash='#unfreeze-domain-modal'" class="button green-button">Unfreeze Domain</button>
|
||||
</div>
|
||||
|
||||
<div class="box" v-if="domains[cd].state != 'frozen'">
|
||||
@@ -294,7 +294,7 @@
|
||||
If you desire to temporarily freeze new comments (domain-wide), thereby making it read-only, you can do so. You can choose to unfreeze later; this is temporary.
|
||||
</div>
|
||||
|
||||
<button id="orange-button" onclick="window.location.hash='#freeze-domain-modal'" class="button orange-button">Freeze Domain</button>
|
||||
<button id="orange-button" onclick="document.location.hash='#freeze-domain-modal'" class="button orange-button">Freeze Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -305,7 +305,7 @@
|
||||
Want to completely remove Commento from your website? This will permanently delete all comments and there is literally no way to retrieve your data once you do this.
|
||||
</div>
|
||||
|
||||
<button id="big-red-button" class="button big-red-button" onclick="window.location.hash='#delete-domain-modal'">Delete Domain</button>
|
||||
<button id="big-red-button" class="button big-red-button" onclick="document.location.hash='#delete-domain-modal'">Delete Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -323,7 +323,7 @@
|
||||
Are you absolutely sure you want to freeze your domain, thereby making it read-only? You can choose to unfreeze later; this is temporary.
|
||||
</div>
|
||||
<div class="modal-contents">
|
||||
<button id="orange-button" class="button orange-button" onclick="window.domainFreezeHandler()">Freeze Domain</button>
|
||||
<button id="orange-button" class="button orange-button" onclick="window.commento.domainFreezeHandler()">Freeze Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -336,7 +336,7 @@
|
||||
Are you absolutely sure you want to unfreeze your domain? This will re-allow new comments. You can choose to freeze again in the future.
|
||||
</div>
|
||||
<div class="modal-contents">
|
||||
<button id="blue-button" class="button green-button" onclick="window.domainUnfreezeHandler()">Unfreeze Domain</button>
|
||||
<button id="blue-button" class="button green-button" onclick="window.commento.domainUnfreezeHandler()">Unfreeze Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -349,7 +349,7 @@
|
||||
Are you absolutely sure? This will permanently delete all comments and there is literally no way to retrieve your data once you do this.
|
||||
</div>
|
||||
<div class="modal-contents">
|
||||
<button id="big-red-button" class="button big-red-button" onclick="window.domainDeleteHandler()">Delete Domain</button>
|
||||
<button id="big-red-button" class="button big-red-button" onclick="window.commento.domainDeleteHandler()">Delete Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -374,7 +374,7 @@
|
||||
</div>
|
||||
<div id="new-domain-error" class="modal-error-box"></div>
|
||||
<div class="center">
|
||||
<button id="add-site-button" onclick="window.domainNewHandler()" class="button">Add Domain</button>
|
||||
<button id="add-site-button" onclick="window.commento.domainNewHandler()" class="button">Add Domain</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<div class="err" id="err"></div>
|
||||
<div class="msg" id="msg"></div>
|
||||
<button id="reset-button" class="button" onclick="sendResetHex()">Send Reset Password Link</button>
|
||||
<button id="reset-button" class="button" onclick="window.commento.sendResetHex()">Send Reset Password Link</button>
|
||||
<a class="link" href="[[[.Origin]]]/login">Suddenly remembered your password? Login.</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
139
frontend/gulpfile.js
Normal file
139
frontend/gulpfile.js
Normal file
@@ -0,0 +1,139 @@
|
||||
"use strict";
|
||||
|
||||
const gulp = require("gulp");
|
||||
const sass = require("gulp-sass");
|
||||
const sourcemaps = require("gulp-sourcemaps");
|
||||
const cleanCss = require("gulp-clean-css");
|
||||
const htmlMinifier = require("gulp-html-minifier");
|
||||
const uglify = require("gulp-uglify");
|
||||
const concat = require("gulp-concat");
|
||||
const rename = require("gulp-rename");
|
||||
const eslint = require("gulp-eslint");
|
||||
|
||||
const develPath = "build/devel/";
|
||||
const prodPath = "build/prod/";
|
||||
const scssSrc = "./sass/*.scss";
|
||||
const cssDir = "css/";
|
||||
const imagesDir = "images/";
|
||||
const imagesGlob = imagesDir + "**/*";
|
||||
const jsDir = "js/";
|
||||
const jsGlob = jsDir + "*.js";
|
||||
const htmlGlob = "./*.html";
|
||||
|
||||
const jsCompileMap = {
|
||||
"js/jquery.js": ["node_modules/jquery/dist/jquery.min.js"],
|
||||
"js/vue.js": ["node_modules/vue/dist/vue.min.js"],
|
||||
"js/highlight.js": ["node_modules/highlightjs/highlight.pack.min.js"],
|
||||
"js/chartist.js": ["node_modules/chartist/dist/chartist.min.js"],
|
||||
"js/login.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/http.js",
|
||||
"js/auth-common.js",
|
||||
"js/login.js"
|
||||
],
|
||||
"js/forgot.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/http.js",
|
||||
"js/forgot.js"
|
||||
],
|
||||
"js/reset.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/http.js",
|
||||
"js/reset.js"
|
||||
],
|
||||
"js/signup.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/http.js",
|
||||
"js/auth-common.js",
|
||||
"js/signup.js"
|
||||
],
|
||||
"js/dashboard.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/http.js",
|
||||
"js/errors.js",
|
||||
"js/self.js",
|
||||
"js/dashboard.js",
|
||||
"js/dashboard-setting.js",
|
||||
"js/dashboard-domain.js",
|
||||
"js/dashboard-installation.js",
|
||||
"js/dashboard-general.js",
|
||||
"js/dashboard-moderation.js",
|
||||
"js/dashboard-statistics.js",
|
||||
"js/dashboard-import.js",
|
||||
"js/dashboard-danger.js",
|
||||
],
|
||||
"js/logout.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
"js/logout.js"
|
||||
],
|
||||
"js/commento.js": ["js/commento.js"],
|
||||
};
|
||||
|
||||
gulp.task("scss-devel", function () {
|
||||
return gulp.src(scssSrc)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(sass({outputStyle: "expanded"}).on("error", sass.logError))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest(develPath + cssDir));
|
||||
});
|
||||
|
||||
gulp.task("scss-prod", function () {
|
||||
return gulp.src(scssSrc)
|
||||
.pipe(sass({outputStyle: "compressed"}).on("error", sass.logError))
|
||||
.pipe(cleanCss({compatibility: "ie8", level: 2}))
|
||||
.pipe(gulp.dest(prodPath + cssDir));
|
||||
});
|
||||
|
||||
gulp.task("html-devel", function () {
|
||||
gulp.src([htmlGlob]).pipe(gulp.dest(develPath));
|
||||
});
|
||||
|
||||
gulp.task("html-prod", function () {
|
||||
gulp.src(htmlGlob)
|
||||
.pipe(htmlMinifier({collapseWhitespace: true, removeComments: true}))
|
||||
.pipe(gulp.dest(prodPath))
|
||||
});
|
||||
|
||||
gulp.task("images-devel", function () {
|
||||
gulp.src([imagesGlob]).pipe(gulp.dest(develPath + imagesDir));
|
||||
});
|
||||
|
||||
gulp.task("images-prod", function () {
|
||||
gulp.src([imagesGlob]).pipe(gulp.dest(prodPath + imagesDir));
|
||||
});
|
||||
|
||||
gulp.task("js-devel", function () {
|
||||
for (let outputFile in jsCompileMap) {
|
||||
gulp.src(jsCompileMap[outputFile])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat(outputFile))
|
||||
.pipe(rename(outputFile))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest(develPath))
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task("js-prod", function () {
|
||||
for (let outputFile in jsCompileMap) {
|
||||
gulp.src(jsCompileMap[outputFile])
|
||||
.pipe(concat(outputFile))
|
||||
.pipe(rename(outputFile))
|
||||
.pipe(uglify())
|
||||
.pipe(gulp.dest(prodPath))
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task("lint", function () {
|
||||
return gulp.src(jsGlob)
|
||||
.pipe(eslint())
|
||||
.pipe(eslint.failAfterError())
|
||||
});
|
||||
|
||||
gulp.task("devel", ["scss-devel", "html-devel", "images-devel", "lint", "js-devel"]);
|
||||
gulp.task("prod", ["scss-prod", "html-prod", "images-prod", "lint", "js-prod"]);
|
||||
@@ -1,20 +1,22 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
// Redirect the user to the dashboard if there's a cookie. If the cookie is
|
||||
// invalid, they would be redirected back to the login page *after* the
|
||||
// cookie is deleted.
|
||||
global.loggedInRedirect = function() {
|
||||
if (global.cookieGet("commentoOwnerToken") !== undefined)
|
||||
document.location = global.commentoOrigin + "/dashboard";
|
||||
if (global.cookieGet("commentoOwnerToken") !== undefined) {
|
||||
document.location = global.origin + "/dashboard";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Prefills the email field from the URL parameter.
|
||||
global.prefillEmail = function() {
|
||||
if (paramGet("email") != undefined) {
|
||||
if (paramGet("email") !== undefined) {
|
||||
$("#email").val(paramGet("email"));
|
||||
$("#password").click();
|
||||
}
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
13
frontend/js/constants.js
Normal file
13
frontend/js/constants.js
Normal file
@@ -0,0 +1,13 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
if (window.commento === undefined) {
|
||||
window.commento = {};
|
||||
}
|
||||
|
||||
window.commento.origin = "[[[.Origin]]]";
|
||||
window.commento.cdn = "[[[.CdnPrefix]]]";
|
||||
|
||||
} (window, document));
|
||||
@@ -1,4 +1,5 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
// Opens the danger zone.
|
||||
global.dangerOpen = function() {
|
||||
@@ -11,9 +12,10 @@
|
||||
global.domainDeleteHandler = function() {
|
||||
var data = global.dashboard.$data;
|
||||
|
||||
domainDelete(data.domains[data.cd].domain, function(success) {
|
||||
if (success)
|
||||
document.location = global.commentoOrigin + '/dashboard';
|
||||
global.domainDelete(data.domains[data.cd].domain, function(success) {
|
||||
if (success) {
|
||||
document.location = global.origin + "/dashboard";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +25,7 @@
|
||||
var data = global.dashboard.$data;
|
||||
|
||||
data.domains[data.cd].state = "frozen"
|
||||
domainUpdate(data.domains[data.cd])
|
||||
global.domainUpdate(data.domains[data.cd])
|
||||
document.location.hash = "#modal-close";
|
||||
}
|
||||
|
||||
@@ -33,9 +35,9 @@
|
||||
var data = global.dashboard.$data;
|
||||
|
||||
data.domains[data.cd].state = "unfrozen"
|
||||
domainUpdate(data.domains[data.cd])
|
||||
global.domainUpdate(data.domains[data.cd])
|
||||
document.location.hash = "#modal-close";
|
||||
}
|
||||
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
// Selects a domain.
|
||||
global.domainSelect = function(domain) {
|
||||
@@ -6,19 +7,19 @@
|
||||
var domains = data.domains;
|
||||
|
||||
for (var i = 0; i < domains.length; i++) {
|
||||
if (domains[i].domain == domain) {
|
||||
vs("frozen", domains[i].state == "frozen");
|
||||
if (domains[i].domain === domain) {
|
||||
global.vs("frozen", domains[i].state === "frozen");
|
||||
domains[i].selected = true;
|
||||
data.cd = i;
|
||||
data.importedComments = domains[i].importedComments;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
domains[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
data.showSettings = true;
|
||||
|
||||
settingDeselectAll();
|
||||
global.settingDeselectAll();
|
||||
$(".view").hide();
|
||||
};
|
||||
|
||||
@@ -28,9 +29,10 @@
|
||||
var data = global.dashboard.$data;
|
||||
var domains = data.domains;
|
||||
|
||||
for (var i = 0; i < domains.length; i++)
|
||||
for (var i = 0; i < domains.length; i++) {
|
||||
domains[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Creates a new domain.
|
||||
@@ -42,7 +44,7 @@
|
||||
}
|
||||
|
||||
global.buttonDisable("#add-site-button");
|
||||
global.post(global.commentoOrigin + "/api/domain/new", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/new", json, function(resp) {
|
||||
global.buttonEnable("#add-site-button");
|
||||
|
||||
$("#new-domain-name").val("");
|
||||
@@ -69,7 +71,7 @@
|
||||
"ownerToken": global.cookieGet("commentoOwnerToken"),
|
||||
};
|
||||
|
||||
global.post(global.commentoOrigin + "/api/domain/list", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/list", json, function(resp) {
|
||||
if (!resp.success) {
|
||||
global.globalErrorShow(resp.message);
|
||||
return;
|
||||
@@ -98,8 +100,9 @@
|
||||
|
||||
global.vs("domains", resp.domains);
|
||||
|
||||
if (callback !== undefined)
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -111,9 +114,10 @@
|
||||
"domain": domain,
|
||||
};
|
||||
|
||||
global.post(global.commentoOrigin + "/api/domain/update", json, function(resp) {
|
||||
if (callback !== undefined)
|
||||
global.post(global.origin + "/api/domain/update", json, function(resp) {
|
||||
if (callback !== undefined) {
|
||||
callback(resp.success);
|
||||
}
|
||||
|
||||
if (!resp.success) {
|
||||
global.globalErrorShow(resp.message);
|
||||
@@ -130,15 +134,16 @@
|
||||
"domain": domain,
|
||||
};
|
||||
|
||||
global.post(global.commentoOrigin + "/api/domain/delete", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/delete", json, function(resp) {
|
||||
if (!resp.success) {
|
||||
global.globalErrorShow(resp.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback !== undefined)
|
||||
if (callback !== undefined) {
|
||||
callback(resp.success);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Opens the general settings window.
|
||||
global.generalOpen = function() {
|
||||
@@ -16,4 +19,4 @@
|
||||
});
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Opens the import window.
|
||||
global.importOpen = function() {
|
||||
@@ -6,7 +9,6 @@
|
||||
$("#import-view").show();
|
||||
}
|
||||
|
||||
|
||||
global.importDisqus = function() {
|
||||
var url = $("#disqus-url").val();
|
||||
var data = global.dashboard.$data;
|
||||
@@ -18,7 +20,7 @@
|
||||
}
|
||||
|
||||
global.buttonDisable("#disqus-import-button");
|
||||
global.post(global.commentoOrigin + "/api/domain/import/disqus", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/import/disqus", json, function(resp) {
|
||||
global.buttonEnable("#disqus-import-button");
|
||||
|
||||
if (!resp.success) {
|
||||
@@ -28,8 +30,8 @@
|
||||
|
||||
$("#disqus-import-button").hide();
|
||||
|
||||
globalOKShow("Imported " + resp.numImported + " comments!");
|
||||
global.globalOKShow("Imported " + resp.numImported + " comments!");
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Opens the installation view.
|
||||
global.installationOpen = function() {
|
||||
var data = global.dashboard.$data;
|
||||
|
||||
var html = '' +
|
||||
'<div id="commento"></div>\n' +
|
||||
'<script src="' + window.commentoCdn + '/js/commento.js"><\/script>\n' +
|
||||
'';
|
||||
var html = "" +
|
||||
"<div id=\"commento\"></div>\n" +
|
||||
"<script src=\"" + global.cdn + "/js/commento.js\"><\/script>\n" +
|
||||
"";
|
||||
|
||||
$("#code-div").text(html);
|
||||
|
||||
$('pre code').each(function(i, block) {
|
||||
$("pre code").each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
|
||||
@@ -19,4 +20,4 @@
|
||||
$("#installation-view").show();
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Opens the moderatiosn settings window.
|
||||
global.moderationOpen = function() {
|
||||
@@ -20,16 +23,16 @@
|
||||
|
||||
var idx = -1;
|
||||
for (var i = 0; i < data.domains[data.cd].moderators.length; i++) {
|
||||
if (data.domains[data.cd].moderators[i].email == email) {
|
||||
if (data.domains[data.cd].moderators[i].email === email) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
if (idx === -1) {
|
||||
data.domains[data.cd].moderators.push({"email": email, "timeAgo": "just now"});
|
||||
global.buttonDisable("#new-mod-button");
|
||||
global.post(global.commentoOrigin + "/api/domain/moderator/new", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/moderator/new", json, function(resp) {
|
||||
global.buttonEnable("#new-mod-button");
|
||||
|
||||
if (!resp.success) {
|
||||
@@ -41,8 +44,7 @@
|
||||
$("#new-mod").val("");
|
||||
$("#new-mod").focus();
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
global.globalErrorShow("Already a moderator.");
|
||||
}
|
||||
}
|
||||
@@ -60,23 +62,23 @@
|
||||
|
||||
var idx = -1;
|
||||
for (var i = 0; i < data.domains[data.cd].moderators.length; i++) {
|
||||
if (data.domains[data.cd].moderators[i].email == email) {
|
||||
if (data.domains[data.cd].moderators[i].email === email) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx != -1) {
|
||||
if (idx !== -1) {
|
||||
data.domains[data.cd].moderators.splice(idx, 1);
|
||||
global.post(global.commentoOrigin + "/api/domain/moderator/delete", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/moderator/delete", json, function(resp) {
|
||||
if (!resp.success) {
|
||||
global.globalErrorShow(resp.message);
|
||||
return
|
||||
}
|
||||
|
||||
globalOKShow("Removed!");
|
||||
global.globalOKShow("Removed!");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Sets the vue.js toggle to select and deselect panes visually.
|
||||
function settingSelectCSS(id) {
|
||||
@@ -6,12 +9,7 @@
|
||||
var settings = data.settings;
|
||||
|
||||
for (var i = 0; i < settings.length; i++) {
|
||||
if (settings[i].id == id) {
|
||||
settings[i].selected = true;
|
||||
}
|
||||
else {
|
||||
settings[i].selected = false;
|
||||
}
|
||||
settings[i].selected = settings[i].id === id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +26,10 @@
|
||||
$(".original").addClass("current");
|
||||
|
||||
for (var i = 0; i < settings.length; i++) {
|
||||
if (id == settings[i].id)
|
||||
if (id === settings[i].id) {
|
||||
settings[i].open();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,8 +38,9 @@
|
||||
var data = global.dashboard.$data;
|
||||
var settings = data.settings;
|
||||
|
||||
for (var i = 0; i < settings.length; i++)
|
||||
for (var i = 0; i < settings.length; i++) {
|
||||
settings[i].selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
global.numberify = function(x) {
|
||||
if (x == 0)
|
||||
if (x === 0) {
|
||||
return {"zeros": "000", "num": "", "units": ""}
|
||||
}
|
||||
|
||||
if (x < 10)
|
||||
if (x < 10) {
|
||||
return {"zeros": "00", "num": x, "units": ""}
|
||||
}
|
||||
|
||||
if (x < 100)
|
||||
if (x < 100) {
|
||||
return {"zeros": "0", "num": x, "units": ""}
|
||||
}
|
||||
|
||||
if (x < 1000)
|
||||
if (x < 1000) {
|
||||
return {"zeros": "", "num": x, "units": ""}
|
||||
}
|
||||
|
||||
var res;
|
||||
|
||||
if (x < 1000000) {
|
||||
res = numberify((x/1000).toFixed(0))
|
||||
res = global.numberify((x/1000).toFixed(0))
|
||||
res.units = "K"
|
||||
}
|
||||
else if (x < 1000000000) {
|
||||
res = numberify((x/1000000).toFixed(0))
|
||||
} else if (x < 1000000000) {
|
||||
res = global.numberify((x/1000000).toFixed(0))
|
||||
res.units = "M"
|
||||
}
|
||||
else if (x < 1000000000000) {
|
||||
res = numberify((x/1000000000).toFixed(0))
|
||||
} else if (x < 1000000000000) {
|
||||
res = global.numberify((x/1000000000).toFixed(0))
|
||||
res.units = "B"
|
||||
}
|
||||
|
||||
if (res.num*10 % 10 == 0)
|
||||
if (res.num*10 % 10 === 0) {
|
||||
res.num = Math.ceil(res.num);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -43,11 +49,11 @@
|
||||
}
|
||||
|
||||
$(".view").hide();
|
||||
post(global.commentoOrigin + "/api/domain/statistics", json, function(resp) {
|
||||
global.post(global.origin + "/api/domain/statistics", json, function(resp) {
|
||||
$("#statistics-view").show();
|
||||
|
||||
if (!resp.success) {
|
||||
globalErrorShow(resp.message);
|
||||
global.globalErrorShow(resp.message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,13 +80,13 @@
|
||||
|
||||
var labels = new Array();
|
||||
for (var i = 0; i < views.length; i++) {
|
||||
if ((views.length-i) % 7 == 0) {
|
||||
if ((views.length-i) % 7 === 0) {
|
||||
var x = (views.length-i)/7;
|
||||
labels.push(x + " week" + (x > 1 ? "s" : "") + " ago");
|
||||
}
|
||||
else
|
||||
} else {
|
||||
labels.push("");
|
||||
}
|
||||
}
|
||||
|
||||
new Chartist.Line("#views-graph", {
|
||||
labels: labels,
|
||||
@@ -92,9 +98,13 @@
|
||||
series: [comments],
|
||||
}, options);
|
||||
|
||||
data.domains[data.cd].viewsLast30Days = numberify(views.reduce(function(a, b) { return a + b; }, 0));
|
||||
data.domains[data.cd].commentsLast30Days = numberify(comments.reduce(function(a, b) { return a + b; }, 0));
|
||||
data.domains[data.cd].viewsLast30Days = numberify(views.reduce(function(a, b) {
|
||||
return a + b;
|
||||
}, 0));
|
||||
data.domains[data.cd].commentsLast30Days = numberify(comments.reduce(function(a, b) {
|
||||
return a + b;
|
||||
}, 0));
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Sets a vue.js field. Short for "vue set".
|
||||
function vs(field, value) {
|
||||
@@ -23,42 +26,42 @@
|
||||
"text": "Installation",
|
||||
"meaning": "Install Commento with HTML",
|
||||
"selected": false,
|
||||
"open": installationOpen,
|
||||
"open": global.installationOpen,
|
||||
},
|
||||
{
|
||||
"id": "general",
|
||||
"text": "Configure Domain",
|
||||
"meaning": "Names, domains and the rest",
|
||||
"selected": false,
|
||||
"open": generalOpen,
|
||||
"open": global.generalOpen,
|
||||
},
|
||||
{
|
||||
"id": "moderation",
|
||||
"text": "Moderation Settings",
|
||||
"meaning": "Manage list of moderators",
|
||||
"selected": false,
|
||||
"open": moderationOpen,
|
||||
"open": global.moderationOpen,
|
||||
},
|
||||
{
|
||||
"id": "statistics",
|
||||
"text": "View Activity",
|
||||
"meaning": "Usage and comment statistics",
|
||||
"selected": false,
|
||||
"open": statisticsOpen,
|
||||
"open": global.statisticsOpen,
|
||||
},
|
||||
{
|
||||
"id": "import",
|
||||
"text": "Import Comments",
|
||||
"meaning": "Import from a different service",
|
||||
"selected": false,
|
||||
"open": importOpen,
|
||||
"open": global.importOpen,
|
||||
},
|
||||
{
|
||||
"id": "danger",
|
||||
"text": "Danger Zone",
|
||||
"meaning": "Delete or freeze domain",
|
||||
"selected": false,
|
||||
"open": dangerOpen,
|
||||
"open": global.dangerOpen,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -82,8 +85,9 @@
|
||||
data: reactiveData,
|
||||
});
|
||||
|
||||
if (callback !== undefined)
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Registers a given ID for a fade out after 5 seconds.
|
||||
global.registerHide = function(id) {
|
||||
var el = $(id);
|
||||
|
||||
setTimeout(function() {
|
||||
$(id).fadeOut("fast");
|
||||
}, 5000);
|
||||
@@ -28,4 +29,4 @@
|
||||
global.showGlobalMessage("#global-ok", text);
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Talks to the API and sends an reset email.
|
||||
global.sendResetHex = function() {
|
||||
var all_ok = global.unfilledMark(["#email"], function(el) {
|
||||
var allOk = global.unfilledMark(["#email"], function(el) {
|
||||
el.css("border-bottom", "1px solid red");
|
||||
});
|
||||
|
||||
if (!all_ok) {
|
||||
if (!allOk) {
|
||||
global.textSet("#err", "Please make sure all fields are filled.");
|
||||
return;
|
||||
}
|
||||
@@ -16,7 +19,7 @@
|
||||
};
|
||||
|
||||
global.buttonDisable("#reset-button");
|
||||
global.post(global.commentoOrigin + "/api/owner/send-reset-hex", json, function(resp) {
|
||||
global.post(global.origin + "/api/owner/send-reset-hex", json, function(resp) {
|
||||
global.buttonEnable("#reset-button");
|
||||
|
||||
global.textSet("#err", "");
|
||||
@@ -30,4 +33,4 @@
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,7 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Performs a JSON POST request to the given url with the given data and
|
||||
// calls the callback function with the JSON response.
|
||||
@@ -28,4 +31,4 @@
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
4
frontend/js/jquery.js
vendored
4
frontend/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,13 +1,15 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
(document);
|
||||
|
||||
// Shows messages produced from email confirmation attempts.
|
||||
function displayConfirmedEmail() {
|
||||
var confirmed = global.paramGet("confirmed");
|
||||
|
||||
if (confirmed == "true") {
|
||||
if (confirmed === "true") {
|
||||
$("#msg").html("Successfully confirmed! Login to continue.")
|
||||
}
|
||||
else if (confirmed == "false") {
|
||||
} else if (confirmed === "false") {
|
||||
$("#err").html("That link has expired.")
|
||||
}
|
||||
}
|
||||
@@ -15,18 +17,18 @@
|
||||
|
||||
// Shows messages produced from password reset attempts.
|
||||
function displayChangedPassword() {
|
||||
var changed = paramGet("changed");
|
||||
var changed = global.paramGet("changed");
|
||||
|
||||
if (changed == "true") {
|
||||
if (changed === "true") {
|
||||
$("#msg").html("Password changed successfully! Login to continue.")
|
||||
}
|
||||
}
|
||||
|
||||
// Shows messages produced from completed signups.
|
||||
function displaySignedUp() {
|
||||
var signedUp = paramGet("signedUp");
|
||||
var signedUp = global.paramGet("signedUp");
|
||||
|
||||
if (signedUp == "true") {
|
||||
if (signedUp === "true") {
|
||||
$("#msg").html("Registration successful! Login to continue.")
|
||||
}
|
||||
}
|
||||
@@ -42,11 +44,11 @@
|
||||
|
||||
// Logs the user in and redirects to the dashboard.
|
||||
global.login = function() {
|
||||
var all_ok = global.unfilledMark(["#email", "#password"], function(el) {
|
||||
var allOk = global.unfilledMark(["#email", "#password"], function(el) {
|
||||
el.css("border-bottom", "1px solid red");
|
||||
});
|
||||
|
||||
if (!all_ok) {
|
||||
if (!allOk) {
|
||||
global.textSet("#err", "Please make sure all fields are filled");
|
||||
return;
|
||||
}
|
||||
@@ -57,7 +59,7 @@
|
||||
};
|
||||
|
||||
global.buttonDisable("#login-button");
|
||||
global.post(global.commentoOrigin + "/api/owner/login", json, function(resp) {
|
||||
global.post(global.origin + "/api/owner/login", json, function(resp) {
|
||||
global.buttonEnable("#login-button");
|
||||
|
||||
if (!resp.success) {
|
||||
@@ -66,8 +68,8 @@
|
||||
}
|
||||
|
||||
global.cookieSet("commentoOwnerToken", resp.ownerToken);
|
||||
document.location = global.commentoOrigin + "/dashboard";
|
||||
document.location = global.origin + "/dashboard";
|
||||
});
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
global.logout = function() {
|
||||
global.cookieDelete("commentoOwnerToken");
|
||||
document.location = global.commentoOrigin + "/login";
|
||||
document.location = global.origin + "/login";
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
global.resetPassword = function() {
|
||||
var all_ok = global.unfilledMark(["#password", "#password2"], function(el) {
|
||||
var allOk = global.unfilledMark(["#password", "#password2"], function(el) {
|
||||
el.css("border-bottom", "1px solid red");
|
||||
});
|
||||
|
||||
if (!all_ok) {
|
||||
if (!allOk) {
|
||||
global.textSet("#err", "Please make sure all fields are filled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($("#password").val() != $("#password2").val()) {
|
||||
if ($("#password").val() !== $("#password2").val()) {
|
||||
global.textSet("#err", "The two passwords do not match.");
|
||||
return;
|
||||
}
|
||||
@@ -21,7 +22,7 @@
|
||||
};
|
||||
|
||||
global.buttonDisable("#reset-button");
|
||||
global.post(global.commentoOrigin + "/api/owner/reset-password", json, function(resp) {
|
||||
global.post(global.origin + "/api/owner/reset-password", json, function(resp) {
|
||||
global.buttonEnable("#reset-button");
|
||||
|
||||
global.textSet("#err", "");
|
||||
@@ -30,8 +31,8 @@
|
||||
return
|
||||
}
|
||||
|
||||
document.location = global.commentoOrigin + "/login?changed=true";
|
||||
document.location = global.origin + "/login?changed=true";
|
||||
});
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
// Get self details.
|
||||
global.selfGet = function(callback) {
|
||||
@@ -7,14 +8,14 @@
|
||||
};
|
||||
|
||||
if (json.ownerToken === undefined) {
|
||||
document.location = global.commentoOrigin + "/login";
|
||||
document.location = global.origin + "/login";
|
||||
return;
|
||||
}
|
||||
|
||||
global.post(global.commentoOrigin + "/api/owner/self", json, function(resp) {
|
||||
global.post(global.origin + "/api/owner/self", json, function(resp) {
|
||||
if (!resp.success || !resp.loggedIn) {
|
||||
global.cookieDelete("commentoOwnerToken");
|
||||
document.location = global.commentoOrigin + "/login";
|
||||
document.location = global.origin + "/login";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,4 +24,4 @@
|
||||
});
|
||||
};
|
||||
|
||||
}(window, document));
|
||||
}(window.commento, document));
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
(function (global, document) {
|
||||
"use strict"
|
||||
|
||||
// Signs up the user and redirects to either the login page or the email
|
||||
// confirmation, depending on whether or not SMTP is configured in the
|
||||
// backend.
|
||||
global.signup = function() {
|
||||
if ($("#password").val() != $("#password2").val()) {
|
||||
if ($("#password").val() !== $("#password2").val()) {
|
||||
global.textSet("#err", "The two passwords don't match");
|
||||
return;
|
||||
}
|
||||
|
||||
var all_ok = unfilledMark(["#email", "#name", "#password", "#password2"], function(el) {
|
||||
var allOk = global.unfilledMark(["#email", "#name", "#password", "#password2"], function(el) {
|
||||
el.css("border-bottom", "1px solid red");
|
||||
});
|
||||
|
||||
if (!all_ok) {
|
||||
if (!allOk) {
|
||||
global.textSet("#err", "Please make sure all fields are filled");
|
||||
return;
|
||||
}
|
||||
@@ -25,7 +26,7 @@
|
||||
};
|
||||
|
||||
global.buttonDisable("#signup-button");
|
||||
post(global.commentoOrigin + "/api/owner/new", json, function(resp) {
|
||||
global.post(global.origin + "/api/owner/new", json, function(resp) {
|
||||
global.buttonEnable("#signup-button")
|
||||
|
||||
if (!resp.success) {
|
||||
@@ -33,11 +34,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp.confirmEmail)
|
||||
document.location = global.commentoOrigin + "/confirm-email";
|
||||
else
|
||||
document.location = global.commentoOrigin + "/login?signedUp=true";
|
||||
if (resp.confirmEmail) {
|
||||
document.locatidocumenton = global.origin + "/confirm-email";
|
||||
} else {
|
||||
document.location = global.origin + "/login?signedUp=true";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
} (window, document));
|
||||
} (window.commento, document));
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
(function (global, document) {
|
||||
"use strict";
|
||||
|
||||
// Gets a GET parameter in the current URL.
|
||||
global.paramGet = function(param) {
|
||||
var pageURL = decodeURIComponent(window.location.search.substring(1));
|
||||
var urlVariables = pageURL.split('&');
|
||||
var urlVariables = pageURL.split("&");
|
||||
|
||||
for (var i = 0; i < urlVariables.length; i++) {
|
||||
var paramURL = urlVariables[i].split('=');
|
||||
if (paramURL[0] === param)
|
||||
var paramURL = urlVariables[i].split("=");
|
||||
if (paramURL[0] === param) {
|
||||
return paramURL[1] === undefined ? true : paramURL[1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -42,16 +44,16 @@
|
||||
// Given an array of input IDs, this function calls a callback function with
|
||||
// the first unfilled ID.
|
||||
global.unfilledMark = function(fields, callback) {
|
||||
var all_ok = true;
|
||||
var allOk = true;
|
||||
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var el = $(fields[i]);
|
||||
if (el.val() == "") {
|
||||
if (el.val() === "") {
|
||||
callback(el);
|
||||
}
|
||||
}
|
||||
|
||||
return all_ok;
|
||||
return allOk;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +61,9 @@
|
||||
global.cookieGet = function(name) {
|
||||
var c = "; " + document.cookie;
|
||||
var x = c.split("; " + name + "=");
|
||||
if (x.length == 2)
|
||||
if (x.length === 2) {
|
||||
return x.pop().split(";").shift();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -72,8 +75,9 @@
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
|
||||
var cookieString = name + "=" + value + expires + "; path=/";
|
||||
if (/^https:\/\//i.test(commentoOrigin))
|
||||
if (/^https:\/\//i.test(origin)) {
|
||||
cookieString += "; secure";
|
||||
}
|
||||
|
||||
document.cookie = cookieString;
|
||||
}
|
||||
@@ -81,7 +85,7 @@
|
||||
|
||||
// Deletes a cookie.
|
||||
global.cookieDelete = function(name) {
|
||||
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:01 GMT;";
|
||||
}
|
||||
|
||||
|
||||
@@ -90,29 +94,35 @@
|
||||
var seconds = Math.floor((new Date() - date) / 1000);
|
||||
var interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (interval > 1)
|
||||
if (interval > 1) {
|
||||
return interval + " years ago";
|
||||
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval > 1)
|
||||
return interval + " months ago";
|
||||
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval > 1)
|
||||
return interval + " days ago";
|
||||
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval > 1)
|
||||
return interval + " hours ago";
|
||||
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1)
|
||||
return interval + " minutes ago";
|
||||
|
||||
if (seconds > 5)
|
||||
return Math.floor(seconds) + " seconds ago";
|
||||
else
|
||||
return "just now";
|
||||
}
|
||||
|
||||
} (window, document));
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval > 1) {
|
||||
return interval + " months ago";
|
||||
}
|
||||
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval > 1) {
|
||||
return interval + " days ago";
|
||||
}
|
||||
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval > 1) {
|
||||
return interval + " hours ago";
|
||||
}
|
||||
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1) {
|
||||
return interval + " minutes ago";
|
||||
}
|
||||
|
||||
if (seconds > 5) {
|
||||
return Math.floor(seconds) + " seconds ago";
|
||||
} else {
|
||||
return "just now";
|
||||
}
|
||||
}
|
||||
|
||||
} (window.commento, document));
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -16,9 +16,9 @@
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.loggedInRedirect();
|
||||
window.prefillEmail();
|
||||
window.displayMessages();
|
||||
window.commento.loggedInRedirect();
|
||||
window.commento.prefillEmail();
|
||||
window.commento.displayMessages();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="err" id="err"></div>
|
||||
<div class="msg" id="msg"></div>
|
||||
|
||||
<button id="button" class="button" onclick="window.login()">Login</button>
|
||||
<button id="button" class="button" onclick="window.commento.login()">Login</button>
|
||||
|
||||
<a class="link" href="[[[.Origin]]]/forgot">Trouble logging in? Reset your password.</a>
|
||||
<a class="link" href="[[[.Origin]]]/signup">Don't have an account yet? Sign up.</a>
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
</head>
|
||||
|
||||
<script>
|
||||
window.onload = window.logout;
|
||||
window.onload = window.commento.logout;
|
||||
</script>
|
||||
</html>
|
||||
|
||||
33
frontend/package.json
Normal file
33
frontend/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "commento",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"repository": "git@gitlab.com:commento/commento.git",
|
||||
"author": "Adhityaa <c.adhityaa@gmail.com> Anton Linevych anton@linevich.net",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"chartist": "0.11.0",
|
||||
"fixmyjs": "2.0.0",
|
||||
"gulp": "3.9.1",
|
||||
"gulp-clean-css": "3.9.4",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-eslint": "5.0.0",
|
||||
"gulp-html-minifier": "0.1.8",
|
||||
"gulp-rename": "1.3.0",
|
||||
"gulp-sass": "4.0.1",
|
||||
"gulp-sourcemaps": "2.6.4",
|
||||
"gulp-uglify": "3.0.0",
|
||||
"highlightjs": "9.10.0",
|
||||
"html-minifier": "3.5.7",
|
||||
"jquery": "3.2.1",
|
||||
"natives": "^1.1.6",
|
||||
"normalize-scss": "7.0.1",
|
||||
"sass": "1.5.1",
|
||||
"uglify-js": "3.4.1",
|
||||
"vue": "2.5.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint": "^5.10.0"
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<div class="err" id="err"></div>
|
||||
<div class="msg" id="msg"></div>
|
||||
<button id="reset-button" class="button" onclick="resetPassword()">Reset Password</button>
|
||||
<button id="reset-button" class="button" onclick="window.commento.resetPassword()">Reset Password</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -83,6 +83,20 @@
|
||||
background: $green-7;
|
||||
}
|
||||
|
||||
.commento-option-sticky,
|
||||
.commento-option-unsticky {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
@include mask-image('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8"?><svg enable-background="new 0 0 487.222 487.222" version="1.1" viewBox="0 0 487.22 487.22" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m486.55 186.81c-1.6-4.9-5.8-8.4-10.9-9.2l-152-21.6-68.4-137.5c-2.3-4.6-7-7.5-12.1-7.5s-9.8 2.9-12.1 7.6l-67.5 137.9-152 22.6c-5.1 0.8-9.3 4.3-10.9 9.2s-0.2 10.3 3.5 13.8l110.3 106.9-25.5 151.4c-0.9 5.1 1.2 10.2 5.4 13.2 2.3 1.7 5.1 2.6 7.9 2.6 2.2 0 4.3-0.5 6.3-1.6l135.7-71.9 136.1 71.1c2 1 4.1 1.5 6.2 1.5 7.4 0 13.5-6.1 13.5-13.5 0-1.1-0.1-2.1-0.4-3.1l-26.3-150.5 109.6-107.5c3.9-3.6 5.2-9 3.6-13.9zm-137 107.1c-3.2 3.1-4.6 7.6-3.8 12l22.9 131.3-118.2-61.7c-3.9-2.1-8.6-2-12.6 0l-117.8 62.4 22.1-131.5c0.7-4.4-0.7-8.8-3.9-11.9l-95.6-92.8 131.9-19.6c4.4-0.7 8.2-3.4 10.1-7.4l58.6-119.7 59.4 119.4c2 4 5.8 6.7 10.2 7.4l132 18.8-95.3 93.3z" fill="%231e2127"/></svg>');
|
||||
margin: 12px 6px 12px 6px;
|
||||
background: $gray-5;
|
||||
}
|
||||
|
||||
.commento-option-unsticky {
|
||||
@include mask-image('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 487.22 487.22" xmlns="http://www.w3.org/2000/svg"><g><title>background</title><rect x="-1" y="-1" fill="none"/></g><g><title>Layer 1</title><path d="m486.55 186.81c-1.6-4.9-5.8-8.4-10.9-9.2l-152-21.6-68.4-137.5c-2.3-4.6-7-7.5-12.1-7.5s-9.8 2.9-12.1 7.6l-67.5 137.9-152 22.6c-5.1 0.8-9.3 4.3-10.9 9.2s-0.2 10.3 3.5 13.8l110.3 106.9-25.5 151.4c-0.9 5.1 1.2 10.2 5.4 13.2 2.3 1.7 5.1 2.6 7.9 2.6 2.2 0 4.3-0.5 6.3-1.6l135.7-71.9 136.1 71.1c2 1 4.1 1.5 6.2 1.5 7.4 0 13.5-6.1 13.5-13.5 0-1.1-0.1-2.1-0.4-3.1l-26.3-150.5 109.6-107.5c3.9-3.6 5.2-9 3.6-13.9z" fill="%231e2127"/></g></svg>');
|
||||
background: $yellow-7;
|
||||
}
|
||||
|
||||
.commento-option-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ textarea::placeholder {
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
line-height: 80px;
|
||||
line-height: 110px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
@@ -28,7 +28,7 @@ textarea {
|
||||
padding: 8px;
|
||||
outline: none;
|
||||
overflow: auto;
|
||||
min-height: 100px;
|
||||
min-height: 130px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ textarea {
|
||||
|
||||
.commento-account-buttons-question {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
top: 10px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
@@ -124,9 +124,14 @@ textarea {
|
||||
}
|
||||
|
||||
.commento-anonymous-button {
|
||||
background: #096fa6;
|
||||
text-transform: uppercase;
|
||||
display: block;
|
||||
color: $blue-6;
|
||||
font-weight: 700;
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.commento-blurred-textarea {
|
||||
@@ -152,18 +157,24 @@ textarea {
|
||||
}
|
||||
|
||||
.commento-create-button {
|
||||
width: 120px;
|
||||
width: 150px;
|
||||
background: $pink-9;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.commento-login-button {
|
||||
width: 50px;
|
||||
background: $cyan-9;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.commento-submit-button {
|
||||
float: right;
|
||||
background: $indigo-7;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.commento-approve-button {
|
||||
@@ -177,18 +188,3 @@ textarea {
|
||||
.commento-button-margin {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.commento-mod-tools-lock-button {
|
||||
color: $gray-6;
|
||||
background: none;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
margin-left: 12px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.commento-mod-tools-lock-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
text-align: center;
|
||||
|
||||
.commento-login-link {
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');
|
||||
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700');
|
||||
|
||||
.commento-root-min-height {
|
||||
min-height: 350px;
|
||||
}
|
||||
|
||||
.commento-root {
|
||||
font-family: "Source Sans Pro", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
||||
overflow-x: hidden;
|
||||
padding: 0px;
|
||||
|
||||
* {
|
||||
font-family: "Source Sans Pro", "Segoe UI", "Roboto", "Helvetica Neue", sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
color: #50596c;
|
||||
overflow-x: hidden;
|
||||
text-rendering: optimizeLegibility;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@import "colors-main.scss";
|
||||
@import "common-main.scss";
|
||||
@@ -41,19 +44,30 @@
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
color: $red-7;
|
||||
font-weight: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.commento-mod-tools {
|
||||
margin-bottom: 16px;
|
||||
|
||||
button {
|
||||
text-transform: uppercase;
|
||||
color: $gray-7;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
margin-left: 12px;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.commento-mod-tools::before {
|
||||
content: "Moderators";
|
||||
content: "Moderator Tools";
|
||||
text-transform: uppercase;
|
||||
color: $indigo-8;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.commento-moderation-notice {
|
||||
@@ -62,17 +76,17 @@
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
color: $orange-7;
|
||||
font-weight: bold;
|
||||
font-weight: 700;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.commento-dark-card {
|
||||
background: $blue-1;
|
||||
background: $yellow-0;
|
||||
}
|
||||
|
||||
.commento-avatar {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -81,8 +95,7 @@
|
||||
font-size: 22px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #fff;
|
||||
box-shadow: 0px 0px 0px 2px #f00;
|
||||
border: 0px transparent;
|
||||
}
|
||||
|
||||
.commento-avatar-img {
|
||||
@@ -111,7 +124,7 @@
|
||||
}
|
||||
|
||||
.commento-name {
|
||||
font-weight: bold;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
border: none;
|
||||
@@ -124,6 +137,17 @@
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.commento-flagged::after {
|
||||
content: "Flagged";
|
||||
text-transform: uppercase;
|
||||
font-size: 10px;
|
||||
background: $red-7;
|
||||
color: white;
|
||||
margin-left: 8px;
|
||||
padding: 2px 6px 2px 6px;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.commento-subtitle {
|
||||
display: block;
|
||||
color: #999;
|
||||
@@ -131,13 +155,20 @@
|
||||
margin-left: 48px;
|
||||
}
|
||||
|
||||
.commento-score {
|
||||
.commento-timeago {
|
||||
display: inline;
|
||||
color: #999;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.commento-score::before {
|
||||
.commento-score {
|
||||
display: inline;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.commento-timeago::before {
|
||||
content: "\00a0 \00a0 \00b7 \00a0 \00a0";
|
||||
}
|
||||
|
||||
@@ -155,6 +186,16 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.commento-options-mobile {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.commento-options-clearfix {
|
||||
height: 38px;
|
||||
width: 1px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.commento-moderation {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.loggedInRedirect();
|
||||
window.prefillEmail();
|
||||
window.commento.loggedInRedirect();
|
||||
window.commento.prefillEmail();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<p class="cent">
|
||||
</p>
|
||||
|
||||
<button id="signup-button" class="button" onclick="window.signup()">Sign up</button>
|
||||
<button id="signup-button" class="button" onclick="window.commento.signup()">Sign up</button>
|
||||
|
||||
<a class="link" href="[[[.Origin]]]/login">Already have an account? Login instead.</a>
|
||||
</div>
|
||||
|
||||
4501
frontend/yarn.lock
Normal file
4501
frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
binary_name=commento-ce
|
||||
binary_name=commento
|
||||
|
||||
trap ctrl_c INT
|
||||
ctrl_c() {
|
||||
@@ -9,10 +9,12 @@ ctrl_c() {
|
||||
exit
|
||||
}
|
||||
|
||||
version=devel
|
||||
|
||||
binary_pid=
|
||||
if make -j$(($(nproc) + 1)); then
|
||||
if make $version -j$(($(nproc) + 1)); then
|
||||
source devel.env
|
||||
cd build/devel
|
||||
cd build/$version
|
||||
./$binary_name &
|
||||
binary_pid=$!
|
||||
cd ../../
|
||||
@@ -50,9 +52,9 @@ while true; do
|
||||
wait $binary_pid
|
||||
fi
|
||||
|
||||
if make -j$(($(nproc) + 1)); then
|
||||
if make $version -j$(($(nproc) + 1)); then
|
||||
source devel.env
|
||||
cd build/devel
|
||||
cd build/$version
|
||||
./$binary_name &
|
||||
binary_pid=$!
|
||||
cd ../../
|
||||
|
||||
0
scripts/check-dco
Normal file → Executable file
0
scripts/check-dco
Normal file → Executable file
17
scripts/gitlab-ci-build-prescript
Normal file
17
scripts/gitlab-ci-build-prescript
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
mkdir -p /go/src /go/bin /go/pkg
|
||||
ln -s $CI_PROJECT_DIR /go/src/$CI_PROJECT_NAME
|
||||
|
||||
apt update
|
||||
apt install -y curl gnupg git make golang python
|
||||
export GOPATH=/go
|
||||
export PATH=$PATH:/go/bin
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
|
||||
curl -sL https://deb.nodesource.com/setup_10.x | bash -
|
||||
apt install -y nodejs
|
||||
npm install -g yarn@1.10.0
|
||||
|
||||
apt install -y python python-pip
|
||||
pip install awscli
|
||||
Reference in New Issue
Block a user