Merge branch 'master' into faster-rss
Cette révision appartient à :
révision
003951f902
23 fichiers modifiés avec 326 ajouts et 132 suppressions
1
.gitignore
externe
1
.gitignore
externe
|
@ -7,6 +7,7 @@ nyaa.exe
|
|||
nyaa-master.exe
|
||||
*.zip
|
||||
*.swp
|
||||
.idea
|
||||
.vscode
|
||||
templates/*.html.go
|
||||
*.bat
|
||||
|
|
|
@ -102,4 +102,4 @@ func (config *Config) Pretty(output io.Writer) error {
|
|||
data = append(data, []byte("\n")...)
|
||||
_, err = output.Write(data)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
20
db/gorm.go
20
db/gorm.go
|
@ -31,28 +31,12 @@ func GormInit(conf *config.Config) (*gorm.DB, error) {
|
|||
if config.Environment == "DEVELOPMENT" {
|
||||
db.LogMode(true)
|
||||
// db.DropTable(&model.User{}, "UserFollower")
|
||||
db.AutoMigrate(&model.Torrents{})
|
||||
// db.AutoMigrate(&model.User{}, &model.Role{}, &model.Connection{}, &model.Language{}, &model.Article{}, &model.Location{}, &model.Comment{}, &model.File{})
|
||||
db.AutoMigrate(&model.Torrents{}, &model.User{}, &model.Role{}, &model.Connection{}, &model.Language{})
|
||||
// db.AutoMigrate(&model.Article{}, &model.Location{}, &model.Comment{}, &model.File{})
|
||||
// db.Model(&model.User{}).AddIndex("idx_user_token", "token")
|
||||
|
||||
}
|
||||
log.CheckError(err)
|
||||
|
||||
// relation := gorm.Relationship{}
|
||||
// relation.Kind = "many2many"
|
||||
// relation.ForeignFieldNames = []string{"id"} //(M1 pkey)
|
||||
// relation.ForeignDBNames = []string{"user_id"} //(M1 fkey in m1m2join)
|
||||
// relation.AssociationForeignFieldNames = []string{"id"} //(M2 pkey)
|
||||
// // relation.AssociationForeignStructFieldNames = []string{"id", "ID"} //(m2 pkey name in m2 struct?)
|
||||
// relation.AssociationForeignDBNames = []string{"follower_id"} //(m2 fkey in m1m2join)
|
||||
// m1Type := reflect.TypeOf(model.User{})
|
||||
// m2Type := reflect.TypeOf(model.User{})
|
||||
// handler := gorm.JoinTableHandler{}
|
||||
// // ORDER BELOW MATTERS
|
||||
// // Install handler
|
||||
// db.SetJoinTableHandler(&model.User{}, "Likings", &handler)
|
||||
// // Configure handler to use the relation that we've defined
|
||||
// handler.Setup(&relation, "users_followers", m1Type, m2Type)
|
||||
|
||||
return db, err
|
||||
}
|
||||
|
|
2
main.go
2
main.go
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/router"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/ewhal/nyaa/util/search" // super hacky fix
|
||||
"github.com/ewhal/nyaa/util/signals"
|
||||
|
||||
"net/http"
|
||||
|
@ -59,6 +60,7 @@ func main() {
|
|||
if len(config.TorrentFileStorage) > 0 {
|
||||
os.MkdirAll(config.TorrentFileStorage, 0755)
|
||||
}
|
||||
search.Init(conf.DBType) // super hacky fix
|
||||
RunServer(conf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
/* Night mode image */
|
||||
#sunmoon {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
height: 30px;
|
||||
|
||||
/* Night mode switcher */
|
||||
.nightswitch {
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 48px;
|
||||
}
|
||||
.nightswitch > a > img {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
/* Torrent status colors */
|
||||
.remake {
|
||||
background-color: #795c46;
|
||||
|
@ -55,12 +58,8 @@ body {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
background-color: #264040;
|
||||
}
|
||||
|
||||
.pagination > .active > a {
|
||||
background-color: #ececec;
|
||||
background: #ececec;
|
||||
border-color: #ececec;
|
||||
color: #337ab7; /* restore usual text color */
|
||||
}
|
||||
|
@ -115,6 +114,12 @@ a {
|
|||
padding: 4px;
|
||||
}
|
||||
|
||||
.captcha-container {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-template-columns: 240px;
|
||||
}
|
||||
|
||||
tr.torrent-info td.date {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -154,11 +159,25 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
|
|||
.table > tbody > tr > td {
|
||||
border: none;
|
||||
}
|
||||
#container.cont-home {
|
||||
background: #29363d url(/img/megumin.png) no-repeat;
|
||||
}
|
||||
#container.cont-view {
|
||||
background: #29363d url(/img/megumin.png) no-repeat;
|
||||
background-size: 75px, 100px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Credit to bootsnipp.com for the css for the color graph */
|
||||
.colorgraph {
|
||||
height: 5px;
|
||||
border-top: 0;
|
||||
background: #c4e17f;
|
||||
border-radius: 5px;
|
||||
background-image: -webkit-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
|
||||
background-image: -moz-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
|
||||
background-image: -o-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
|
||||
background-image: linear-gradient(to right, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
|
||||
}
|
||||
|
||||
.center-image {
|
||||
max-width: 100%;
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-radius: 0px;
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
/* Night mode image */
|
||||
#sunmoon {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
height: 30px;
|
||||
/* Night mode switcher */
|
||||
.nightswitch {
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 48px;
|
||||
}
|
||||
.nightswitch > a > img {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
/* Torrent status colors */
|
||||
.remake {
|
||||
background-color: rgb(240, 176, 128);
|
||||
|
@ -173,3 +177,8 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
|
|||
max-width: 100%;
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
/* the curved edges triggered my autism */
|
||||
.navbar {
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
// Night mode
|
||||
// also sorry that this code is soo bad, literally nothing else worked.. ima remake it in a near future
|
||||
var night = localStorage.getItem("night");
|
||||
if (night=="true") {
|
||||
document.getElementById("style").href = "/css/style-night.css";
|
||||
document.getElementById("nightbutton").innerHTML = "<img id='sunmoon' src='/img/sun.png' alt='Day!'>";
|
||||
if (night == "true") {
|
||||
$("#style")[0].href = "/css/style-night.css";
|
||||
$("#nighticon")[0].src = "/img/sun.png";
|
||||
}
|
||||
|
||||
function toggleNightMode() {
|
||||
var styleshieeet = document.getElementById("style").href;
|
||||
var styleshieet = new RegExp("style.css");
|
||||
var stylesheet = styleshieet.test(styleshieeet);
|
||||
if (stylesheet==true) {
|
||||
document.getElementById("style").href = "/css/style-night.css";
|
||||
document.getElementById("nightbutton").innerHTML = "<img id='sunmoon' src='/img/sun.png' alt='Day!'>";
|
||||
localStorage.setItem("night", "true");
|
||||
}
|
||||
else {
|
||||
document.getElementById("style").href = "/css/style.css";
|
||||
document.getElementById("nightbutton").innerHTML = "<img id='sunmoon' src='/img/moon.png' alt='Night!'>";
|
||||
localStorage.setItem("night", "false");
|
||||
var night = localStorage.getItem("night");
|
||||
if(night == "true") {
|
||||
$("#style")[0].href = "/css/style.css";
|
||||
$("#nighticon")[0].src = "/img/moon.png";
|
||||
} else {
|
||||
$("#style")[0].href = "/css/style-night.css";
|
||||
$("#nighticon")[0].src = "/img/sun.png";
|
||||
}
|
||||
localStorage.setItem("night", (night == "true") ? "false" : "true");
|
||||
}
|
||||
|
||||
// Used by spoiler tags
|
||||
|
@ -30,6 +25,7 @@ function toggleLayer(elem) {
|
|||
elem.classList.add("hide");
|
||||
}
|
||||
|
||||
// Date formatting
|
||||
function formatDate(date) { // thanks stackoverflow
|
||||
var monthNames = [
|
||||
"January", "February", "March",
|
||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
|||
Router.HandleFunc("/upload", UploadHandler).Name("upload")
|
||||
Router.HandleFunc("/user/register", UserRegisterFormHandler).Name("user_register").Methods("GET")
|
||||
Router.HandleFunc("/user/login", UserLoginFormHandler).Name("user_login").Methods("GET")
|
||||
Router.HandleFunc("/verify/email/{token}", UserVerifyEmailHandler).Name("user_verify").Methods("GET")
|
||||
Router.HandleFunc("/user/register", UserRegisterPostHandler).Name("user_register").Methods("POST")
|
||||
Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
var TemplateDir = "templates"
|
||||
|
||||
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate *template.Template
|
||||
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate *template.Template
|
||||
|
||||
type templateLoader struct {
|
||||
templ **template.Template
|
||||
|
@ -53,6 +53,11 @@ func ReloadTemplates() {
|
|||
name: "user_register_success",
|
||||
file: "user/signup_success.html",
|
||||
},
|
||||
templateLoader{
|
||||
templ: &viewVerifySuccessTemplate,
|
||||
name: "user_verify_success",
|
||||
file: "user/verify_success.html",
|
||||
},
|
||||
templateLoader{
|
||||
templ: &viewLoginTemplate,
|
||||
name: "user_login",
|
||||
|
|
|
@ -38,6 +38,15 @@ type ViewTemplateVariables struct {
|
|||
|
||||
type UserRegisterTemplateVariables struct {
|
||||
RegistrationForm userForms.RegistrationForm
|
||||
FormErrors map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
URL *url.URL // For parsing Url in templates
|
||||
Route *mux.Route // For getting current route in templates
|
||||
}
|
||||
|
||||
type UserVerifyTemplateVariables struct {
|
||||
FormErrors map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
URL *url.URL // For parsing Url in templates
|
||||
|
|
|
@ -16,14 +16,19 @@ import (
|
|||
|
||||
// Getting View User Registration
|
||||
func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) {
|
||||
b := form.RegistrationForm{}
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
b.CaptchaID = captcha.GetID()
|
||||
languages.SetTranslation("en-us", viewRegisterTemplate)
|
||||
htv := UserRegisterTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
err := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
_, errorUser := userService.CurrentUser(r)
|
||||
if (errorUser != nil) {
|
||||
b := form.RegistrationForm{}
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
b.CaptchaID = captcha.GetID()
|
||||
languages.SetTranslation("en-us", viewRegisterTemplate)
|
||||
htv := UserRegisterTemplateVariables{b, form.NewErrors(), NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
err := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else {
|
||||
HomeHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,31 +57,58 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// Post Registration controller, we do some check on the form here, the rest on user service
|
||||
func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Check same Password
|
||||
b := form.RegistrationForm{}
|
||||
err := form.NewErrors()
|
||||
if !captcha.Authenticate(captcha.Extract(r)) {
|
||||
// TODO: Prettier passing of mistyoed captcha errors
|
||||
http.Error(w, captcha.ErrInvalidCaptcha.Error(), 403)
|
||||
return
|
||||
err["errors"] = append(err["errors"], "Wrong captcha!")
|
||||
}
|
||||
if (r.PostFormValue("password") == r.PostFormValue("password_confirm")) && (r.PostFormValue("password") != "") {
|
||||
if (form.EmailValidation(r.PostFormValue("email"))) &&
|
||||
(form.ValidateUsername(r.PostFormValue("username"))) &&
|
||||
(form.IsAgreed(r.PostFormValue("t_and_c"))) {
|
||||
_, err := userService.CreateUser(w, r)
|
||||
if err == nil {
|
||||
b := form.RegistrationForm{}
|
||||
htv := UserRegisterTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
err = viewRegisterSuccessTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
if (len(err) == 0) {
|
||||
_, err = form.EmailValidation(r.PostFormValue("email"), err)
|
||||
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
|
||||
if (len(err) == 0) {
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
err = modelHelper.ValidateForm(&b, err)
|
||||
if (len(err) == 0) {
|
||||
_, errorUser := userService.CreateUser(w, r)
|
||||
if (errorUser != nil) {
|
||||
err["errors"] = append(err["errors"], errorUser.Error())
|
||||
}
|
||||
} else {
|
||||
UserRegisterFormHandler(w, r)
|
||||
}
|
||||
} else {
|
||||
UserRegisterFormHandler(w, r)
|
||||
if (len(err) == 0) {
|
||||
b := form.RegistrationForm{}
|
||||
languages.SetTranslation("en-us", viewRegisterSuccessTemplate)
|
||||
htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
errorTmpl := viewRegisterSuccessTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if errorTmpl != nil {
|
||||
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len(err) > 0) {
|
||||
b.CaptchaID = captcha.GetID()
|
||||
languages.SetTranslation("en-us", viewRegisterTemplate)
|
||||
htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
errorTmpl := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if errorTmpl != nil {
|
||||
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else {
|
||||
UserRegisterFormHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
token := vars["token"]
|
||||
err := form.NewErrors()
|
||||
_, errEmail := userService.EmailVerification(token, w)
|
||||
if (errEmail != nil) {
|
||||
err["errors"] = append(err["errors"], errEmail.Error())
|
||||
}
|
||||
languages.SetTranslation("en-us", viewVerifySuccessTemplate)
|
||||
htv := UserVerifyTemplateVariables{err, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
|
||||
errorTmpl := viewVerifySuccessTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if errorTmpl != nil {
|
||||
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs
|
|||
var torrents []model.Torrents
|
||||
var dbQuery *gorm.DB
|
||||
var count int
|
||||
|
||||
conditions := "torrent_hash IS NOT NULL AND filesize > 0" //filter out broken entries
|
||||
var params []interface{}
|
||||
if parameters != nil { // if there is where parameters
|
||||
|
@ -76,9 +77,9 @@ func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs
|
|||
}
|
||||
dbQuery = db.ORM.Model(&torrents).Where(conditions, params...)
|
||||
|
||||
if orderBy == "" {
|
||||
if orderBy == "" { // default OrderBy
|
||||
orderBy = "torrent_id DESC"
|
||||
} // Default OrderBy
|
||||
}
|
||||
if limit != 0 || offset != 0 { // if limits provided
|
||||
dbQuery = dbQuery.Limit(limit).Offset(offset)
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er
|
|||
if email != "" && pass != "" {
|
||||
log.Debugf("User email : %s , password : %s", email, pass)
|
||||
var user model.User
|
||||
isValidEmail := formStruct.EmailValidation(email)
|
||||
isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors())
|
||||
if isValidEmail {
|
||||
log.Debug("User entered valid email.")
|
||||
if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
|
||||
|
|
|
@ -9,34 +9,32 @@ import (
|
|||
const EMAIL_REGEX = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`
|
||||
const USERNAME_REGEX = `(\W)`
|
||||
|
||||
func EmailValidation(email string) bool {
|
||||
exp, err := regexp.Compile(EMAIL_REGEX)
|
||||
if regexpCompiled := log.CheckError(err); regexpCompiled {
|
||||
func EmailValidation(email string, err map[string][]string) (bool, map[string][]string) {
|
||||
exp, errorRegex := regexp.Compile(EMAIL_REGEX)
|
||||
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
|
||||
if exp.MatchString(email) {
|
||||
return true
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
err["email"] = append(err["email"], "Email Address is not valid")
|
||||
return false, err
|
||||
}
|
||||
func ValidateUsername(username string) bool {
|
||||
exp, err := regexp.Compile(USERNAME_REGEX)
|
||||
|
||||
if username == "" {
|
||||
return false
|
||||
|
||||
}
|
||||
if (len(username) < 3) || (len(username) > 15) {
|
||||
return false
|
||||
|
||||
}
|
||||
if regexpCompiled := log.CheckError(err); regexpCompiled {
|
||||
func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) {
|
||||
exp, errorRegex := regexp.Compile(USERNAME_REGEX)
|
||||
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
|
||||
if exp.MatchString(username) {
|
||||
return false
|
||||
err["username"] = append(err["username"], "Username contains illegal characters")
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
return true
|
||||
return true, err
|
||||
}
|
||||
|
||||
func NewErrors() map[string][]string {
|
||||
err := make(map[string][]string)
|
||||
return err
|
||||
}
|
||||
func IsAgreed(t_and_c string) bool {
|
||||
if t_and_c == "1" {
|
||||
|
@ -47,10 +45,12 @@ func IsAgreed(t_and_c string) bool {
|
|||
|
||||
// RegistrationForm is used when creating a user.
|
||||
type RegistrationForm struct {
|
||||
Username string `form:"registrationUsername"`
|
||||
Email string `form:"registrationEmail"`
|
||||
Password string `form:"registrationPassword"`
|
||||
CaptchaID string `form:"captchaID" inmodel:"false"`
|
||||
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
|
||||
Email string `form:"email" needed:"true"`
|
||||
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
|
||||
Confirm_Password string `form:"password_confirmation" omit:"true" needed:"true"`
|
||||
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
|
||||
T_and_C bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
|
||||
}
|
||||
|
||||
// RegistrationForm is used when creating a user authentication.
|
||||
|
|
|
@ -91,6 +91,10 @@
|
|||
"id":"sign_up_success",
|
||||
"translation": "Almost Signed Up!"
|
||||
},
|
||||
{
|
||||
"id":"verify_success",
|
||||
"translation": "<i style=\"color:limegreen\" class=\"glyphicon glyphicon-ok-circle\"></i>Your account is now activated!"
|
||||
},
|
||||
{
|
||||
"id":"signup_verification_email",
|
||||
"translation": "Now, you are one step left before being part of our community! Check your emails (inbox or spam folder) and click the link provided for activating your account!"
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/ewhal/nyaa/util/modelHelper"
|
||||
"github.com/ewhal/nyaa/util/timeHelper"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var userFields []string = []string{"name", "email", "createdAt", "updatedAt"}
|
||||
|
@ -42,7 +43,14 @@ func SuggestUsername(username string) string {
|
|||
}
|
||||
return usernameCandidate
|
||||
}
|
||||
|
||||
func CheckEmail(email string) bool {
|
||||
var count int
|
||||
db.ORM.Model(model.User{}).Where(&model.User{Email: email}).Count(&count)
|
||||
if count == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// CreateUserFromForm creates a user from a registration form.
|
||||
func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.User, error) {
|
||||
var user model.User
|
||||
|
@ -70,7 +78,13 @@ func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
var err error
|
||||
|
||||
modelHelper.BindValueForm(®istrationForm, r)
|
||||
|
||||
usernameCandidate := SuggestUsername(registrationForm.Username)
|
||||
if (usernameCandidate != registrationForm.Username) {
|
||||
return http.StatusInternalServerError, fmt.Errorf("Username already taken, you can choose: %s", usernameCandidate)
|
||||
}
|
||||
if CheckEmail(registrationForm.Email) {
|
||||
return http.StatusInternalServerError, errors.New("Email Address already in our database!")
|
||||
}
|
||||
password, err := bcrypt.GenerateFromPassword([]byte(registrationForm.Password), 10)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
|
|
|
@ -8,12 +8,10 @@ import (
|
|||
"github.com/ewhal/nyaa/config"
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/util/modelHelper"
|
||||
"github.com/ewhal/nyaa/util/crypto"
|
||||
"github.com/ewhal/nyaa/util/email"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/ewhal/nyaa/util/timeHelper"
|
||||
formStruct "github.com/ewhal/nyaa/service/user/form"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
)
|
||||
|
@ -66,12 +64,10 @@ func SendVerification(r *http.Request) (int, error) {
|
|||
}
|
||||
|
||||
// EmailVerification verifies an email of user.
|
||||
func EmailVerification(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
func EmailVerification(token string,w http.ResponseWriter) (int, error) {
|
||||
var user model.User
|
||||
var verifyEmailForm formStruct.VerifyEmailForm
|
||||
modelHelper.BindValueForm(&verifyEmailForm, r)
|
||||
log.Debugf("verifyEmailForm.ActivationToken : %s", verifyEmailForm.ActivationToken)
|
||||
if db.ORM.Where(&model.User{ActivationToken: verifyEmailForm.ActivationToken}).First(&user).RecordNotFound() {
|
||||
log.Debugf("verifyEmailForm.ActivationToken : %s", token)
|
||||
if db.ORM.Where(&model.User{ActivationToken: token}).First(&user).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
}
|
||||
isExpired := timeHelper.IsExpired(user.ActivateUntil)
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
<li><a href="irc://irc.rizon.net/nyaapantsu">IRC</a></li>
|
||||
<li><a href="{{ genRouteWithQuery "feed" .URL }}">RSS</a></li>
|
||||
<li><a href="https://sukebei.pantsu.cat">Fap</a></li>
|
||||
<li><a href="javascript:void(0);" id="nightbutton" onclick='toggleNightMode();'><img id="sunmoon" src="/img/moon.png" alt="Night!"></a></li>
|
||||
|
||||
</ul>
|
||||
<form class="navbar-form navbar-right" role="search" action="/search" method="get">
|
||||
|
@ -56,6 +55,9 @@
|
|||
{{block "search_button" .}}{{end}}
|
||||
</div>
|
||||
</form>
|
||||
<div class="nightswitch" style="position:absolute;right:1em">
|
||||
<a href="javascript:toggleNightMode();" ><img id="nighticon" src="/img/moon.png"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -8,21 +8,36 @@
|
|||
<form role="form" method="POST">
|
||||
<h2>{{T "signup_box_title" }}</h2>
|
||||
<hr class="colorgraph">
|
||||
{{ range (index $.FormErrors "errors")}}
|
||||
<div class="alert alert-danger">{{ . }}</div>
|
||||
{{end}}
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" id="display_name" class="form-control input-lg" placeholder="{{T "username" }}" tabindex="1" value="{{ .Username }}">
|
||||
{{ range (index $.FormErrors "username")}}
|
||||
<p class="bg-danger">{{ . }}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" name="email" id="email" class="form-control input-lg" placeholder="{{T "email_address" }}" tabindex="2" value="{{ .Email }}">
|
||||
{{ range (index $.FormErrors "email")}}
|
||||
<p class="bg-danger">{{ . }}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" id="password" class="form-control input-lg" placeholder="{{T "password" }}" tabindex="3" value="{{ .Password }}">
|
||||
</div>
|
||||
{{ range (index $.FormErrors "password")}}
|
||||
<p class="bg-danger">{{ . }}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<input type="password" name="password_confirmation" id="password_confirmation" class="form-control input-lg" placeholder="{{T "confirm_password" }}" tabindex="4">
|
||||
{{ range (index $.FormErrors "password_confirmation")}}
|
||||
<p class="bg-danger">{{ . }}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,6 +46,9 @@
|
|||
<span class="button-checkbox">
|
||||
<button type="button" class="btn hidden" data-color="info" tabindex="5">{{T "i_agree" }}</button>
|
||||
<input type="checkbox" name="t_and_c" id="t_and_c" value="1">
|
||||
{{ range (index $.FormErrors "t_and_c")}}
|
||||
<p class="bg-danger">{{ . }}</p>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-9 col-md-9">
|
||||
|
|
17
templates/user/verify_success.html
Fichier normal
17
templates/user/verify_success.html
Fichier normal
|
@ -0,0 +1,17 @@
|
|||
{{define "title"}}{{ T "register_success_title" }}{{end}}
|
||||
{{define "contclass"}}cont-view{{end}}
|
||||
{{define "content"}}
|
||||
<div class="blockBody">
|
||||
<div class="row" style="margin-top:20px">
|
||||
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3">
|
||||
|
||||
<h2>{{T "verify_success"}}</h2>
|
||||
<hr class="colorgraph">
|
||||
{{ range (index $.FormErrors "errors")}}
|
||||
<div class="alert alert-danger">{{ . }}</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "js_footer"}}<script type="text/javascript" charset="utf-8" src="{{.URL.Parse "/js/registerPage.js"}}"></script>{{end}}
|
|
@ -7,16 +7,16 @@ import (
|
|||
func FormatFilesize(bytes int64) string {
|
||||
var unit string
|
||||
var value float64
|
||||
if bytes > 1024*1024*1024*1024 {
|
||||
if bytes >= 1024*1024*1024*1024 {
|
||||
unit = "TiB"
|
||||
value = float64(bytes) / (1024*1024*1024*1024)
|
||||
} else if bytes > 1024*1024*1024 {
|
||||
} else if bytes >= 1024*1024*1024 {
|
||||
unit = "GiB"
|
||||
value = float64(bytes) / (1024*1024*1024)
|
||||
} else if bytes > 1024*1024 {
|
||||
} else if bytes >= 1024*1024 {
|
||||
unit = "MiB"
|
||||
value = float64(bytes) / (1024*1024)
|
||||
} else if bytes > 1024 {
|
||||
} else if bytes >= 1024 {
|
||||
unit = "KiB"
|
||||
value = float64(bytes) / (1024)
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"strconv"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func IsZeroOfUnderlyingType(x interface{}) bool {
|
||||
|
@ -18,7 +19,7 @@ func AssignValue(model interface{}, form interface{}) {
|
|||
typeOfTForm := formElem.Type()
|
||||
for i := 0; i < formElem.NumField(); i++ {
|
||||
tag := typeOfTForm.Field(i).Tag
|
||||
if tag.Get("omit") != "false" {
|
||||
if tag.Get("omit") != "true" {
|
||||
modelField := modelIndirect.FieldByName(typeOfTForm.Field(i).Name)
|
||||
if modelField.IsValid() {
|
||||
formField := formElem.Field(i)
|
||||
|
@ -46,6 +47,78 @@ func BindValueForm(form interface{}, r *http.Request) {
|
|||
case "float" :
|
||||
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetFloat(float64(nbr))
|
||||
case "bool" :
|
||||
nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetBool(nbr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func ValidateForm(form interface{}, errorForm map[string][]string) (map[string][]string) {
|
||||
formElem := reflect.ValueOf(form).Elem()
|
||||
for i := 0; i < formElem.NumField(); i++ {
|
||||
typeField := formElem.Type().Field(i)
|
||||
tag := typeField.Tag
|
||||
inputName := typeField.Name
|
||||
if (tag.Get("hum_name") != "") { // For more human input name than gibberish
|
||||
inputName = tag.Get("hum_name")
|
||||
}
|
||||
if tag.Get("len_min") != "" { // Check minimum length
|
||||
lenMin, _ := strconv.Atoi(tag.Get("len_min"))
|
||||
if formElem.Field(i).Len() < lenMin {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Minimal length of %s required for the input: %s", strconv.Itoa(lenMin), inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("len_max") != "" { // Check minimum length
|
||||
lenMax, _ := strconv.Atoi(tag.Get("len_max"))
|
||||
if formElem.Field(i).Len() > lenMax {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Maximal length of %s required for the input: %s", strconv.Itoa(lenMax), inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("equalInput") != "" {
|
||||
otherInput := formElem.FieldByName(tag.Get("equalInput"))
|
||||
if formElem.Field(i).Interface() != otherInput.Interface() {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Must be same %s", inputName))
|
||||
}
|
||||
}
|
||||
switch typeField.Type.Name() {
|
||||
case "string" :
|
||||
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).String() == "" {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
case "int" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Int() > int64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
}
|
||||
case "float" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Float() != float64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
}
|
||||
case "bool" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.ParseBool(tag.Get("equal"))
|
||||
if formElem.Field(i).Bool() != equal {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorForm
|
||||
}
|
|
@ -19,6 +19,17 @@ type SearchParam struct {
|
|||
Sort string
|
||||
}
|
||||
|
||||
|
||||
// super hacky fix:
|
||||
var search_op string
|
||||
func Init(backend string) {
|
||||
if backend == "postgres" {
|
||||
search_op = "ILIKE"
|
||||
} else {
|
||||
search_op = "LIKE"
|
||||
}
|
||||
}
|
||||
|
||||
func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents, int) {
|
||||
return searchByQuery(r, pagenum, true)
|
||||
|
||||
|
|
Référencer dans un nouveau ticket