Merge branch 'develop'

This commit is contained in:
Lars Hoogestraat 2021-07-31 14:01:14 +02:00
commit 86a6ab3cd2
45 changed files with 567 additions and 469 deletions

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//package crypt
// Package crypt provides utilities for creating hashes, random strings, password encryption
package crypt
import (
@ -16,24 +16,26 @@ import (
"golang.org/x/crypto/bcrypt"
)
const bcryptRounds = 12
var (
//AlphaUpper all upper alphas chars
// AlphaUpper all upper alphas chars
AlphaUpper = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
//AlphaLower all lowers alphas chars
// AlphaLower all lowers alphas chars
AlphaLower = RandomSource("abcdefghijklmnopqrstuvwxyz")
//AlphaUpperLower all upper and lowers aplhas chars
// AlphaUpperLower all upper and lowers aplhas chars
AlphaUpperLower = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
//AlphaUpperLowerNumeric all upper lowers alphas and numerics
// AlphaUpperLowerNumeric all upper lowers alphas and numerics
AlphaUpperLowerNumeric = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz")
//AlphaUpperLowerNumericSpecial all upper lowers alphas, numerics and special chars
// AlphaUpperLowerNumericSpecial all upper lowers alphas, numerics and special chars
AlphaUpperLowerNumericSpecial = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456890" +
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
)
//RandomSource string containing which characters should be considered when generating random sequences
// RandomSource string containing which characters should be considered when generating random sequences
type RandomSource string
//RandomSequence returns random character with given length;
// RandomSequence returns random character with given length;
func (r RandomSource) RandomSequence(length int) []byte {
result := make([]byte, length)
for i := 0; i < length; i++ {
@ -44,7 +46,7 @@ func (r RandomSource) RandomSequence(length int) []byte {
return result
}
//RandomSecureKey returns random character with given length
// RandomSecureKey returns random character with given length
func RandomSecureKey(length int) []byte {
k := make([]byte, length)
if _, err := io.ReadFull(rand.Reader, k); err != nil {
@ -53,22 +55,17 @@ func RandomSecureKey(length int) []byte {
return k
}
//CryptPassword hashes a password with bcrypt and a given cost
func CryptPassword(password []byte, cost int) ([]byte, error) {
s, err := bcrypt.GenerateFromPassword(password, cost)
if err != nil {
return nil, err
}
return s, nil
// CryptPassword hashes a password with bcrypt and a given cost
func CryptPassword(password []byte) ([]byte, error) {
return bcrypt.GenerateFromPassword(password, bcryptRounds)
}
//GenerateSalt generates a random salt with alphanumerics and some special characters
// GenerateSalt generates a random salt with alphanumerics and some special characters
func GenerateSalt() []byte {
return AlphaUpperLowerNumericSpecial.RandomSequence(32)
}
// RandomHash returns a random SHA-512 hash
func RandomHash(length int) string {
hash := sha512.New()
hash.Write(RandomSecureKey(length))

View File

@ -10,17 +10,17 @@ import (
_ "github.com/mattn/go-sqlite3"
)
//SQLiteConfig represents sqlite configuration type
// SQLiteConfig represents sqlite configuration type
type SQLiteConfig struct {
File string
}
//Open receives handle for sqlite database, returns an error if connection failed
// Open receives handle for sqlite database, returns an error if connection failed
func (d SQLiteConfig) Open() (*sql.DB, error) {
return sql.Open("sqlite3", d.File)
}
//InitTables creates the tables
// InitTables creates the tables
func InitTables(db *sql.DB) error {
if _, err := db.Exec("CREATE TABLE user " +
"(" +

20
go.mod
View File

@ -4,16 +4,22 @@ go 1.15
require (
git.hoogi.eu/snafu/cfg v1.0.6
git.hoogi.eu/snafu/session v1.2.0
git.hoogi.eu/snafu/session v1.3.0
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/gorilla/csrf v1.7.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/justinas/alice v1.2.0
github.com/mattn/go-sqlite3 v1.14.5
github.com/microcosm-cc/bluemonday v1.0.4
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-sqlite3 v1.14.8
github.com/microcosm-cc/bluemonday v1.0.15
github.com/russross/blackfriday/v2 v2.1.0
github.com/sirupsen/logrus v1.7.0
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/net v0.0.0-20210716203947-853a461950ff // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

76
go.sum
View File

@ -1,17 +1,17 @@
git.hoogi.eu/snafu/cfg v1.0.6 h1:O34hYFqjwfnMjEwB4M8GaQQmBtf3H+AA0RFHb7PoMNs=
git.hoogi.eu/snafu/cfg v1.0.6/go.mod h1:LQolv8bqH8ZPz7h9PSVswdBXj1BIM+kW79AVS/jpE7A=
git.hoogi.eu/snafu/session v1.1.2 h1:MclTbSqD/9JodRUqFc4OwyJGk5AtonqB6BaG5RRJHf8=
git.hoogi.eu/snafu/session v1.1.2/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
git.hoogi.eu/snafu/session v1.2.0 h1:qmZXMCAZRrzcOOLsOltwPUeA4ckpjwjjJ8fQpFDSx+w=
git.hoogi.eu/snafu/session v1.2.0/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
git.hoogi.eu/snafu/session v1.3.0 h1:CzJQG7rseuerwBcLwxoJDtvWjXNP13bnWE90TsuTAls=
git.hoogi.eu/snafu/session v1.3.0/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y=
github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
@ -24,36 +24,52 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY=
github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds=
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -14,7 +14,7 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
//AdminProfileHandler returns page for updating the profile of the currently logged-in user
// AdminProfileHandler returns the page for updating the profile of the currently logged-in user
func AdminProfileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
user, _ := middleware.User(r)
@ -27,7 +27,7 @@ func AdminProfileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
}
}
//AdminProfilePostHandler handles the updating of the user profile which is currently logged in
// AdminProfilePostHandler handles the updating of the user profile which is currently logged in
func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
ctxUser, _ := middleware.User(r)
ctxUser.PlainPassword = []byte(r.FormValue("current_password"))
@ -81,7 +81,7 @@ func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
session.SetValue("userid", u.ID)
sessions := ctx.SessionService.SessionProvider.FindSessionsByValue("userid", u.ID)
sessions := ctx.SessionService.SessionProvider.FindByValue("userid", u.ID)
for _, sid := range sessions {
if sid.SessionID() != session.SessionID() {
@ -111,7 +111,7 @@ func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//ActivateAccountHandler shows the form to activate an account.
// ActivateAccountHandler shows the form to activate an account
func ActivateAccountHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
hash := getVar(r, "hash")
@ -139,9 +139,9 @@ func ActivateAccountHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}
}
//ActivateAccountPostHandler activates an user account
// ActivateAccountPostHandler activates an user account
func ActivateAccountPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
// Delete any cookies if an user is logged in
// Delete cookie if the user is logged in
ctx.SessionService.Remove(w, r)
password := r.FormValue("password")
@ -196,11 +196,11 @@ func ActivateAccountPostHandler(ctx *middleware.AppContext, w http.ResponseWrite
return &middleware.Template{
RedirectPath: "admin",
SuccessMsg: "The account was successfully activated. You can now log in.",
SuccessMsg: "The account was successfully activated. You can now login.",
}
}
//ResetPasswordHandler returns the form for resetting the password
// ResetPasswordHandler returns the form to reset the password
func ResetPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
hash := getVar(r, "hash")
@ -227,7 +227,7 @@ func ResetPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
}
}
//ResetPasswordPostHandler handles the resetting of the password
// ResetPasswordPostHandler handles a password reset
func ResetPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
password := r.FormValue("password")
password2 := r.FormValue("password_repeat")
@ -283,14 +283,14 @@ func ResetPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//ForgotPasswordHandler returns the form for the reset password form
// ForgotPasswordHandler returns the form for the password reset
func ForgotPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Name: tplAdminForgotPassword,
}
}
//ForgotPasswordPostHandler handles the processing of the reset password function
// ForgotPasswordPostHandler handles the processing for the password reset
func ForgotPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
email := r.FormValue("email")

View File

@ -15,8 +15,8 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
//GetArticleHandler returns a specific article
//Parameters in the url form 2016/3/my-headline are used for obtaining the article
// GetArticleHandler returns a specific article
// Parameters are in the form /year/month/slug e.g. 2016/3/my-headline
func GetArticleHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
year := getVar(r, "year")
month := getVar(r, "month")
@ -51,8 +51,7 @@ func GetArticleHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
}}
}
//GetArticleHandler returns a specific article
//Parameters in the url form 2016/03/my-headline are used for obtaining the article
// GetArticleByIDHandler returns a specific article by the ID
func GetArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
id, err := parseInt(getVar(r, "articleID"))
@ -90,7 +89,7 @@ func GetArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}}
}
//ListArticlesHandler returns the template which contains all published articles
// ListArticlesHandler returns all published articles
func ListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
page := getPageParam(r)
@ -142,7 +141,7 @@ func ListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
}
}
//ListArticlesHandler returns the template which contains all published articles
// ListArticlesCategoryHandler returns all published articles in a category
func ListArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
page := getPageParam(r)
@ -207,7 +206,39 @@ func ListArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWrit
}
}
//IndexArticlesCategoryHandler returns the template information for the index page grouped by categories
// IndexArticlesHandler returns articles for the index page
func IndexArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
a, err := ctx.ArticleService.Index(nil, nil, nil, models.OnlyPublished)
if err != nil {
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Err: err,
}
}
c, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
if err != nil {
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Err: err,
}
}
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Data: map[string]interface{}{
"articles": a,
"categories": c,
},
}
}
// IndexArticlesCategoryHandler returns articles for the index page grouped by categories
func IndexArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
cs, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
@ -257,40 +288,7 @@ func IndexArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWri
}
}
//IndexArticlesHandler returns the template information for the index page
func IndexArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
a, err := ctx.ArticleService.Index(nil, nil, nil, models.OnlyPublished)
if err != nil {
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Err: err,
}
}
c, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
if err != nil {
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Err: err,
}
}
return &middleware.Template{
Name: tplIndexArticles,
Active: "index",
Data: map[string]interface{}{
"articles": a,
"categories": c,
},
}
}
//GetArticleHandler returns a specific article
//Parameters in the url form 2016/03/my-headline are used for obtaining the article
// RSSFeed returns XML list of published articles for the RSS feed
func RSSFeed(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) (*models.XMLData, error) {
p := &models.Pagination{
Limit: ctx.ConfigService.RSSFeedItems,
@ -308,7 +306,7 @@ func RSSFeed(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request)
}, nil
}
//AdminListArticlesHandler returns all articles, also not yet published articles will be shown
// AdminListArticlesHandler returns all articles, also not yet published articles
func AdminListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -347,8 +345,7 @@ func AdminListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}}
}
//AdminShowArticleByIDHandler returns a specific article, renders it on the front page
//used for the preview
// AdminPreviewArticleByIDHandler returns a specific article, renders it on the front page used for the preview
func AdminPreviewArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -392,7 +389,7 @@ func AdminPreviewArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseW
}}
}
// AdminArticleNewHandler returns the template which shows the form to create a new article
// AdminArticleNewHandler returns the form to create a new article
func AdminArticleNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
c, err := ctx.CategoryService.List(models.AllCategories)
@ -458,7 +455,7 @@ func AdminArticleNewPostHandler(ctx *middleware.AppContext, w http.ResponseWrite
}
}
//AdminArticleEditHandler shows the form for changing an article
// AdminArticleEditHandler shows the form for changing an article
func AdminArticleEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -499,7 +496,7 @@ func AdminArticleEditHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminArticleEditPostHandler handles the update of an article
// AdminArticleEditPostHandler handles the update of an article
func AdminArticleEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -556,7 +553,7 @@ func AdminArticleEditPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
}
}
//AdminArticlePublishHandler returns the action template which asks the user if the article should be published / unpublished
// AdminArticlePublishHandler returns the action template which asks the user if the article should be published / unpublished
func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -574,6 +571,14 @@ func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWrite
a, err := ctx.ArticleService.GetByID(id, u, models.All)
if err != nil {
return &middleware.Template{
Name: tplAdminArticles,
Err: err,
Active: "articles",
}
}
var action models.Action
if a.Published {
@ -603,7 +608,7 @@ func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWrite
}
}
// AdminArticlePublishPostHandler publishes or "depublishes" an article
// AdminArticlePublishPostHandler publish or unpublish an article
func AdminArticlePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -632,7 +637,7 @@ func AdminArticlePublishPostHandler(ctx *middleware.AppContext, w http.ResponseW
}
}
//AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
// AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
func AdminArticleDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -675,7 +680,7 @@ func AdminArticleDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter
}
}
//AdminArticleDeletePostHandler handles the removing of an article
// AdminArticleDeletePostHandler handles the removing of an article
func AdminArticleDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)

View File

@ -13,6 +13,7 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
// AdminListCategoriesHandler returns a list of all categories
func AdminListCategoriesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
c, err := ctx.CategoryService.List(models.AllCategories)
@ -31,6 +32,7 @@ func AdminListCategoriesHandler(ctx *middleware.AppContext, w http.ResponseWrite
}}
}
// AdminGetCategoryHandler get category by the ID
func AdminGetCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "categoryID")
id, err := parseInt(reqVar)
@ -59,7 +61,7 @@ func AdminGetCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}}
}
// AdminCategoryNewHandler returns the template which shows the form to create a new article
// AdminCategoryNewHandler returns the form to create a new category
func AdminCategoryNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Active: "categories",
@ -67,7 +69,7 @@ func AdminCategoryNewHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
// AdminCategoryNewPostHandler handles the creation of a new article
// AdminCategoryNewPostHandler handles the creation of a new category
func AdminCategoryNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -99,7 +101,7 @@ func AdminCategoryNewPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
}
}
//AdminCategoryEditHandler shows the form for changing an article
// AdminCategoryEditHandler shows the form to change a category
func AdminCategoryEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
id, err := parseInt(getVar(r, "categoryID"))
@ -128,7 +130,7 @@ func AdminCategoryEditHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminArticleEditPostHandler handles the update of an article
// AdminCategoryEditPostHandler handles the update of a category
func AdminCategoryEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -168,7 +170,7 @@ func AdminCategoryEditPostHandler(ctx *middleware.AppContext, w http.ResponseWri
}
}
//AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
// AdminCategoryDeleteHandler returns the action which asks the user if the category should be removed
func AdminCategoryDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "categoryID")
@ -209,7 +211,7 @@ func AdminCategoryDeleteHandler(ctx *middleware.AppContext, w http.ResponseWrite
}
}
//AdminArticleDeletePostHandler handles the removing of an article
// AdminCategoryDeletePostHandler handles the removing of a category
func AdminCategoryDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "categoryID")

View File

@ -19,7 +19,7 @@ type FileHandler struct {
Context *middleware.AppContext
}
//FileGetHandler serves the file based on the url filename
// FileGetHandler serves the file based on the unique filename
func (fh FileHandler) FileGetHandler(w http.ResponseWriter, r *http.Request) {
rv := getVar(r, "uniquename")
@ -55,12 +55,19 @@ func (fh FileHandler) FileGetHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
}
defer rf.Close()
defer func(rf *os.File) {
err := rf.Close()
if err != nil {
logger.Log.Errorf("error while closing the file %v", err)
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
}
}(rf)
http.ServeContent(w, r, loc, f.LastModified, rf)
}
//AdminListFilesHandler returns the template which lists all uploaded files belonging to a user, admins will see all files
// AdminListFilesHandler returns the template which lists all uploaded files belonging to a user, admins will see all files
func AdminListFilesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -102,7 +109,7 @@ func AdminListFilesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}}
}
//AdminUploadFileHandler returns the form for uploading a file
// AdminUploadFileHandler returns the form for uploading a file
func AdminUploadFileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Name: tplAdminFileUpload,
@ -110,6 +117,7 @@ func AdminUploadFileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}
}
// AdminToggleInlineFilePostHandler toggles the flag if the file should be inline or downloaded (toggles Content-Disposition header)
func AdminToggleInlineFilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -173,6 +181,7 @@ func AdminUploadFilePostHandler(ctx *middleware.AppContext, w http.ResponseWrite
}
}
// AdminUploadJSONFilePostHandler
func AdminUploadJSONFilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) (*models.JSONData, error) {
file, err := parseFileField(ctx, w, r)
@ -197,7 +206,7 @@ func AdminUploadJSONFilePostHandler(ctx *middleware.AppContext, w http.ResponseW
return json, nil
}
//AdminUploadDeleteHandler returns the action template which asks the user if the file should be removed
// AdminUploadDeleteHandler returns the action template which asks the user if the file should be removed
func AdminUploadDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -239,7 +248,7 @@ func AdminUploadDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminUploadDeletePostHandler removes a file
// AdminUploadDeletePostHandler removes a file
func AdminUploadDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)

View File

@ -7,12 +7,14 @@ package handler
import (
"net/http"
"git.hoogi.eu/snafu/go-blog/logger"
"git.hoogi.eu/snafu/go-blog/middleware"
"git.hoogi.eu/snafu/go-blog/models"
)
// LoginHandler shows the login form;
// if the user is already logged in the user will be redirected to the administration page of aricles
// if the user is already logged in the user will be redirected to the administration articles page
func LoginHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
_, err := ctx.SessionService.Get(rw, r)
@ -29,7 +31,7 @@ func LoginHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Re
}
// LoginPostHandler receives the login information from the form; checks the login and
// starts a session for the user. The sesion will be stored in a cookie
// starts a session for the user. The session will be stored in a cookie
func LoginPostHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
if err := r.ParseForm(); err != nil {
return &middleware.Template{
@ -75,7 +77,9 @@ func LoginPostHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *htt
// LogoutHandler logs the user out by removing the cookie and removing the session from the session store
func LogoutHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
ctx.SessionService.Remove(rw, r)
if err := ctx.SessionService.Remove(rw, r); err != nil {
logger.Log.Infof("LogoutHandler: unable to remove session, err: %v", err)
}
return &middleware.Template{
RedirectPath: "admin",
@ -85,9 +89,7 @@ func LogoutHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.R
// KeepAliveSessionHandler keeps a session alive.
func KeepAliveSessionHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) (*models.JSONData, error) {
_, err := ctx.SessionService.Get(rw, r)
if err != nil {
if _, err := ctx.SessionService.Get(rw, r); err != nil {
return nil, err
}

View File

@ -15,7 +15,7 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
//GetSiteHandler returns the site template - only published sites are considered
// GetSiteHandler returns the published sites
func GetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
site, err := ctx.SiteService.GetByLink(getVar(r, "site"), models.OnlyPublished)
@ -40,7 +40,7 @@ func GetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.R
}
}
//AdminGetSiteHandler returns the template containing the sites
// AdminGetSiteHandler returns a specific site by the ID
func AdminGetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "siteID")
@ -76,7 +76,7 @@ func AdminGetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
}
}
//AdminSitesHandler returns the template containing the sites overview in the administration
// AdminSitesHandler returns all sites
func AdminSitesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
page := getPageParam(r)
@ -121,7 +121,7 @@ func AdminSitesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
}
}
//AdminSiteNewHandler returns the template for adding a new site
// AdminSiteNewHandler returns the form for adding a new site
func AdminSiteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Name: tplAdminSiteNew,
@ -129,8 +129,8 @@ func AdminSiteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
}
}
//AdminSiteNewPostHandler receives the form values and creating the site; on success the user is redirected with a success message
//to the site overview
// AdminSiteNewPostHandler receives the form values and creating the site; on success the user is redirected with a success message
// to the site overview
func AdminSiteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
user, _ := middleware.User(r)
@ -169,7 +169,7 @@ func AdminSiteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminSiteEditHandler returns the template for editing an existing site
// AdminSiteEditHandler returns the form for changing an existing site
func AdminSiteEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
siteID, err := parseInt(getVar(r, "siteID"))
@ -198,8 +198,8 @@ func AdminSiteEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
}
}
//AdminSiteEditPostHandler receives the form values and updates the site; on success the user is redirected with a success message
//to the site overview
// AdminSiteEditPostHandler receives the form values and updates the site; on success the user is redirected with a success message
// to the site overview
func AdminSiteEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u, _ := middleware.User(r)
@ -244,7 +244,7 @@ func AdminSiteEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminSiteOrderHandler moves the site with site id down or up
// AdminSiteOrderHandler moves the site with site ID down or up
func AdminSiteOrderHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
siteID, err := parseInt(getVar(r, "siteID"))
@ -286,7 +286,7 @@ func AdminSiteOrderHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}
}
//AdminSitePublishHandler returns the action template which asks the user if the site should be published / unpublished
// AdminSitePublishHandler returns the action template which asks the user if the site should be published / unpublished
func AdminSitePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "siteID")
@ -338,7 +338,7 @@ func AdminSitePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminSitePublishPostHandler handles the un-/publishing of a site
// AdminSitePublishPostHandler handles the un-/publishing of a site
func AdminSitePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "siteID")
@ -367,7 +367,7 @@ func AdminSitePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
}
}
//AdminSiteDeleteHandler returns the action template which asks the user if the site should be removed
// AdminSiteDeleteHandler returns the action which asks the user if the site should be removed
func AdminSiteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "siteID")
@ -408,7 +408,7 @@ func AdminSiteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}
}
//AdminSiteDeletePostHandler handles the removing of a site
// AdminSiteDeletePostHandler handles the removing of a site
func AdminSiteDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
reqVar := getVar(r, "siteID")

View File

@ -13,7 +13,7 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
//AdminUsersHandler returns an overview of the created users (admin only action)
// AdminUsersHandler returns an overview of the created users
func AdminUsersHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
page := getPageParam(r)
@ -73,7 +73,7 @@ func AdminUsersHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
}
}
//AdminUserNewHandler returns the form for adding new user (admin only action)
// AdminUserNewHandler returns the form for adding new user
func AdminUserNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Name: tplAdminUserNew,
@ -81,7 +81,7 @@ func AdminUserNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
}
}
//AdminUserNewPostHandler handles the creation of new users (admin only action)
// AdminUserNewPostHandler handles the creation of new users
func AdminUserNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
u := &models.User{
DisplayName: r.FormValue("displayname"),
@ -114,7 +114,7 @@ func AdminUserNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminUserEditHandler returns the form for editing an user (admin only action)
// AdminUserEditHandler returns the form for editing an user
func AdminUserEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
userID, err := parseInt(getVar(r, "userID"))
@ -143,7 +143,7 @@ func AdminUserEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
}
}
//AdminUserEditPostHandler handles the updating of an user (admin only action)
// AdminUserEditPostHandler handles the updating of an user
func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
userID, err := parseInt(getVar(r, "userID"))
@ -196,7 +196,7 @@ func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
sessions := ctx.SessionService.SessionProvider.FindSessionsByValue("userid", u.ID)
sessions := ctx.SessionService.SessionProvider.FindByValue("userid", u.ID)
for _, s := range sessions {
if session.SessionID() != s.SessionID() {
@ -212,7 +212,7 @@ func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
}
}
//AdminUserDeleteHandler returns the form for removing user (admin only action)
// AdminUserDeleteHandler returns the form for removing a user
func AdminUserDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
userID, err := parseInt(getVar(r, "userID"))
@ -256,7 +256,7 @@ func AdminUserDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
}
}
//AdminUserDeletePostHandler handles removing of a user (admin only action)
// AdminUserDeletePostHandler handles removing of a user
func AdminUserDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
userID, err := parseInt(getVar(r, "userID"))

View File

@ -8,6 +8,7 @@ import (
"git.hoogi.eu/snafu/go-blog/models"
)
// AdminUserInviteNewHandler shows the form to invite an user
func AdminUserInviteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
return &middleware.Template{
Name: tplAdminUserInviteNew,
@ -15,6 +16,7 @@ func AdminUserInviteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter
}
}
// AdminUserInviteNewPostHandler handles the invitation, sends an activation mail to the invited user
func AdminUserInviteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
user, _ := middleware.User(r)
@ -52,6 +54,7 @@ func AdminUserInviteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWr
}
}
// AdminUserInviteResendPostHandler resends the activation link to the user
func AdminUserInviteResendPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
inviteID, err := parseInt(getVar(r, "inviteID"))
@ -86,6 +89,7 @@ func AdminUserInviteResendPostHandler(ctx *middleware.AppContext, w http.Respons
}
}
// AdminUserInviteDeleteHandler shows the form to remove an user invitation
func AdminUserInviteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
inviteID, err := parseInt(getVar(r, "inviteID"))
@ -124,6 +128,7 @@ func AdminUserInviteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWri
}
}
// AdminUserInviteDeletePostHandler handles the removing of an user invitation
func AdminUserInviteDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
inviteID, err := parseInt(getVar(r, "inviteID"))

View File

@ -115,7 +115,7 @@ func setup(t *testing.T) {
AppConfig: &cfg.Application,
}
sessionService := session.SessionService{
sessionService := session.Service{
Path: "/admin",
Name: "test-session",
HTTPOnly: true,
@ -147,7 +147,7 @@ func teardown() {
func fillSeeds(db *sql.DB) error {
salt := crypt.GenerateSalt()
saltedPassword := append([]byte("123456789012"), salt[:]...)
password, err := crypt.CryptPassword([]byte(saltedPassword), 12)
password, err := crypt.CryptPassword([]byte(saltedPassword))
if err != nil {
return err

View File

@ -9,23 +9,23 @@ import (
"net/http"
)
//Error enriches the original go error type with
//DisplayMsg the description for the displaying message
//HTTPStatus the HTTP status code
//Err the internal error it should not be shown to the user
// Error enriches the original go error type with
// DisplayMsg the human readable display message
// HTTPStatus the HTTP status code
// Err the internal error
type Error struct {
DisplayMsg string `json:"display_message"`
HTTPStatus int `json:"status"`
Err error `json:"-"`
}
//New returns a new error
// New returns a new error
func New(httpStatus int, displayMsg string, err error) *Error {
return &Error{DisplayMsg: displayMsg, Err: err, HTTPStatus: httpStatus}
}
//PermissionDenied returns a permission denied message with code 403.
//The following display message is returned: "You are not allowed to [action] the [subject]."
// PermissionDenied returns a permission denied message with code 403.
// The following display message is returned: "You are not allowed to [action] the [subject]."
func PermissionDenied(action, subject string, err error) *Error {
return &Error{
HTTPStatus: http.StatusForbidden,
@ -34,8 +34,8 @@ func PermissionDenied(action, subject string, err error) *Error {
}
}
//NotFound returns a not found message with code 404.
//The following display message is returned: "The [res] was not found."
// NotFound returns a not found message with code 404.
// The following display message is returned: "The [res] was not found."
func NotFound(res string, err error) *Error {
return &Error{
HTTPStatus: http.StatusNotFound,
@ -44,8 +44,8 @@ func NotFound(res string, err error) *Error {
}
}
//ValueTooLong returns the following display message with code 422.
//Display message: "The value of [param] is too long. Maximum [nchars] characters are allowed."
// ValueTooLong returns the following display message with code 422.
// Display message: "The value of [param] is too long. Maximum [nchars] characters are allowed."
func ValueTooLong(param string, nchars int) *Error {
return &Error{
HTTPStatus: http.StatusUnprocessableEntity,
@ -54,18 +54,18 @@ func ValueTooLong(param string, nchars int) *Error {
}
}
//InternalServerError returns a internal server error message with code 500.
//Display message: "An internal server error occured."
// InternalServerError returns a internal server error message with code 500.
// Display message: "An internal server error occurred."
func InternalServerError(err error) *Error {
return &Error{
HTTPStatus: http.StatusInternalServerError,
DisplayMsg: "An internal server error occured.",
DisplayMsg: "An internal server error occurred.",
Err: err,
}
}
//ParameterMissing returns a parameter missing message with code 422.
//Display message: "The parameter [param] is invalid."
// ParameterMissing returns a parameter missing message with code 422.
// Display message: "The parameter [param] is invalid."
func ParameterMissing(param string, err error) *Error {
return &Error{
HTTPStatus: http.StatusUnprocessableEntity,
@ -74,8 +74,8 @@ func ParameterMissing(param string, err error) *Error {
}
}
//ValueRequired returns a value required message with code 422.
//Display message: "Please fill out the field [param]."
// ValueRequired returns a value required message with code 422.
// Display message: "Please fill out the field [param]."
func ValueRequired(param string) *Error {
return &Error{
HTTPStatus: http.StatusUnprocessableEntity,

View File

@ -11,12 +11,12 @@ import (
"github.com/sirupsen/logrus"
)
//Log returns a new logrus instance
// Log returns a new logrus instance
var Log = logrus.New()
//InitLogger initializes the logger
//Valid log levels are: debug|info|warn|error|fatal|panic
//Fallback: info
// InitLogger initializes the logger
// Valid log levels are: debug|info|warn|error|fatal|panic
// Fallback: info
func InitLogger(w io.Writer, level string) {
level = strings.ToLower(level)

View File

@ -9,8 +9,8 @@ import (
"git.hoogi.eu/snafu/go-blog/logger"
)
//Service holds configuration for the SMTP server
//The sender address and an optional subject prefix
// Service holds configuration for the SMTP server
// The sender address and an optional subject prefix
type Service struct {
SubjectPrefix string
SMTPConfig SMTPConfig
@ -25,7 +25,7 @@ func (m Mail) validate() error {
return nil
}
//NewMailService returns a new Service with specified config
// NewMailService returns a new Service with specified config
func NewMailService(subjectPrefix, from string, smtpConfig SMTPConfig) Service {
s := Service{
SubjectPrefix: subjectPrefix,
@ -44,16 +44,16 @@ type Sender interface {
SendAsync(m Mail)
}
//SMTPConfig holds the configuration for the SMTP server
// SMTPConfig holds the configuration for the SMTP server
type SMTPConfig struct {
Address string
Port int
User string
Helo string
HELO string
Password []byte
}
//Mail represents a mail
// Mail represents a mail
type Mail struct {
To string
Subject string
@ -89,7 +89,7 @@ func (s Service) SendAsync(m Mail) {
}()
}
//Send sends a mail over the configured SMTP server
// Send sends a mail over the configured SMTP server
func (s Service) Send(m Mail) error {
if len(s.SMTPConfig.User) > 0 && len(s.SMTPConfig.Password) > 0 {
auth := smtp.PlainAuth("", s.SMTPConfig.User, string(s.SMTPConfig.Password), s.SMTPConfig.Address)
@ -109,8 +109,8 @@ func (s Service) Send(m Mail) error {
return err
}
if len(s.SMTPConfig.Helo) > 0 {
if err := c.Hello(s.SMTPConfig.Helo); err != nil {
if len(s.SMTPConfig.HELO) > 0 {
if err := c.Hello(s.SMTPConfig.HELO); err != nil {
return err
}
}

40
main.go
View File

@ -36,19 +36,19 @@ func main() {
}()
configFiles := []cfg.File{
cfg.File{
{
Name: "go-blog.conf",
Path: ".",
Required: true,
},
cfg.File{
{
Name: "go-blog.conf",
Path: "./custom",
Required: false,
},
}
cfg, err := settings.MergeConfigs(configFiles)
config, err := settings.MergeConfigs(configFiles)
if err != nil {
exitCode = 1
@ -56,29 +56,29 @@ func main() {
return
}
cfg.BuildVersion = BuildVersion
cfg.BuildGitHash = GitHash
config.BuildVersion = BuildVersion
config.BuildGitHash = GitHash
if err = cfg.CheckConfig(); err != nil {
if err = config.CheckConfig(); err != nil {
exitCode = 1
fmt.Println(err)
return
}
if cfg.Environment == "prod" {
logFile, err := os.OpenFile(cfg.Log.File, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if config.Environment == "prod" {
logFile, err := os.OpenFile(config.Log.File, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if err != nil {
fmt.Println(err)
exitCode = 1
}
logger.InitLogger(logFile, cfg.Log.Level)
logger.InitLogger(logFile, config.Log.Level)
} else {
logger.InitLogger(os.Stdout, cfg.Log.Level)
logger.InitLogger(os.Stdout, config.Log.Level)
}
csrf, err := cfg.GenerateCSRF()
csrf, err := config.GenerateCSRF()
if err != nil {
exitCode = 1
@ -91,10 +91,10 @@ func main() {
}
logger.Log.Infof("Go-Blog version: %s, commit: %s", BuildVersion, GitHash)
logger.Log.Infof("running in %s mode", cfg.Environment)
logger.Log.Infof("running in %s mode", config.Environment)
dbConf := database.SQLiteConfig{
File: cfg.Database.File,
File: config.Database.File,
}
db, err := dbConf.Open()
@ -112,7 +112,7 @@ func main() {
}
}()
ctx, err := context(db, cfg)
ctx, err := context(db, config)
if err != nil {
logger.Log.Error(err)
@ -120,20 +120,20 @@ func main() {
return
}
r := routers.InitRoutes(ctx, cfg)
r := routers.InitRoutes(ctx, config)
s := &http.Server{
Addr: fmt.Sprintf("%s:%d", cfg.Server.Address, cfg.Server.Port),
Addr: fmt.Sprintf("%s:%d", config.Server.Address, config.Server.Port),
Handler: r,
ReadTimeout: 15 * time.Second,
WriteTimeout: 20 * time.Second,
MaxHeaderBytes: 1 << 20,
}
logger.Log.Infof("server will start at %s on port %d", cfg.Server.Address, cfg.Server.Port)
logger.Log.Infof("server will start at %s on port %d", config.Server.Address, config.Server.Port)
if cfg.Server.UseTLS {
err = s.ListenAndServeTLS(cfg.Server.Cert, cfg.Server.Key)
if config.Server.UseTLS {
err = s.ListenAndServeTLS(config.Server.Cert, config.Server.Key)
} else {
err = s.ListenAndServe()
@ -221,7 +221,7 @@ func context(db *sql.DB, cfg *settings.Settings) (*m.AppContext, error) {
return nil, err
}
sessionService := session.SessionService{
sessionService := session.Service{
Path: cfg.Session.CookiePath,
Name: cfg.Session.CookieName,
Secure: cfg.Session.CookieSecure,

View File

@ -12,9 +12,9 @@ import (
"git.hoogi.eu/snafu/session"
)
//AppContext contains the services, session store, templates, ...
// AppContext contains the services, session store, templates, ...
type AppContext struct {
SessionService *session.SessionService
SessionService *session.Service
ArticleService models.ArticleService
CategoryService models.CategoryService
UserService models.UserService

View File

@ -19,7 +19,7 @@ type JSONHandler struct {
Handler JHandler
}
//JHandler enriches handler with the AppContext
// JHandler enriches handler with the AppContext
type JHandler func(*AppContext, http.ResponseWriter, *http.Request) (*models.JSONData, error)
func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
@ -41,6 +41,7 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
logger.Log.Error(err)
j, err := json.Marshal(err)
if err != nil {
logger.Log.Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
@ -48,7 +49,14 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
}
rw.WriteHeader(code)
rw.Write(j)
_, err = rw.Write(j)
if err != nil {
logger.Log.Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
return
}
@ -61,5 +69,12 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
}
rw.WriteHeader(code)
rw.Write(j)
_, err = rw.Write(j)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
rw.WriteHeader(http.StatusInternalServerError)
return
}
}

View File

@ -15,15 +15,15 @@ import (
)
var locals = [...]net.IPNet{
net.IPNet{
{
IP: net.IPv4(10, 0, 0, 0),
Mask: net.CIDRMask(8, 32),
},
net.IPNet{
{
IP: net.IPv4(172, 16, 0, 0),
Mask: net.CIDRMask(12, 32),
},
net.IPNet{
{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(16, 32),
},

View File

@ -36,13 +36,13 @@ type Template struct {
Err error
}
//Templates defines in which directory should be looked for template
// Templates defines in which directory should be looked for template
type Templates struct {
Directory string
FuncMap template.FuncMap
}
//NotFound returned if no route matches
// NotFound returned if no route matches
func NotFound(ctx *AppContext, rw http.ResponseWriter, r *http.Request) *Template {
//For deleting flash cookies
getFlash(rw, r, "ErrorMsg")
@ -63,7 +63,7 @@ func NotFound(ctx *AppContext, rw http.ResponseWriter, r *http.Request) *Templat
}
}
//FuncMap some function that can be used in templates
// FuncMap some function that can be used in templates
func FuncMap(ss models.SiteService, settings *settings.Settings) template.FuncMap {
return template.FuncMap{
"GetMetadata": func(data map[string]interface{}) template.HTML {
@ -202,7 +202,7 @@ func FuncMap(ss models.SiteService, settings *settings.Settings) template.FuncMa
}
}
//Load walks threw directory and parses templates ending with html
// Load walks threw directory and parses templates ending with html
func (ts Templates) Load() (*template.Template, error) {
tpl := template.New("").Funcs(ts.FuncMap)
@ -227,7 +227,7 @@ func (ts Templates) Load() (*template.Template, error) {
return tpl, err
}
//RedirectURL builds a URL for redirecting
// RedirectURL builds a URL for redirecting
func (t Template) RedirectURL() string {
if t.RedirectPath[0] == byte('/') {
return t.RedirectPath

View File

@ -23,13 +23,13 @@ var (
UserContextKey = contextKey("user")
)
//TemplateHandler enriches handlers with a application context containing 'services'
// TemplateHandler enriches handlers with a application context containing 'services'
type TemplateHandler struct {
AppCtx *AppContext
Handler Handler
}
//Handler enriches handler with the AppContext
// Handler enriches handler with the AppContext
type Handler func(*AppContext, http.ResponseWriter, *http.Request) *Template
func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
@ -66,7 +66,7 @@ func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
errorMsg = e.DisplayMsg
default:
en.Error(e)
errorMsg = "Sorry, an internal server error occured"
errorMsg = "Sorry, an internal server error occurred"
}
t.Data["ErrorMsg"] = errorMsg
@ -119,7 +119,7 @@ func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
}
}
//AuthHandler checks if the user is authenticated; if not next handler in chain is not called
// AuthHandler checks if the user is authenticated; if not next handler in chain is not called
func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
fn := func(rw http.ResponseWriter, r *http.Request) {
session, err := ctx.SessionService.Get(rw, r)
@ -127,11 +127,14 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
if err != nil {
logger.Log.Error(err)
rw.WriteHeader(http.StatusUnauthorized)
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
"ErrorMsg": "Please provide login credentials.",
"state": r.URL.EscapedPath(),
csrf.TemplateTag: csrf.TemplateField(r),
})
}); err != nil {
logger.Log.Errorf("error while executing the template %v", err)
return
}
return
}
@ -141,11 +144,15 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
logger.Log.Errorf("userid is not an integer %v", userid)
rw.WriteHeader(http.StatusUnauthorized)
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
"ErrorMsg": "Please provide login credentials.",
"state": r.URL.EscapedPath(),
csrf.TemplateTag: csrf.TemplateField(r),
})
}); err != nil {
logger.Log.Errorf("error while executing the template %v", err)
return
}
return
}
@ -154,11 +161,14 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
if err != nil {
logger.Log.Error(err)
rw.WriteHeader(http.StatusUnauthorized)
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
"ErrorMsg": "Please provide login credentials.",
"state": r.URL.EscapedPath(),
csrf.TemplateTag: csrf.TemplateField(r),
})
}); err != nil {
logger.Log.Errorf("error while executing the template %v", err)
return
}
return
}
@ -167,24 +177,30 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
return http.HandlerFunc(fn)
}
//RequireAdmin ensures that the user is an admin; if not next handler in chain is not called
// RequireAdmin ensures that the user is an admin; if not next handler in chain is not called
func (ctx AppContext) RequireAdmin(handler http.Handler) http.Handler {
fn := func(rw http.ResponseWriter, r *http.Request) {
u, err := User(r)
if err != nil {
logger.Log.Error(err)
ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
"ErrorMsg": "An internal server error occured",
})
if err := ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
"ErrorMsg": "An internal server error occurred",
}); err != nil {
logger.Log.Errorf("error while executing the template %v", err)
return
}
return
}
if u.IsAdmin == false {
ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
if err := ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
"ErrorMsg": "You have not the permissions to execute this action",
"currentUser": u,
})
}); err != nil {
logger.Log.Errorf("error while executing the template %v", err)
return
}
return
}
@ -193,7 +209,7 @@ func (ctx AppContext) RequireAdmin(handler http.Handler) http.Handler {
return http.HandlerFunc(fn)
}
//User gets the user from the request context
// User gets the user from the request context
func User(r *http.Request) (*models.User, error) {
v := r.Context().Value(UserContextKey)
if v == nil {

View File

@ -15,7 +15,7 @@ type XMLHandler struct {
Handler XHandler
}
//XNLHandler enriches handler with the AppContext
// XHandler enriches handler with the AppContext
type XHandler func(*AppContext, http.ResponseWriter, *http.Request) (*models.XMLData, error)
func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
@ -34,7 +34,12 @@ func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
return
}
rw.Write(x)
if _, err = rw.Write(x); err != nil {
logger.Log.Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
return
}
@ -55,5 +60,9 @@ func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
x = bytes.Replace(x, []byte("&gt;"), []byte("&#x3e;"), -1) // >
}
rw.Write(x)
if _, err := rw.Write(x); err != nil {
logger.Log.Error(err)
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
}

View File

@ -37,7 +37,7 @@ type Article struct {
CName sql.NullString
}
//ArticleDatasourceService defines an interface for CRUD operations of articles
// ArticleDatasourceService defines an interface for CRUD operations of articles
type ArticleDatasourceService interface {
Create(a *Article) (int, error)
List(u *User, c *Category, p *Pagination, pc PublishedCriteria) ([]Article, error)
@ -53,7 +53,7 @@ const (
maxHeadlineSize = 150
)
//SlugEscape escapes the slug for use in URLs
// SlugEscape escapes the slug for use in URLs
func (a Article) SlugEscape() string {
spl := strings.Split(a.Slug, "/")
return fmt.Sprintf("%s/%s/%s", spl[0], spl[1], url.PathEscape(spl[2]))
@ -106,7 +106,7 @@ func (a *Article) validate() error {
return nil
}
//ArticleService containing the service to access articles
// ArticleService containing the service to access articles
type ArticleService struct {
Datasource ArticleDatasourceService
AppConfig settings.Application
@ -129,7 +129,7 @@ func (as ArticleService) Create(a *Article) (int, error) {
return as.Datasource.Create(a)
}
//Update updates an article
// Update updates an article
func (as ArticleService) Update(a *Article, u *User, updateSlug bool) error {
if err := a.validate(); err != nil {
return err
@ -161,7 +161,7 @@ func (as ArticleService) Update(a *Article, u *User, updateSlug bool) error {
return as.Datasource.Update(a)
}
//Publish publishes or 'unpublishes' an article
// Publish publishes or 'unpublishes' an article
func (as ArticleService) Publish(id int, u *User) error {
a, err := as.Datasource.Get(id, nil, All)
@ -178,7 +178,7 @@ func (as ArticleService) Publish(id int, u *User) error {
return as.Datasource.Publish(a)
}
//Delete deletes an article
// Delete deletes an article
func (as ArticleService) Delete(id int, u *User) error {
a, err := as.Datasource.Get(id, nil, All)

View File

@ -1,8 +1,9 @@
package models
import (
"bytes"
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"strings"
"time"
)
@ -38,8 +39,8 @@ func (rdb SQLiteArticleDatasource) Create(a *Article) (int, error) {
return int(id), nil
}
//List returns a slice of articles; if the user is not nil the number of articles for this explcit user is returned
//the PublishedCritera specifies which articles should be considered
// List returns a slice of articles; if the user is not nil the number of articles for this explcit user is returned
// the PublishedCritera specifies which articles should be considered
func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc PublishedCriteria) ([]Article, error) {
rows, err := selectArticlesStmt(rdb.SQLConn, u, c, p, pc)
@ -47,7 +48,11 @@ func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
articles := []Article{}
@ -72,12 +77,12 @@ func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc
}
//Count returns the number of article found; if the user is not nil the number of articles for this explcit user is returned
//the PublishedCritera specifies which articles should be considered
// Count returns the number of article found; if the user is not nil the number of articles for this explcit user is returned
// the PublishedCritera specifies which articles should be considered
func (rdb SQLiteArticleDatasource) Count(u *User, c *Category, pc PublishedCriteria) (int, error) {
var total int
var stmt strings.Builder
var args []interface{}
var stmt bytes.Buffer
stmt.WriteString("SELECT count(a.id) FROM article a ")
@ -116,8 +121,8 @@ func (rdb SQLiteArticleDatasource) Count(u *User, c *Category, pc PublishedCrite
return total, nil
}
//Get returns a article by its id; if the user is not nil the article for this explcit user is returned
//the PublishedCritera specifies which articles should be considered
// Get returns a article by its id; if the user is not nil the article for this explcit user is returned
// the PublishedCritera specifies which articles should be considered
func (rdb SQLiteArticleDatasource) Get(articleID int, u *User, pc PublishedCriteria) (*Article, error) {
var a Article
var ru User
@ -132,8 +137,8 @@ func (rdb SQLiteArticleDatasource) Get(articleID int, u *User, pc PublishedCrite
return &a, nil
}
//GetBySlug returns a article by its slug; if the user is not nil the article for this explcit user is returned
//the PublishedCritera specifies which articles should be considered
// GetBySlug returns a article by its slug; if the user is not nil the article for this explcit user is returned
// the PublishedCritera specifies which articles should be considered
func (rdb SQLiteArticleDatasource) GetBySlug(slug string, u *User, pc PublishedCriteria) (*Article, error) {
var a Article
var ru User
@ -183,7 +188,7 @@ func (rdb SQLiteArticleDatasource) Delete(articleID int) error {
}
func selectArticleStmt(db *sql.DB, articleID int, slug string, u *User, pc PublishedCriteria) *sql.Row {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
@ -224,7 +229,7 @@ func selectArticleStmt(db *sql.DB, articleID int, slug string, u *User, pc Publi
}
func selectArticlesStmt(db *sql.DB, u *User, c *Category, p *Pagination, pc PublishedCriteria) (*sql.Rows, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT a.id, a.headline, a.teaser, a.content, a.published, a.published_on, a.slug, a.last_modified, ")

View File

@ -52,12 +52,12 @@ type CategoryDatasourceService interface {
Delete(categoryID int) error
}
//CategoryService containing the service to access categories
// CategoryService containing the service to access categories
type CategoryService struct {
Datasource CategoryDatasourceService
}
//SlugEscape escapes the slug for use in URLs
// SlugEscape escapes the slug for use in URLs
func (c Category) SlugEscape() string {
return url.PathEscape(c.Slug)
}
@ -96,7 +96,7 @@ func (cs CategoryService) List(fc FilterCriteria) ([]Category, error) {
return cs.Datasource.List(fc)
}
//Create creates a category
// Create creates a category
func (cs CategoryService) Create(c *Category) (int, error) {
for i := 0; i < 10; i++ {
c.Slug = slug.CreateURLSafeSlug(c.Name, i)
@ -122,7 +122,7 @@ func (cs CategoryService) Create(c *Category) (int, error) {
return cid, nil
}
//Update updates a category
// Update updates a category
func (cs CategoryService) Update(c *Category) error {
if err := c.validate(); err != nil {
return err
@ -131,7 +131,7 @@ func (cs CategoryService) Update(c *Category) error {
return cs.Datasource.Update(c)
}
//Delete removes a category
// Delete removes a category
func (cs CategoryService) Delete(id int) error {
c, err := cs.Datasource.Get(id, AllCategories)

View File

@ -3,10 +3,12 @@ package models
import (
"bytes"
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"strings"
"time"
)
// SQLiteArticleDatasource providing an implementation of ArticleDatasourceService for SQLite
// SQLiteCategoryDatasource providing an implementation of CategoryDatasourceService for SQLite
type SQLiteCategoryDatasource struct {
SQLConn *sql.DB
}
@ -34,7 +36,7 @@ func (rdb SQLiteCategoryDatasource) Create(c *Category) (int, error) {
func (rdb SQLiteCategoryDatasource) List(fc FilterCriteria) ([]Category, error) {
var args []interface{}
var stmt bytes.Buffer
var stmt strings.Builder
stmt.WriteString("SELECT DISTINCT c.id, c.name, c.slug, c.last_modified, ")
stmt.WriteString("u.id, u.display_name, u.username, u.email, u.is_admin ")
@ -60,7 +62,11 @@ func (rdb SQLiteCategoryDatasource) List(fc FilterCriteria) ([]Category, error)
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
var cs []Category
@ -131,7 +137,7 @@ func (rdb SQLiteCategoryDatasource) Get(categoryID int, fc FilterCriteria) (*Cat
}
func (rdb SQLiteCategoryDatasource) GetBySlug(slug string, fc FilterCriteria) (*Category, error) {
var stmt bytes.Buffer
var stmt strings.Builder
stmt.WriteString("SELECT c.id, c.name, c.slug, c.last_modified, ")
stmt.WriteString("u.id, u.display_name, u.username, u.email, u.is_admin ")

View File

@ -4,12 +4,12 @@
package models
// JSONData represents arbritary JSON data
// JSONData represents arbitrary JSON data
type JSONData struct {
Data interface{} `json:"data,-" xml:"data,-"`
}
// XMLData represents arbritary XML data
// XMLData represents arbitrary XML data
type XMLData struct {
Data interface{} `xml:"data,-"`
HexEncode bool `xml:"-"`

View File

@ -18,7 +18,7 @@ import (
"git.hoogi.eu/snafu/go-blog/settings"
)
//File represents a file
// File represents a file
type File struct {
ID int
UniqueName string `json:"unique_name"`
@ -33,15 +33,15 @@ type File struct {
Author *User
}
//FileInfo contains Path, Name and Extension of a file.
//Use SplitFilename to split the information from a filename
// FileInfo contains Path, Name and Extension of a file.
// Use SplitFilename to split the information from a filename
type FileInfo struct {
Path string
Name string
Extension string
}
//FileDatasourceService defines an interface for CRUD operations of files
// FileDatasourceService defines an interface for CRUD operations of files
type FileDatasourceService interface {
Create(f *File) (int, error)
Get(fileID int, u *User) (*File, error)
@ -100,26 +100,26 @@ func SplitFilename(filename string) FileInfo {
}
}
//FileService containing the service to interact with files
// FileService containing the service to interact with files
type FileService struct {
Datasource FileDatasourceService
Config settings.File
}
//GetByID returns the file based on the fileID; it the user is given and it is a non admin
//only file specific to this user is returned
// GetByID returns the file based on the fileID; it the user is given and it is a non admin
// only file specific to this user is returned
func (fs FileService) GetByID(fileID int, u *User) (*File, error) {
return fs.Datasource.Get(fileID, u)
}
//GetByUniqueName returns the file based on the unique name; it the user is given and it is a non admin
//only file specific to this user is returned
// GetByUniqueName returns the file based on the unique name; it the user is given and it is a non admin
// only file specific to this user is returned
func (fs FileService) GetByUniqueName(uniqueName string, u *User) (*File, error) {
return fs.Datasource.GetByUniqueName(uniqueName, u)
}
//List returns a list of files based on the filename; it the user is given and it is a non admin
//only files specific to this user are returned
// List returns a list of files based on the filename; it the user is given and it is a non admin
// only files specific to this user are returned
func (fs FileService) List(u *User, p *Pagination) ([]File, error) {
return fs.Datasource.List(u, p)
}
@ -152,7 +152,7 @@ func (fs FileService) ToggleInline(fileID int, u *User) error {
return fs.Datasource.Update(f)
}
//Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files; except admins
// Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files; except admins
func (fs FileService) Delete(fileID int, u *User) error {
file, err := fs.Datasource.Get(fileID, u)
@ -175,7 +175,7 @@ func (fs FileService) Delete(fileID int, u *User) error {
return os.Remove(filepath.Join(fs.Config.Location, file.UniqueName))
}
//Upload uploaded files will be saved at the configured file location, filename is saved in the database
// Upload uploaded files will be saved at the configured file location, filename is saved in the database
func (fs FileService) Upload(f *File) (int, error) {
if err := f.validate(); err != nil {
return -1, err
@ -256,7 +256,7 @@ func isDot(r rune) bool {
return '.' == r
}
//SanitizeFilename sanitizes a filename for safe use when serving file
// sanitizeFilename sanitizes a filename for safe use when serving file
func sanitizeFilename(s string) string {
s = strings.ToValidUTF8(s, "")
s = strings.TrimFunc(s, unicode.IsSpace)

View File

@ -1,20 +1,21 @@
package models
import (
"bytes"
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"strings"
"time"
)
//SQLiteFileDatasource providing an implementation of FileDatasourceService using MariaDB
// SQLiteFileDatasource providing an implementation of FileDatasourceService using MariaDB
type SQLiteFileDatasource struct {
SQLConn *sql.DB
}
//GetByFilename returns the file based on the filename; it the user is given and it is a non admin
//only file specific to this user is returned
// GetByUniqueName returns the file based on the unique filename; it the user is given and it is a non admin
// only file specific to this user is returned
func (rdb SQLiteFileDatasource) GetByUniqueName(uniqueName string, u *User) (*File, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT f.id, f.filename, f.unique_name, f.content_type, f.inline, f.size, f.last_modified, f.user_id, ")
@ -46,10 +47,10 @@ func (rdb SQLiteFileDatasource) GetByUniqueName(uniqueName string, u *User) (*Fi
return &f, nil
}
//Get returns the file based on the filename; it the user is given and it is a non admin
//only file specific to this user is returned
// Get returns the file based on the filename; it the user is given and it is a non admin
// only file specific to this user is returned
func (rdb SQLiteFileDatasource) Get(fileID int, u *User) (*File, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT f.id, f.filename, f.unique_name, f.content_type, f.inline, f.size, f.last_modified, f.user_id, ")
@ -81,7 +82,7 @@ func (rdb SQLiteFileDatasource) Get(fileID int, u *User) (*File, error) {
return &f, nil
}
//Create inserts some file meta information into the database
// Create inserts some file meta information into the database
func (rdb SQLiteFileDatasource) Create(f *File) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO file (filename, unique_name, content_type, inline, size, last_modified, user_id) VALUES(?, ?, ?, ?, ?, ?, ?)",
f.FullFilename, f.UniqueName, f.ContentType, f.Inline, f.Size, time.Now(), f.Author.ID)
@ -107,10 +108,10 @@ func (rdb SQLiteFileDatasource) Update(f *File) error {
return nil
}
//List returns a list of files based on the filename; it the user is given and it is a non admin
//only files specific to this user are returned
// List returns a list of files based on the filename; it the user is given and it is a non admin
// only files specific to this user are returned
func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
@ -140,7 +141,13 @@ func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
return nil, err
}
defer rows.Close()
defer func() {
err := rows.Close()
if err != nil {
logger.Log.Error(err)
}
}()
var files []File
var f File
@ -165,10 +172,10 @@ func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
}
//Count returns a number of files based on the filename; it the user is given and it is a non admin
//only files specific to this user are counted
// Count returns a number of files based on the filename; it the user is given and it is a non admin
// only files specific to this user are counted
func (rdb SQLiteFileDatasource) Count(u *User) (int, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
@ -190,8 +197,8 @@ func (rdb SQLiteFileDatasource) Count(u *User) (int, error) {
return total, nil
}
//Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files;
//except admins
// Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files;
// except admins
func (rdb SQLiteFileDatasource) Delete(fileID int) error {
if _, err := rdb.SQLConn.Exec("DELETE FROM file WHERE id=?", fileID); err != nil {
return err

View File

@ -13,15 +13,11 @@ import (
bf "github.com/russross/blackfriday/v2"
)
// Defines the extensions that are used
// ext Defines the extensions that are used
var ext = bf.NoIntraEmphasis | bf.Tables | bf.FencedCode | bf.Autolink |
bf.Strikethrough | bf.SpaceHeadings | bf.BackslashLineBreak |
bf.DefinitionLists | bf.Footnotes | bf.HardLineBreak
// Defines the HTML rendering flags that are used
var flags = bf.UseXHTML | bf.Smartypants | bf.SmartypantsFractions |
bf.SmartypantsDashes | bf.SmartypantsLatexDashes | bf.TOC
var p *bluemonday.Policy
func init() {
@ -30,7 +26,7 @@ func init() {
p.AllowAttrs("style").OnElements("span")
}
//MarkdownToHTML sanitizes and parses markdown to HTML
// MarkdownToHTML sanitizes and parses markdown to HTML
func MarkdownToHTML(md []byte) []byte {
md = bytes.Replace(md, []byte("\r\n"), []byte("\n"), -1)
unsafe := bf.Run((md), bf.WithExtensions(ext))

View File

@ -15,33 +15,33 @@ type Mailer struct {
func (m Mailer) SendActivationLink(ui *UserInvite) {
activation := m.AppConfig.Domain + "/admin/activate-account/" + ui.Hash
mail := mail.Mail{
ml := mail.Mail{
To: ui.Email,
Subject: "You got an invitation",
Body: fmt.Sprintf("Hi %s,\n\n you are invited join %s. To activate your account click the following link and enter a password %s", ui.DisplayName, m.AppConfig.Title, activation),
}
m.Sender.SendAsync(mail)
m.Sender.SendAsync(ml)
}
func (m Mailer) SendPasswordChangeConfirmation(u *User) {
mail := mail.Mail{
ml := mail.Mail{
To: u.Email,
Subject: "Password change",
Body: fmt.Sprintf("Hi %s,\n\nyour password change was successful.", u.DisplayName),
}
m.Sender.SendAsync(mail)
m.Sender.SendAsync(ml)
}
func (m Mailer) SendPasswordResetLink(u *User, t *Token) {
resetLink := m.AppConfig.Domain + "/admin/reset-password/" + t.Hash
mail := mail.Mail{
ml := mail.Mail{
To: u.Email,
Subject: "Changing password instructions",
Body: fmt.Sprintf("Hi %s,\n\nuse the following link to reset your password:\n\n%s", u.DisplayName, resetLink),
}
m.Sender.SendAsync(mail)
m.Sender.SendAsync(ml)
}

View File

@ -11,7 +11,7 @@ import (
"strings"
)
//Pagination type is used to provide a page selector
// Pagination type is used to provide a page selector
type Pagination struct {
Total int
Limit int
@ -19,12 +19,12 @@ type Pagination struct {
RelURL string
}
//Offset returns the offset where to start
// Offset returns the offset where to start
func (p Pagination) Offset() int {
return (p.CurrentPage - 1) * p.Limit
}
//url returns the absolute url
// url returns the absolute url
func (p Pagination) url() string {
if p.RelURL[0] == '/' {
return p.RelURL
@ -32,12 +32,12 @@ func (p Pagination) url() string {
return "/" + p.RelURL
}
//pages returns the amount of pages
// pages returns the amount of pages
func (p Pagination) pages() int {
return int(math.Ceil(float64(p.Total) / float64(p.Limit)))
}
//hasNext returns true if a next page is available
// hasNext returns true if a next page is available
func (p Pagination) hasNext() bool {
if p.CurrentPage*p.Limit >= p.Total {
return false
@ -45,17 +45,17 @@ func (p Pagination) hasNext() bool {
return true
}
//hasMoreThanOnePage returns true if the bar has more than one page
// hasMoreThanOnePage returns true if the bar has more than one page
func (p Pagination) hasMoreThanOnePage() bool {
return p.Limit < p.Total
}
//hasPrevious returns true if a previous page is available
// hasPrevious returns true if a previous page is available
func (p Pagination) hasPrevious() bool {
return !(p.CurrentPage == 1)
}
//nextPage returns the next page
// nextPage returns the next page
func (p Pagination) nextPage() int {
if !p.hasNext() {
return p.CurrentPage
@ -63,7 +63,7 @@ func (p Pagination) nextPage() int {
return p.CurrentPage + 1
}
//previousPage returns the previous page
// previousPage returns the previous page
func (p Pagination) previousPage() int {
if !p.hasPrevious() {
return p.CurrentPage
@ -71,7 +71,7 @@ func (p Pagination) previousPage() int {
return p.CurrentPage - 1
}
//PaginationBar returns the HTML for the pagination bar which can be embedded
// PaginationBar returns the HTML for the pagination bar which can be embedded
func (p Pagination) PaginationBar() template.HTML {
var sb strings.Builder

View File

@ -11,7 +11,7 @@ import (
"git.hoogi.eu/snafu/go-blog/slug"
)
//SiteDatasourceService defines an interface for CRUD operations on sites
// SiteDatasourceService defines an interface for CRUD operations on sites
type SiteDatasourceService interface {
Create(s *Site) (int, error)
List(pc PublishedCriteria, p *Pagination) ([]Site, error)
@ -25,17 +25,17 @@ type SiteDatasourceService interface {
Count(pc PublishedCriteria) (int, error)
}
//Direction type to distinct if a site should be moved up or down
// Direction type to distinct if a site should be moved up or down
type Direction int
const (
//Up for moving the site one up
// Up for moving the site one up
Up = iota
//Down for moving the site one down
// Down for moving the site one down
Down
)
//Site represents a site
// Site represents a site
type Site struct {
ID int
Title string
@ -114,17 +114,17 @@ func (s *Site) validate(ds SiteDatasourceService, changeLink bool) error {
return nil
}
//SiteService containing the service to access site
// SiteService containing the service to access site
type SiteService struct {
Datasource SiteDatasourceService
}
//List returns all sites
// List returns all sites
func (ss SiteService) List(pc PublishedCriteria, p *Pagination) ([]Site, error) {
return ss.Datasource.List(pc, p)
}
//Publish switches the publish state of the site
// Publish switches the publish state of the site
func (ss SiteService) Publish(siteID int) error {
s, err := ss.Datasource.Get(siteID, All)
@ -141,7 +141,7 @@ func (ss SiteService) Publish(siteID int) error {
return nil
}
//Create creates a site
// Create creates a site
func (ss SiteService) Create(s *Site) (int, error) {
if err := s.validate(ss.Datasource, true); err != nil {
return -1, err
@ -160,12 +160,12 @@ func (ss SiteService) Create(s *Site) (int, error) {
return ss.Datasource.Create(s)
}
//Order reorder the site
// Order reorder the site
func (ss SiteService) Order(siteID int, dir Direction) error {
return ss.Datasource.Order(siteID, dir)
}
//Update updates a site
// Update updates a site
func (ss SiteService) Update(s *Site) error {
oldSite, err := ss.GetByID(s.ID, All)
@ -187,7 +187,7 @@ func (ss SiteService) Update(s *Site) error {
return ss.Datasource.Update(s)
}
//Delete deletes a site
// Delete deletes a site
func (ss SiteService) Delete(siteID int) error {
s, err := ss.GetByID(siteID, All)

View File

@ -1,21 +1,21 @@
package models
import (
"bytes"
"database/sql"
"strings"
"time"
"git.hoogi.eu/snafu/go-blog/logger"
)
//SQLiteSiteDatasource providing an implementation of SiteDatasourceService for sqlite
// SQLiteSiteDatasource providing an implementation of SiteDatasourceService for sqlite
type SQLiteSiteDatasource struct {
SQLConn *sql.DB
}
//List returns a array of sites
// List returns a array of sites
func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Site, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.last_modified, s.order_no, u.id, u.display_name, u.email, u.username ")
@ -44,7 +44,11 @@ func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Sit
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
var sites []Site
var s Site
@ -67,9 +71,9 @@ func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Sit
return sites, nil
}
//Get returns a site based on the site id
// Get returns a site based on the site id
func (rdb SQLiteSiteDatasource) Get(siteID int, pc PublishedCriteria) (*Site, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.last_modified, s.order_no, u.id, u.display_name, u.email, u.username FROM site as s ")
@ -96,9 +100,9 @@ func (rdb SQLiteSiteDatasource) Get(siteID int, pc PublishedCriteria) (*Site, er
return &s, nil
}
//GetByLink returns a site based on the provided link
// GetByLink returns a site based on the provided link
func (rdb SQLiteSiteDatasource) GetByLink(link string, pc PublishedCriteria) (*Site, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.order_no, s.last_modified, u.id, u.display_name, u.email, u.username FROM site as s ")
@ -125,7 +129,7 @@ func (rdb SQLiteSiteDatasource) GetByLink(link string, pc PublishedCriteria) (*S
return &s, nil
}
//Publish publishes or unpublishes a site
// Publish publishes or unpublishes a site
func (rdb SQLiteSiteDatasource) Publish(s *Site) error {
publishOn := NullTime{Valid: false}
@ -139,7 +143,7 @@ func (rdb SQLiteSiteDatasource) Publish(s *Site) error {
return nil
}
//Create creates a site
// Create creates a site
func (rdb SQLiteSiteDatasource) Create(s *Site) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO site (title, link, section, content, published, published_on, last_modified, order_no, user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)",
s.Title, s.Link, s.Section, s.Content, s.Published, s.PublishedOn, time.Now(), s.OrderNo, s.Author.ID)
@ -157,7 +161,7 @@ func (rdb SQLiteSiteDatasource) Create(s *Site) (int, error) {
return int(i), nil
}
//Order moves a site up or down
// Order moves a site up or down
func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
tx, err := rdb.SQLConn.Begin()
@ -168,7 +172,12 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
defer func() {
if err != nil {
logger.Log.Error("error during ordering of sites ", err)
tx.Rollback()
err := tx.Rollback()
if err != nil {
logger.Log.Error("error during transaction rollback ", err)
}
}
}()
@ -185,7 +194,9 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
} else if d == Down {
var max int
tx.QueryRow("SELECT MAX(order_no) AS max FROM site").Scan(&max)
if err := tx.QueryRow("SELECT MAX(order_no) AS max FROM site").Scan(&max); err != nil {
return err
}
if _, err = tx.Exec("UPDATE site "+
"SET order_no=(SELECT order_no AS swap_el FROM site WHERE id=?) "+
@ -210,7 +221,7 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
return nil
}
//Update updates a site
// Update updates a site
func (rdb SQLiteSiteDatasource) Update(s *Site) error {
if _, err := rdb.SQLConn.Exec("UPDATE site SET title=?, link=?, section=?, content=?, last_modified=? WHERE id=?", s.Title, s.Link, s.Section, s.Content, time.Now(), s.ID); err != nil {
return err
@ -219,9 +230,9 @@ func (rdb SQLiteSiteDatasource) Update(s *Site) error {
return nil
}
//Count returns the amount of sites
// Count returns the amount of sites
func (rdb SQLiteSiteDatasource) Count(pc PublishedCriteria) (int, error) {
var stmt bytes.Buffer
var stmt strings.Builder
stmt.WriteString("SELECT count(id) FROM site ")
@ -240,7 +251,7 @@ func (rdb SQLiteSiteDatasource) Count(pc PublishedCriteria) (int, error) {
return total, nil
}
//Max returns the maximum order number
// Max returns the maximum order number
func (rdb SQLiteSiteDatasource) Max() (int, error) {
var max sql.NullInt64
@ -255,7 +266,7 @@ func (rdb SQLiteSiteDatasource) Max() (int, error) {
return int(max.Int64), nil
}
//Delete deletes a site and updates the order numbers
// Delete deletes a site and updates the order numbers
func (rdb SQLiteSiteDatasource) Delete(s *Site) error {
tx, err := rdb.SQLConn.Begin()
@ -265,8 +276,11 @@ func (rdb SQLiteSiteDatasource) Delete(s *Site) error {
defer func() {
if err != nil {
logger.Log.Error("error during delete transaction", err)
tx.Rollback()
logger.Log.Errorf("error site removal not successful %v", err)
if err := tx.Rollback(); err != nil {
logger.Log.Errorf("could not rollback transaction during site removal %v", err)
return
}
return
}
}()

View File

@ -5,15 +5,15 @@ import (
"time"
)
//AdminCriteria specifies which type of users should be considered
// AdminCriteria specifies which type of users should be considered
type AdminCriteria int
const (
//OnlyAdmins conider only published
// OnlyAdmins consider only admins
OnlyAdmins = iota
//NoAdmins conider no admins
// NoAdmins consider no admins
NoAdmins
//AllUser conider all users
// AllUser consider all users
AllUser
)
@ -21,15 +21,15 @@ const (
type PublishedCriteria int
const (
// OnlyPublished conider only published
// OnlyPublished consider only published
OnlyPublished = iota
// NotPublished conider only not published
// NotPublished consider only not published
NotPublished
// All conider both published and not published
// All consider both published and not published
All
)
//NullTime represents a time which may not valid if time is null
// NullTime represents a time which may not valid if time is null
type NullTime struct {
Time time.Time
Valid bool

View File

@ -12,7 +12,7 @@ import (
"git.hoogi.eu/snafu/go-blog/logger"
)
//TokenDatasourceService defines an interface for CRUD operations for tokens
// TokenDatasourceService defines an interface for CRUD operations for tokens
type TokenDatasourceService interface {
Create(t *Token) (int, error)
Get(hash string, tt TokenType) (*Token, error)
@ -20,7 +20,7 @@ type TokenDatasourceService interface {
Remove(hash string, tt TokenType) error
}
//Token represents a token
// Token represents a token
type Token struct {
ID int
Hash string
@ -31,13 +31,13 @@ type Token struct {
}
const (
//PasswordReset token generated for resetting passwords
// PasswordReset token generated for resetting passwords
PasswordReset = iota
)
var types = [...]string{"password_reset"}
//TokenType specifies the type where token can be used
// TokenType specifies the type where token can be used
type TokenType int
// Scan implements the Scanner interface.
@ -61,12 +61,12 @@ func (tt TokenType) String() string {
return types[tt]
}
//TokenService containing the service to access tokens
// TokenService containing the service to access tokens
type TokenService struct {
Datasource TokenDatasourceService
}
//Create creates a new token
// Create creates a new token
func (ts TokenService) Create(t *Token) error {
t.Hash = crypt.RandomHash(32)
@ -77,8 +77,8 @@ func (ts TokenService) Create(t *Token) error {
return nil
}
//Get token for a defined token type expires after a defined time
//Expired token will be removed
// Get token for a defined token type expires after a defined time
// Expired token will be removed
func (ts TokenService) Get(hash string, tt TokenType, expireAfter time.Duration) (*Token, error) {
token, err := ts.Datasource.Get(hash, tt)
@ -98,7 +98,7 @@ func (ts TokenService) Get(hash string, tt TokenType, expireAfter time.Duration)
return token, nil
}
//RateLimit returns an error if a token is requested greater three times in a time span of 15 minutes
// RateLimit returns an error if a token is requested greater three times in a time span of 15 minutes
func (ts TokenService) RateLimit(userID int, tt TokenType) error {
tokens, err := ts.Datasource.ListByUser(userID, tt)
@ -122,7 +122,7 @@ func (ts TokenService) RateLimit(userID int, tt TokenType) error {
return nil
}
//Remove removes a token
// Remove removes a token
func (ts TokenService) Remove(hash string, tt TokenType) error {
return ts.Datasource.Remove(hash, tt)
}

View File

@ -2,15 +2,16 @@ package models
import (
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"time"
)
//SQLiteTokenDatasource providing an implementation of TokenDatasourceService using MariaDB
// SQLiteTokenDatasource providing an implementation of TokenDatasourceService using MariaDB
type SQLiteTokenDatasource struct {
SQLConn *sql.DB
}
//Create creates a new token
// Create creates a new token
func (rdb SQLiteTokenDatasource) Create(t *Token) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO token (hash, requested_at, token_type, user_id) VALUES(?, ?, ?, ?)",
t.Hash, time.Now(), t.Type, t.Author.ID)
@ -28,7 +29,7 @@ func (rdb SQLiteTokenDatasource) Create(t *Token) (int, error) {
return int(i), nil
}
//Get gets a token based on the hash and the token type
// Get gets a token based on the hash and the token type
func (rdb SQLiteTokenDatasource) Get(hash string, tt TokenType) (*Token, error) {
var t Token
var u User
@ -43,7 +44,7 @@ func (rdb SQLiteTokenDatasource) Get(hash string, tt TokenType) (*Token, error)
return &t, nil
}
//ListByUser receives all tokens based on the user id and the token type ordered by requested
// ListByUser receives all tokens based on the user id and the token type ordered by requested
func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token, error) {
rows, err := rdb.SQLConn.Query("SELECT t.id, t.hash, t.requested_at, t.token_type, t.user_id FROM token as t WHERE t.user_id=? AND t.token_type=? ", userID, tt.String())
@ -51,7 +52,11 @@ func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token,
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
tokens := []Token{}
@ -70,7 +75,7 @@ func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token,
return tokens, nil
}
//Remove removes a token based on the hash
// Remove removes a token based on the hash
func (rdb SQLiteTokenDatasource) Remove(hash string, tt TokenType) error {
if _, err := rdb.SQLConn.Exec("DELETE FROM token WHERE hash=? AND token_type=? ", hash, tt.String()); err != nil {
return err

View File

@ -19,7 +19,7 @@ import (
"golang.org/x/crypto/bcrypt"
)
//UserDatasourceService defines an interface for CRUD operations for users
// UserDatasourceService defines an interface for CRUD operations for users
type UserDatasourceService interface {
Create(u *User) (int, error)
List(p *Pagination) ([]User, error)
@ -31,7 +31,7 @@ type UserDatasourceService interface {
Remove(userID int) error
}
//User represents a user
// User represents a user
type User struct {
ID int
Username string
@ -45,18 +45,14 @@ type User struct {
IsAdmin bool
}
const (
bcryptRounds = 12
)
//UserService containing the service to access users
// UserService containing the service to access users
type UserService struct {
Datasource UserDatasourceService
Config settings.User
UserInterceptor UserInterceptor
}
//UserInterceptor will be executed before and after updating/creating users
// UserInterceptor will be executed before and after updating/creating users
type UserInterceptor interface {
PreCreate(user *User) error
PostCreate(user *User) error
@ -163,17 +159,17 @@ func (us UserService) duplicateUsername(username string) error {
return nil
}
//Count returns the amount of users
// Count returns the amount of users
func (us UserService) Count(a AdminCriteria) (int, error) {
return us.Datasource.Count(a)
}
//List returns a list of users. Limits the amount based on the defined pagination
// List returns a list of users. Limits the amount based on the defined pagination
func (us UserService) List(p *Pagination) ([]User, error) {
return us.Datasource.List(p)
}
//GetByID gets the user based on the given id; will not contain the user password
// GetByID gets the user based on the given id; will not contain the user password
func (us UserService) GetByID(userID int) (*User, error) {
u, err := us.Datasource.Get(userID)
@ -187,7 +183,7 @@ func (us UserService) GetByID(userID int) (*User, error) {
return u, nil
}
//GetByUsername gets the user based on the given username; will contain the user password
// GetByUsername gets the user based on the given username; will contain the user password
func (us UserService) GetByUsername(username string) (*User, error) {
u, err := us.Datasource.GetByUsername(username)
if err != nil {
@ -200,7 +196,7 @@ func (us UserService) GetByUsername(username string) (*User, error) {
return u, nil
}
//GetByMail gets the user based on the given mail; will contain the user password
// GetByMail gets the user based on the given mail; will contain the user password
func (us UserService) GetByMail(mail string) (*User, error) {
u, err := us.Datasource.GetByMail(mail)
@ -214,8 +210,8 @@ func (us UserService) GetByMail(mail string) (*User, error) {
return u, nil
}
//Create creates the user
//If an UserInterceptor is available the action PreCreate is executed before creating and PostCreate after creating the user
// Create creates the user
// If an UserInterceptor is available the action PreCreate is executed before creating and PostCreate after creating the user
func (us UserService) Create(u *User) (int, error) {
if us.UserInterceptor != nil {
if err := us.UserInterceptor.PreCreate(u); err != nil {
@ -229,7 +225,7 @@ func (us UserService) Create(u *User) (int, error) {
salt := crypt.GenerateSalt()
saltedPassword := append(u.PlainPassword[:], salt[:]...)
password, err := crypt.CryptPassword([]byte(saltedPassword), bcryptRounds)
password, err := crypt.CryptPassword([]byte(saltedPassword))
if err != nil {
return -1, err
@ -312,7 +308,7 @@ func (us UserService) Update(u *User, changePassword bool) error {
if changePassword {
salt := crypt.GenerateSalt()
saltedPassword := append(u.PlainPassword[:], salt[:]...)
password, err := crypt.CryptPassword([]byte(saltedPassword), bcryptRounds)
password, err := crypt.CryptPassword([]byte(saltedPassword))
if err != nil {
return err
@ -417,7 +413,7 @@ func (us UserService) Remove(u *User) error {
return err
}
//OneAdmin returns true if there is only one admin
// OneAdmin returns true if there is only one admin
func (us UserService) OneAdmin() (bool, error) {
c, err := us.Datasource.Count(OnlyAdmins)

View File

@ -7,7 +7,7 @@ import (
"git.hoogi.eu/snafu/go-blog/mail"
)
//UserInvite represents a new invited user
// UserInvite represents a new invited user
type UserInvite struct {
ID int
Hash string
@ -29,7 +29,7 @@ func (ui UserInvite) Copy() *User {
}
}
//UserInviteDatasourceService defines an interface for CRUD operations for users
// UserInviteDatasourceService defines an interface for CRUD operations for users
type UserInviteDatasourceService interface {
List() ([]UserInvite, error)
Get(inviteID int) (*UserInvite, error)
@ -39,7 +39,7 @@ type UserInviteDatasourceService interface {
Remove(inviteID int) error
}
//UserInviteService
// UserInviteService
type UserInviteService struct {
Datasource UserInviteDatasourceService
UserService UserService

View File

@ -1,37 +1,33 @@
package models
import (
"bytes"
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"time"
)
//SQLiteUserInviteDatasource
// SQLiteUserInviteDatasource
type SQLiteUserInviteDatasource struct {
SQLConn *sql.DB
}
func (rdb SQLiteUserInviteDatasource) List() ([]UserInvite, error) {
var stmt bytes.Buffer
var args []interface{}
var invites []UserInvite
var ui UserInvite
var u User
stmt.WriteString("SELECT ui.id, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, ")
stmt.WriteString("u.id, u.username, u.email, u.display_name ")
stmt.WriteString("FROM user_invite as ui ")
stmt.WriteString("INNER JOIN user as u ")
stmt.WriteString("ON u.id = ui.created_by ")
stmt.WriteString("ORDER BY ui.username ASC ")
rows, err := rdb.SQLConn.Query(stmt.String(), args...)
rows, err := rdb.SQLConn.Query("SELECT ui.id, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin," +
" u.id, u.username, u.email, u.display_name FROM user_invite as ui INNER JOIN user as u ON u.id = ui.created_by ORDER BY ui.username ASC")
if err != nil {
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
for rows.Next() {
if err = rows.Scan(&ui.ID, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
@ -95,7 +91,7 @@ func (rdb SQLiteUserInviteDatasource) Update(ui *UserInvite) error {
return nil
}
//Create creates an new user invitation
// Create creates an new user invitation
func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO user_invite (hash, username, email, display_name, is_admin, created_at, created_by) VALUES(?, ?, ?, ?, ?, ?, ?);",
ui.Hash, ui.Username, ui.Email, ui.DisplayName, ui.IsAdmin, time.Now(), ui.CreatedBy.ID)
@ -113,7 +109,7 @@ func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
return int(i), nil
}
//Count retuns the amount of users invitations
// Count retuns the amount of users invitations
func (rdb SQLiteUserInviteDatasource) Count() (int, error) {
var total int
@ -124,7 +120,7 @@ func (rdb SQLiteUserInviteDatasource) Count() (int, error) {
return total, nil
}
//Removes an user invitation
// Remove removes an user invitation
func (rdb SQLiteUserInviteDatasource) Remove(inviteID int) error {
if _, err := rdb.SQLConn.Exec("DELETE FROM user_invite WHERE id=?", inviteID); err != nil {
return err

View File

@ -1,19 +1,20 @@
package models
import (
"bytes"
"database/sql"
"git.hoogi.eu/snafu/go-blog/logger"
"strings"
"time"
)
//SQLiteUserDatasource providing an implementation of UserDatasourceService using SQLite
// SQLiteUserDatasource providing an implementation of UserDatasourceService using SQLite
type SQLiteUserDatasource struct {
SQLConn *sql.DB
}
//List returns a list of user
// List returns a list of user
func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
var users []User
var u User
@ -31,7 +32,11 @@ func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
return nil, err
}
defer rows.Close()
defer func() {
if err := rows.Close(); err != nil {
logger.Log.Error(err)
}
}()
for rows.Next() {
if err = rows.Scan(&u.ID, &u.Username, &u.Email, &u.DisplayName, &u.LastModified, &u.Active, &u.IsAdmin); err != nil {
@ -48,7 +53,7 @@ func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
return users, nil
}
//Get gets an user by his userID
// Get gets an user by his userID
func (rdb SQLiteUserDatasource) Get(userID int) (*User, error) {
var u User
@ -62,7 +67,7 @@ func (rdb SQLiteUserDatasource) Get(userID int) (*User, error) {
return &u, nil
}
//GetByMail gets an user by his mail, includes the password and salt
// GetByMail gets an user by his mail, includes the password and salt
func (rdb SQLiteUserDatasource) GetByMail(mail string) (*User, error) {
var u User
@ -73,7 +78,7 @@ func (rdb SQLiteUserDatasource) GetByMail(mail string) (*User, error) {
return &u, nil
}
//GetByUsername gets an user by his username, includes the password and salt
// GetByUsername gets an user by his username, includes the password and salt
func (rdb SQLiteUserDatasource) GetByUsername(username string) (*User, error) {
var u User
@ -84,7 +89,7 @@ func (rdb SQLiteUserDatasource) GetByUsername(username string) (*User, error) {
return &u, nil
}
//Create creates an new user
// Create creates an new user
func (rdb SQLiteUserDatasource) Create(u *User) (int, error) {
res, err := rdb.SQLConn.Exec("INSERT INTO user (salt, password, username, email, display_name, last_modified, active, is_admin) VALUES(?, ?, ?, ?, ?, ?, ?, ?);",
u.Salt, u.Password, u.Username, u.Email, u.DisplayName, time.Now(), u.Active, u.IsAdmin)
@ -101,9 +106,9 @@ func (rdb SQLiteUserDatasource) Create(u *User) (int, error) {
return int(i), nil
}
//Update updates an user
// Update updates an user
func (rdb SQLiteUserDatasource) Update(u *User, changePassword bool) error {
var stmt bytes.Buffer
var stmt strings.Builder
var args []interface{}
stmt.WriteString("UPDATE user SET display_name=?, username=?, email=?, last_modified=?, active=?, is_admin=? ")
@ -125,9 +130,9 @@ func (rdb SQLiteUserDatasource) Update(u *User, changePassword bool) error {
return nil
}
//Count returns the amount of users matches the AdminCriteria
// Count returns the amount of users matches the AdminCriteria
func (rdb SQLiteUserDatasource) Count(ac AdminCriteria) (int, error) {
var stmt bytes.Buffer
var stmt strings.Builder
stmt.WriteString("SELECT count(id) FROM user ")
if ac == OnlyAdmins {
@ -145,7 +150,7 @@ func (rdb SQLiteUserDatasource) Count(ac AdminCriteria) (int, error) {
return total, nil
}
//Removes an user
// Remove removes an user
func (rdb SQLiteUserDatasource) Remove(userID int) error {
if _, err := rdb.SQLConn.Exec("DELETE FROM user WHERE id=?", userID); err != nil {
return err

View File

@ -18,13 +18,13 @@ import (
"github.com/justinas/alice"
)
//InitRoutes initializes restricted and public routes
// InitRoutes initializes restricted and public routes
func InitRoutes(ctx *m.AppContext, cfg *settings.Settings) *mux.Router {
router := mux.NewRouter()
router = router.StrictSlash(false)
sr := router.PathPrefix("/").Subrouter()
csrf :=
rf :=
csrf.Protect([]byte(cfg.CSRF.RandomKey),
csrf.Secure(cfg.CSRF.CookieSecure),
csrf.FieldName(cfg.CSRF.CookieName),
@ -45,7 +45,7 @@ func InitRoutes(ctx *m.AppContext, cfg *settings.Settings) *mux.Router {
ar := router.PathPrefix("/admin").Subrouter()
restrictedChain := chain.Append(csrf).Append(ctx.AuthHandler)
restrictedChain := chain.Append(rf).Append(ctx.AuthHandler)
restrictedRoutes(ctx, ar, restrictedChain)
@ -89,7 +89,7 @@ func fileLoggingHandler(accessLogPath string) (flh func(http.Handler) http.Handl
}
func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain) {
//article
// article
router.Handle("/articles", chain.Then(useTemplateHandler(ctx, handler.AdminListArticlesHandler))).Methods("GET")
router.Handle("/articles/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminListArticlesHandler))).Methods("GET")
router.Handle("/article/new", chain.Then(useTemplateHandler(ctx, handler.AdminArticleNewHandler))).Methods("GET")
@ -102,7 +102,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
router.Handle("/article/delete/{articleID}", chain.Then(useTemplateHandler(ctx, handler.AdminArticleDeletePostHandler))).Methods("POST")
router.Handle("/article/{articleID}", chain.Then(useTemplateHandler(ctx, handler.AdminPreviewArticleByIDHandler))).Methods("GET")
//user
// user
router.Handle("/user/profile", chain.Then(useTemplateHandler(ctx, handler.AdminProfileHandler))).Methods("GET")
router.Handle("/user/profile", chain.Then(useTemplateHandler(ctx, handler.AdminProfilePostHandler))).Methods("POST")
router.Handle("/users", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUsersHandler))).Methods("GET")
@ -114,14 +114,14 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
router.Handle("/user/delete/{userID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserDeleteHandler))).Methods("GET")
router.Handle("/user/delete/{userID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserDeletePostHandler))).Methods("POST")
//user invites
// user invites
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteNewHandler))).Methods("GET")
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteNewPostHandler))).Methods("POST")
router.Handle("/user-invite/resend/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteResendPostHandler))).Methods("POST")
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteDeleteHandler))).Methods("GET")
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteDeletePostHandler))).Methods("POST")
//site
// site
router.Handle("/sites", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSitesHandler))).Methods("GET")
router.Handle("/site/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminSitesHandler))).Methods("GET")
router.Handle("/site/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSiteNewHandler))).Methods("GET")
@ -135,7 +135,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
router.Handle("/site/order/{siteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSiteOrderHandler))).Methods("POST")
router.Handle("/site/{siteID:[0-9]+}}", chain.Then(useTemplateHandler(ctx, handler.AdminGetSiteHandler))).Methods("GET")
//article
// article
router.Handle("/categories", chain.Then(useTemplateHandler(ctx, handler.AdminListCategoriesHandler))).Methods("GET")
router.Handle("/category/{categoryID:[0-9]+}}", chain.Then(useTemplateHandler(ctx, handler.AdminGetCategoryHandler))).Methods("POST")
router.Handle("/category/new", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryNewHandler))).Methods("GET")
@ -145,7 +145,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
router.Handle("/category/delete/{categoryID}", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryDeleteHandler))).Methods("GET")
router.Handle("/category/delete/{categoryID}", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryDeletePostHandler))).Methods("POST")
//file
// file
router.Handle("/files", chain.Then(useTemplateHandler(ctx, handler.AdminListFilesHandler))).Methods("GET")
router.Handle("/files/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminListFilesHandler))).Methods("GET")
router.Handle("/file/upload", chain.Then(useTemplateHandler(ctx, handler.AdminUploadFileHandler))).Methods("GET")

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//Package cfg parses and validates the configuration
// Package settings parses and validates the configuration
package settings
import (
@ -55,7 +55,7 @@ func (afe *AllowedFileExts) Unmarshal(value string) error {
kv[trimmed] = trimmed
*afe = AllowedFileExts(kv)
*afe = kv
}
return nil
@ -183,7 +183,7 @@ func LoadConfig(filename string) (*Settings, error) {
}
func (cfg *Settings) CheckConfig() error {
//check log file is rw in production mode
// check log file is rw in production mode
if cfg.Environment != "dev" {
if _, err := os.OpenFile(cfg.Log.File, os.O_RDONLY|os.O_CREATE, 0640); err != nil {
return fmt.Errorf("config 'log_file': could not open log file %s error %v", cfg.Log.File, err)
@ -258,7 +258,7 @@ func (cfg *Settings) CheckConfig() error {
cfg.Application.Favicon = "assets/favicon.ico"
}
//server settings
// server settings
if cfg.Server.UseTLS {
if _, err := os.Open(cfg.Server.Cert); err != nil {
return fmt.Errorf("config: could not open certificate %s error %v", cfg.Server.Cert, err)
@ -285,7 +285,7 @@ func (cfg *Settings) GenerateCSRF() (bool, error) {
var b []byte
if _, err := os.Stat(csrfTokenFilename); os.IsNotExist(err) {
//create a random csrf token
// create a random csrf token
b = crypt.AlphaUpperLowerNumericSpecial.RandomSequence(32)
err := ioutil.WriteFile(csrfTokenFilename, b, 0640)
@ -298,7 +298,7 @@ func (cfg *Settings) GenerateCSRF() (bool, error) {
return true, nil
} else {
//read existing csrf token
// read existing csrf token
b, err = ioutil.ReadFile(csrfTokenFilename)
if err != nil {

View File

@ -1,7 +1,6 @@
package slug
import (
"bytes"
"regexp"
"strconv"
"strings"
@ -10,7 +9,7 @@ import (
var multipleDashes = regexp.MustCompile(`[-]{2,}`)
//CreateURLSafeSlug creates a URL safe slug to use in URL
// CreateURLSafeSlug creates a URL safe slug to use in URL
func CreateURLSafeSlug(input string, suffix int) string {
input = strings.Replace(input, "-", "", -1)
@ -35,16 +34,3 @@ func CreateURLSafeSlug(input string, suffix int) string {
return input
}
func substitute(input string, subs map[rune]string) string {
var b bytes.Buffer
for _, c := range input {
if _, ok := subs[c]; ok {
b.WriteString(subs[c])
} else {
b.WriteRune(c)
}
}
return b.String()
}