Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0

Fix conflicts

Cette révision appartient à :
ElegantMonkey 2017-05-08 18:16:21 -03:00
révision 108558dfdf
29 fichiers modifiés avec 177 ajouts et 605 suppressions

Voir le fichier

@ -1,6 +0,0 @@
package config
// Constants for public models.
const (
UserPublicFields = "id, username, md5, description, created_at, liking_count, liked_count"
)

Voir le fichier

@ -30,9 +30,8 @@ func GormInit(conf *config.Config) (*gorm.DB, error) {
// db.SingularTable(true)
if config.Environment == "DEVELOPMENT" {
db.LogMode(true)
// db.DropTable(&model.User{}, "UserFollower")
db.AutoMigrate(&model.Torrents{}, &model.UsersFollowers{}, &model.User{}, &model.Role{}, &model.Language{}, &model.Comment{})
// db.AutoMigrate(&model.Comment{})
db.AutoMigrate(&model.User{}, &model.UserFollows{})
db.AutoMigrate(&model.User{}, &model.Torrents{}, &model.Comment{}, &model.OldComment{})
// db.Model(&model.User{}).AddIndex("idx_user_token", "token")
}

Voir le fichier

@ -4,16 +4,28 @@ import (
"time"
)
// Comment is a comment model.
type Comment struct {
Id int `json:"id"`
Content string `json:"content"`
UserId int `json:"userId"`
Username string `json:"username"` // this is duplicate but it'll be faster rite?
TorrentId int
// LikingCount int `json:"likingCount"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DeletedAt *time.Time `json:"deletedAt""`
User User `json:"user"`
Id uint `gorm:"column:comment_id;primary_key"`
TorrentId uint `gorm:"column:torrent_id"`
UserId uint `gorm:"column:user_id"`
Content string `gorm:"column:content"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
User *User `gorm:"ForeignKey:user_id"`
}
type OldComment struct {
TorrentId uint `gorm:"column:torrent_id"`
Username string `gorm:"column:username"`
Content string `gorm:"column:content"`
Date time.Time `gorm:"column:date"`
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
}
func (c OldComment) TableName() string {
// cba to rename this in the db
return "comments_old"
}

Voir le fichier

@ -1,8 +0,0 @@
package model
// Role is a role model for user permission.
type Role struct {
Id uint `json:"id"`
Name string `json:"name",sql:"size:255"`
Description string `json:"description",sql:"size:255"`
}

Voir le fichier

@ -1,7 +0,0 @@
package model
//user status e.g. verified, filtered, etc
type Status struct {
Id int `json:"id"`
Name string `json:"name",sql:"size:255"`
}

Voir le fichier

@ -4,7 +4,6 @@ import (
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/util"
"encoding/json"
"html"
"html/template"
"strconv"
@ -21,26 +20,26 @@ type Feed struct {
}
type Torrents struct {
Id int `gorm:"column:torrent_id;primary_key"`
Name string `gorm:"column:torrent_name"`
Category int `gorm:"column:category_id"`
Sub_Category int `gorm:"column:sub_category_id"`
Status int `gorm:"column:status_id"`
Hash string `gorm:"column:torrent_hash"`
Date int64 `gorm:"column:date"`
Downloads int `gorm:"column:downloads"`
Filesize int64 `gorm:"column:filesize"`
Description string `gorm:"column:description"`
OwnerId int `gorm:"column:owner_id"`
OldComments []byte `gorm:"column:comments"`
Comments []Comment `gorm:"ForeignKey:TorrentId"`
Id uint `gorm:"column:torrent_id;primary_key"`
Name string `gorm:"column:torrent_name"`
Hash string `gorm:"column:torrent_hash"`
Category int `gorm:"column:category"`
Sub_Category int `gorm:"column:sub_category"`
Status int `gorm:"column:status"`
Date time.Time `gorm:"column:date"`
UploaderId uint `gorm:"column:uploader"`
Downloads int `gorm:"column:downloads"`
Stardom int `gorm:"column:stardom"`
Filesize int64 `gorm:"column:filesize"`
Description string `gorm:"column:description"`
WebsiteLink string `gorm:"column:website_link"`
Uploader *User `gorm:"ForeignKey:uploader"`
OldComments []OldComment `gorm:"ForeignKey:torrent_id"`
Comments []Comment `gorm:"ForeignKey:torrent_id"`
}
/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically
--------------------------------------------------------------------------------------------------------------
JSON Models Oject
--------------------------------------------------------------------------------------------------------------
*/
/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically */
type ApiResultJson struct {
Torrents []TorrentsJson `json:"torrents"`
@ -48,19 +47,10 @@ type ApiResultJson struct {
TotalRecordCount int `json:"totalRecordCount"`
}
type OldCommentsJson struct {
C template.HTML `json:"c"`
Us string `json:"us"`
Un string `json:"un"`
UI int `json:"ui"`
T int `json:"t"`
Av string `json:"av"`
ID string `json:"id"`
}
type CommentsJson struct {
Content template.HTML `json:"content"`
Username string `json:"username"`
Content template.HTML `json:"content"`
Date time.Time `json:"date"`
}
type TorrentsJson struct {
@ -81,33 +71,19 @@ type TorrentsJson struct {
func (t *Torrents) ToJson() TorrentsJson {
magnet := util.InfoHashToMagnet(strings.TrimSpace(t.Hash), t.Name, config.Trackers...)
offset := 0
var commentsJson []CommentsJson
if len(t.OldComments) != 0 {
b := []OldCommentsJson{}
err := json.Unmarshal([]byte(t.OldComments), &b)
if err == nil {
commentsJson = make([]CommentsJson, len(t.Comments)+len(b))
offset = len(b)
for i, commentJson := range b {
commentsJson[i] = CommentsJson{Content: commentJson.C,
Username: commentJson.Un}
}
} else {
commentsJson = make([]CommentsJson, len(t.Comments))
}
} else {
commentsJson = make([]CommentsJson, len(t.Comments))
for _, c := range t.OldComments {
commentsJson = append(commentsJson, CommentsJson{Username: c.Username, Content: template.HTML(c.Content), Date: c.Date})
}
for i, comment := range t.Comments {
commentsJson[i+offset] = CommentsJson{Content: template.HTML(comment.Content), Username: comment.Username}
for _, c := range t.Comments {
commentsJson = append(commentsJson, CommentsJson{Username: c.User.Username, Content: template.HTML(c.Content), Date: c.CreatedAt})
}
res := TorrentsJson{
Id: strconv.Itoa(t.Id),
Id: strconv.FormatUint(uint64(t.Id), 10),
Name: html.UnescapeString(t.Name),
Status: t.Status,
Hash: t.Hash,
Date: time.Unix(t.Date, 0).Format(time.RFC3339),
Date: t.Date.Format(time.RFC3339),
Filesize: util.FormatFilesize2(t.Filesize),
Description: template.HTML(t.Description),
Comments: commentsJson,

Voir le fichier

@ -7,78 +7,27 @@ import (
// omit is the bool type for omitting a field of struct.
type omit bool
// User is a user model
type User struct {
Id uint `json:"id"`
Email string `json:"email" sql:"size:255;unique"`
Password string `json:"password" sql:"size:255"`
Username string `json:"username" sql:"size:255;unique"`
Description string `json:"description" sql:"size:100"`
Token string `json:"token"`
TokenExpiration time.Time `json:"tokenExperiation"`
// email md5 for gravatar
Md5 string `json:"md5"`
// admin
Activation bool `json:"activation"`
PasswordResetToken string `json:"passwordResetToken"`
ActivationToken string `json:"activationToken"`
PasswordResetUntil time.Time `json:"passwordResetUntil"`
ActivateUntil time.Time `json:"activateUntil"`
ActivatedAt time.Time `json:"activatedAt"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DeletedAt *time.Time `json:"deletedAt"`
LastLoginAt time.Time `json:"lastLoginAt"`
CurrentLoginAt time.Time `json:"currentLoginAt"`
LastLoginIp string `json:"lastLoginIp" sql:"size:100"`
CurrentLoginIp string `json:"currentLoginIp" sql:"size:100"`
// Liking
LikingCount int `json:"likingCount"`
LikedCount int `json:"likedCount"`
Likings []User `gorm:"foreignkey:userId;associationforeignkey:follower_id;many2many:users_followers;"`
Liked []User `gorm:"foreignkey:follower_id;associationforeignkey:userId;many2many:users_followers;"`
//Connections []Connection
Languages string
Roles []Role `gorm:"many2many:users_roles;"` // Many To Many, users_roles
Torrents []Torrents `gorm:"ForeignKey:owner_id"`
Id uint `gorm:"column:user_id;primary_key"`
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
Email string `gorm:"column:email"`
Status int `gorm:"column:status"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
/*Api*/Token string `gorm:"column:api_token"`
//ApiTokenExpiry
TokenExpiration time.Time `gorm:"column:api_token_expiry"`
Language string `gorm:"column:language"`
}
// UsersFollowers is a relation table to relate users each other.
type UsersFollowers struct {
UserID uint `json:"user_id"`
FollowerID uint `json:"follower_id"`
}
// PublicUser is a public user model that contains only a few information for everyone.
type PublicUser struct {
*User
Email omit `json:"email,omitempty" sql:"size:255;unique"`
Password omit `json:"password,omitempty" sql:"size:255"`
Token omit `json:"token,omitempty"`
TokenExpiration omit `json:"tokenExperiation,omitempty"`
// admin
Activation omit `json:"activation,omitempty"`
PasswordResetToken omit `json:"passwordResetToken,omitempty"`
ActivationToken omit `json:"activationToken,omitempty"`
PasswordResetUntil omit `json:"passwordResetUntil,omitempty"`
ActivateUntil omit `json:"activateUntil,omitempty"`
ActivatedAt omit `json:"activatedAt,omitempty"`
UpdatedAt omit `json:"updatedAt,omitempty"`
DeletedAt omit `json:"deletedAt,omitempty"`
LastLoginAt omit `json:"lastLoginAt,omitempty"`
CurrentLoginAt omit `json:"currentLoginAt,omitempty"`
LastLoginIp omit `json:"lastLoginIp,omitempty" sql:"size:100"`
CurrentLoginIp omit `json:"currentLoginIp,omitempty" sql:"size:100"`
//Connections omit `json:"connections,omitempty"`
Languages omit `json:"languages,omitempty"`
Roles omit `json:"roles,omitempty"`
Torrents omit `json:"articles,omitempty"` //should user torrents not be displayed?
User *User
}
type UserFollows struct {
User User `gorm:"ForeignKey:user_id"`
Following User `gorm:"ForeignKey:following"`
}

Voir le fichier

@ -188,8 +188,25 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
border-radius: 0px;
}
:target {
background-color: #585b4f;
}
#mainmenu button .search_text {
display: none;
}
#mainmenu .navbar-form select.form-control
{
width: 12rem;
}
.special-img
{
position: relative;
top: -5px;
float: left;
left: -5px;
}
#mainmenu .badgemenu {
padding-top: 0;
}

Voir le fichier

@ -192,6 +192,7 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
:target {
background-color: #e5eecc;
}
#mainmenu button .search_text {
display: none;
}
@ -207,119 +208,6 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
left: -5px;
}
#mainmenu .badgemenu .profile-image {
line-height: 35px;
}
#mainmenu .navbar-header, #mainmenu .navbar-nav, #mainmenu .navbar-form {
padding-top: 10px;
}
#mainmenu .badgemenu {
padding-top: 0;
}
/* PROFILE PAGE */
/* Profile container */
.profile {
margin: 20px 0;
}
/* Profile sidebar */
.profile-sidebar {
padding: 20px 0 10px 0;
background: #182430;
}
.profile-userpic img {
float: none;
margin: 0 auto;
width: 50%;
height: 50%;
-webkit-border-radius: 50% !important;
-moz-border-radius: 50% !important;
border-radius: 50% !important;
}
.profile-usertitle {
text-align: center;
margin-top: 20px;
}
.profile-usertitle-name {
color: #5a7391;
font-size: 16px;
font-weight: 600;
margin-bottom: 7px;
}
.profile-usertitle-job {
text-transform: uppercase;
color: #5b9bd1;
font-size: 12px;
font-weight: 600;
margin-bottom: 15px;
}
.profile-userbuttons {
text-align: center;
margin-top: 10px;
}
.profile-userbuttons .btn {
text-transform: uppercase;
font-size: 11px;
font-weight: 600;
padding: 6px 15px;
margin-right: 5px;
}
.profile-userbuttons .btn:last-child {
margin-right: 0px;
}
.profile-usermenu {
margin-top: 30px;
}
.profile-usermenu ul li {
border-bottom: 1px solid #f0f4f7;
}
.profile-usermenu ul li:last-child {
border-bottom: none;
}
.profile-usermenu ul li a {
color: #93a3b5;
font-size: 14px;
font-weight: 400;
}
.profile-usermenu ul li a i {
margin-right: 8px;
font-size: 14px;
}
.profile-usermenu ul li a:hover {
background-color: #fafcfd;
color: #5b9bd1;
}
.profile-usermenu ul li.active {
border-bottom: none;
}
.profile-usermenu ul li.active a {
color: #5b9bd1;
background-color: #f6f9fb;
border-left: 2px solid #5b9bd1;
margin-left: -2px;
}
/* Profile Content */
.profile-content {
padding: 20px;
background: #fff;
min-height: 460px;
}

Voir le fichier

@ -100,7 +100,7 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
Sub_Category: sub_category,
Status: 1,
Hash: b.Hash,
Date: time.Now().Unix(),
Date: time.Now(),
Filesize: 0,
Description: string(b.Description)}
db.ORM.Create(&torrent)

Voir le fichier

@ -15,7 +15,7 @@ func RssHandler(w http.ResponseWriter, r *http.Request) {
created_as_time := time.Now()
if len(torrents) > 0 {
created_as_time = time.Unix(torrents[0].Date, 0)
created_as_time = torrents[0].Date
}
feed := &feeds.Feed{
Title: "Nyaa Pantsu",
@ -26,16 +26,15 @@ func RssHandler(w http.ResponseWriter, r *http.Request) {
feed.Items = make([]*feeds.Item, len(torrents))
for i, _ := range torrents {
timestamp_as_time := time.Unix(torrents[0].Date, 0)
torrent_json := torrents[i].ToJson()
feed.Items[i] = &feeds.Item{
// need a torrent view first
Id: "https://nyaa.pantsu.cat/view/" + strconv.Itoa(torrents[i].Id),
Id: "https://" + config.WebAddress + "/view/" + strconv.FormatUint(uint64(torrents[i].Id), 10),
Title: torrents[i].Name,
Link: &feeds.Link{Href: string(torrent_json.Magnet)},
Description: "",
Created: timestamp_as_time,
Updated: timestamp_as_time,
Created: torrents[0].Date,
Updated: torrents[0].Date,
}
}

Voir le fichier

@ -7,7 +7,7 @@ import (
var TemplateDir = "templates"
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate, viewProfileTemplate *template.Template
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate *template.Template
type templateLoader struct {
templ **template.Template
@ -63,11 +63,6 @@ func ReloadTemplates() {
name: "user_login",
file: "user/login.html",
},
templateLoader{
templ: &viewProfileTemplate,
name: "user_profile",
file: "user/profile.html",
},
}
for _, templ := range templs {
t := template.Must(template.New(templ.name).Funcs(FuncMap).ParseFiles(filepath.Join(TemplateDir, "index.html"), filepath.Join(TemplateDir, templ.file)))

Voir le fichier

@ -7,7 +7,6 @@ import (
"net/url"
"strconv"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/ewhal/nyaa/service/user/permission"
)
var FuncMap = template.FuncMap{
@ -60,9 +59,4 @@ var FuncMap = template.FuncMap{
return template.HTML(ret)
},
"T": i18n.IdentityTfunc,
"getAvatar": func (hash string, size int) string {
return "https://www.gravatar.com/avatar/"+hash+"?s="+strconv.Itoa(size)
},
"CurrentOrAdmin": userPermission.CurrentOrAdmin,
"CurrentUserIdentical": userPermission.CurrentUserIdentical,
}

Voir le fichier

@ -20,7 +20,7 @@ import (
type FaqTemplateVariables struct {
Navigation Navigation
Search SearchForm
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -28,7 +28,7 @@ type FaqTemplateVariables struct {
type NotFoundTemplateVariables struct {
Navigation Navigation
Search SearchForm
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -38,7 +38,7 @@ type ViewTemplateVariables struct {
Captcha captcha.Captcha
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -48,7 +48,7 @@ type UserRegisterTemplateVariables struct {
FormErrors map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -57,7 +57,7 @@ type UserVerifyTemplateVariables struct {
FormErrors map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -67,17 +67,7 @@ type UserLoginFormVariables struct {
FormErrors map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type UserProfileVariables struct {
UserProfile *model.User
FormErrors map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -86,7 +76,7 @@ type HomeTemplateVariables struct {
ListTorrents []model.TorrentsJson
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
@ -95,7 +85,7 @@ type UploadTemplateVariables struct {
Upload UploadForm
Search SearchForm
Navigation Navigation
User *model.User
User model.User
URL *url.URL
Route *mux.Route
}
@ -146,7 +136,7 @@ func NewSearchForm(params ...string) (searchForm SearchForm) {
return
}
func GetUser(r *http.Request) *model.User {
func GetUser(r *http.Request) model.User {
user, _ , _ := userService.RetrieveCurrentUser(r)
return &user
return user
}

Voir le fichier

@ -34,12 +34,12 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
Sub_Category: uploadForm.SubCategoryId,
Status: 1,
Hash: uploadForm.Infohash,
Date: time.Now().Unix(),
Date: time.Now(),
Filesize: uploadForm.Filesize, // FIXME: should set to NULL instead of 0
Description: uploadForm.Description}
db.ORM.Create(&torrent)
fmt.Printf("%+v\n", torrent)
url, err := Router.Get("view_torrent").URL("id", strconv.Itoa(torrent.Id))
url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.Id), 10))
if err == nil {
http.Redirect(w, r, url.String(), 302)
}

Voir le fichier

@ -5,7 +5,6 @@ import (
"github.com/ewhal/nyaa/service/captcha"
"github.com/ewhal/nyaa/service/user"
"github.com/ewhal/nyaa/service/user/permission"
"github.com/ewhal/nyaa/service/user/form"
"github.com/ewhal/nyaa/util/languages"
"github.com/ewhal/nyaa/util/modelHelper"
@ -49,25 +48,7 @@ func UserLoginFormHandler(w http.ResponseWriter, r *http.Request) {
// Getting User Profile
func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
userProfile, _, errorUser := userService.RetrieveUserForAdmin(id)
currentUser := GetUser(r)
view := r.URL.Query().Get("view")
if (errorUser == nil) {
if ((view == "edit")&&(userPermission.CurrentOrAdmin(currentUser, userProfile.Id))) {
} else {
languages.SetTranslationFromRequest(viewProfileTemplate, r, "en-us")
htv := UserProfileVariables{&userProfile, form.NewErrors(), NewSearchForm(), Navigation{}, currentUser, r.URL, mux.CurrentRoute(r)}
err := viewProfileTemplate.ExecuteTemplate(w, "index.html", htv)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
} else {
NotFoundHandler(w, r)
}
}
// Getting View User Profile Update
@ -84,7 +65,9 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
err["errors"] = append(err["errors"], "Wrong captcha!")
}
if (len(err) == 0) {
_, err = form.EmailValidation(r.PostFormValue("email"), err)
if len(r.PostFormValue("email")) > 0 {
_, err = form.EmailValidation(r.PostFormValue("email"), err)
}
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
if (len(err) == 0) {
modelHelper.BindValueForm(&b, r)

Voir le fichier

@ -3,6 +3,7 @@ package router
import (
"net/http"
"strconv"
"time"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
@ -43,14 +44,13 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) {
currentUser := GetUser(r)
content := p.Sanitize(r.FormValue("comment"))
idNum, err := strconv.Atoi(id)
username := "れんちょん"
userId := 0
idNum_, err := strconv.Atoi(id)
var idNum uint = uint(idNum_)
var userId uint = 0
if (currentUser.Id > 0) {
username = currentUser.Username
userId = int(currentUser.Id)
userId = currentUser.Id
}
comment := model.Comment{Username: username, UserId: userId, Content: content, TorrentId: idNum}
comment := model.Comment{TorrentId: idNum, UserId: userId, Content: content, CreatedAt: time.Now()}
db.ORM.Create(&comment)
url, err := Router.Get("view_torrent").URL("id", id)

Voir le fichier

@ -45,9 +45,16 @@ func GetFeeds() []model.Feed {
func GetTorrentById(id string) (model.Torrents, error) {
var torrent model.Torrents
if db.ORM.Where("torrent_id = ?", id).Preload("Comments").Find(&torrent).RecordNotFound() {
if db.ORM.Where("torrent_id = ?", id).
Preload("Comments").Preload("OldComments").
Find(&torrent).RecordNotFound() {
return torrent, errors.New("Article is not found.")
}
// .Preload("Comments.User") doesn't work
for i := range torrent.Comments {
torrent.Comments[i].User = new(model.User)
db.ORM.Where("user_id = ?", torrent.Comments[i].UserId).Find(torrent.Comments[i].User)
}
return torrent, nil
}
@ -55,21 +62,22 @@ func GetTorrentById(id string) (model.Torrents, error) {
func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) ([]model.Torrents, int) {
var torrents []model.Torrents
var count int
conditions := "torrent_hash IS NOT NULL" // filter out broken entries
var conditionArray []string
if strings.HasPrefix(orderBy, "filesize") {
// torrents w/ NULL filesize fuck up the sorting on postgres
// TODO: fix this properly
conditions += " AND filesize IS NOT NULL"
conditionArray = append(conditionArray, "filesize IS NOT NULL")
}
var params []interface{}
if parameters != nil { // if there is where parameters
if len(parameters.Conditions) > 0 {
conditions += " AND " + parameters.Conditions
conditionArray = append(conditionArray, parameters.Conditions)
}
params = parameters.Params
}
conditions := strings.Join(conditionArray, " AND ")
db.ORM.Model(&torrents).Where(conditions, params...).Count(&count)
// build custom db query for performance reasons
dbQuery := "SELECT * FROM torrents"
if conditions != "" {
dbQuery = dbQuery + " WHERE " + conditions

Voir le fichier

@ -8,7 +8,6 @@ import (
"golang.org/x/crypto/bcrypt"
formStruct "github.com/ewhal/nyaa/service/user/form"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util/log"
@ -147,9 +146,9 @@ func CurrentUser(r *http.Request) (model.User, error) {
return user, err
}
}
if db.ORM.Select(config.UserPublicFields+", email").Where("token = ?", token).First(&user).RecordNotFound() {
if db.ORM.Where("api_token = ?", token).First(&user).RecordNotFound() {
return user, errors.New("User is not found.")
}
db.ORM.Model(&user).Association("Roles").Find(&user.Roles)
db.ORM.Model(&user)
return user, nil
}

Voir le fichier

@ -46,14 +46,14 @@ func IsAgreed(t_and_c string) bool {
// RegistrationForm is used when creating a user.
type RegistrationForm struct {
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email" needed:"true"`
Email string `form:"email"`
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.
// LoginForm is used when a user logs in.
type LoginForm struct {
Username string `form:"username" needed="true"`
Password string `form:"password" needed="true"`
@ -80,19 +80,3 @@ type PasswordResetForm struct {
PasswordResetToken string `form:"token"`
Password string `form:"newPassword"`
}
// VerifyEmailForm is used when verifying an email.
type VerifyEmailForm struct {
ActivationToken string `form:"token"`
}
// ActivateForm is used when activating user.
type ActivateForm struct {
Activation bool `form:"activation"`
}
// UserRoleForm is used when adding or removing a role from a user.
type UserRoleForm struct {
UserId int `form:"userId"`
RoleId int `form:"roleId"`
}

Voir le fichier

@ -1,20 +1,16 @@
package userPermission
import (
"errors"
"net/http"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/user"
"github.com/ewhal/nyaa/util/log"
)
// HasAdmin checks that user has an admin permission.
func HasAdmin(user *model.User) bool {
name := "admin"
for _, role := range user.Roles {
log.Debugf("HasAdmin role.Name : %s", role.Name)
if role.Name == name {
return true
}
}
return false
return user.Status == 2
}
// CurrentOrAdmin check that user has admin permission or user is the current user.
@ -24,10 +20,14 @@ func CurrentOrAdmin(user *model.User, userId uint) bool {
}
// CurrentUserIdentical check that userId is same as current user's Id.
func CurrentUserIdentical(user *model.User, userId uint) (bool) {
if user.Id != userId {
return false
func CurrentUserIdentical(r *http.Request, userId uint) (bool, error) {
currentUser, err := userService.CurrentUser(r)
if err != nil {
return false, errors.New("Auth failed.")
}
if currentUser.Id != userId {
return false, errors.New("User is not identical.")
}
return true
return true, nil
}

Voir le fichier

@ -4,6 +4,7 @@ import (
"errors"
"net/http"
"strconv"
"time"
"golang.org/x/crypto/bcrypt"
@ -43,20 +44,24 @@ func SuggestUsername(username string) string {
}
return usernameCandidate
}
func CheckEmail(email string) bool {
if len(email) == 0 {
return true
}
var count int
db.ORM.Model(model.User{}).Where(&model.User{Email: email}).Count(&count)
db.ORM.Model(model.User{}).Where("email = ?", email).Count(&count)
if count == 0 {
return false
return false // duplicate
}
return true
}
// CreateUserFromForm creates a user from a registration form.
func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.User, error) {
var user model.User
log.Debugf("registrationForm %+v\n", registrationForm)
modelHelper.AssignValue(&user, &registrationForm)
user.Md5 = crypto.GenerateMD5Hash(user.Email) // Gravatar
token, err := crypto.GenerateRandomToken32()
if err != nil {
return user, errors.New("Token not generated.")
@ -106,8 +111,8 @@ func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, in
var isAuthor bool
// var publicUser *model.PublicUser
// publicUser.User = &user
if db.ORM.Select(config.UserPublicFields).First(&user, id).RecordNotFound() {
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusNotFound, errors.New("User is not found.")
if db.ORM.First(&user, id).RecordNotFound() {
return nil, isAuthor, currentUserId, http.StatusNotFound, errors.New("User is not found.")
}
currentUser, err := CurrentUser(r)
if err == nil {
@ -115,30 +120,6 @@ func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, in
isAuthor = currentUser.Id == user.Id
}
var likings []model.User
var likingCount int
db.ORM.Table("users_followers").Where("users_followers.user_id=?", user.Id).Count(&likingCount)
if err = db.ORM.Order("created_at desc").Select(config.UserPublicFields).
Joins("JOIN users_followers on users_followers.user_id=?", user.Id).
Where("users.id = users_followers.follower_id").
Group("users.id").Find(&likings).Error; err != nil {
log.Fatal(err.Error())
}
user.Likings = likings
var liked []model.User
var likedCount int
db.ORM.Table("users_followers").Where("users_followers.follower_id=?", user.Id).Count(&likedCount)
if err = db.ORM.Order("created_at desc").Select(config.UserPublicFields).
Joins("JOIN users_followers on users_followers.follower_id=?", user.Id).
Where("users.id = users_followers.user_id").
Group("users.id").Find(&liked).Error; err != nil {
log.Fatal(err.Error())
}
user.Liked = liked
log.Debugf("user liking %v\n", user.Likings)
log.Debugf("user liked %v\n", user.Liked)
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusOK, nil
}
@ -146,7 +127,7 @@ func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, in
func RetrieveUsers() []*model.PublicUser {
var users []*model.User
var userArr []*model.PublicUser
db.ORM.Select(config.UserPublicFields).Find(&users)
db.ORM.Find(&users)
for _, user := range users {
userArr = append(userArr, &model.PublicUser{User: user})
}
@ -155,7 +136,6 @@ func RetrieveUsers() []*model.PublicUser {
// UpdateUserCore updates a user. (Applying the modifed data of user).
func UpdateUserCore(user *model.User) (int, error) {
user.Md5 = crypto.GenerateMD5Hash(user.Email)
token, err := crypto.GenerateRandomToken32()
if err != nil {
return http.StatusInternalServerError, errors.New("Token not generated.")
@ -165,6 +145,7 @@ func UpdateUserCore(user *model.User) (int, error) {
if db.ORM.Save(user).Error != nil {
return http.StatusInternalServerError, errors.New("User is not updated.")
}
user.UpdatedAt = time.Now()
return http.StatusOK, nil
}
@ -220,49 +201,6 @@ func DeleteUser(w http.ResponseWriter, id string) (int, error) {
return status, err
}
// AddRoleToUser adds a role to a user.
func AddRoleToUser(r *http.Request) (int, error) {
var form formStruct.UserRoleForm
var user model.User
var role model.Role
var roles []model.Role
modelHelper.BindValueForm(&form, r)
if db.ORM.First(&user, form.UserId).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
}
if db.ORM.First(&role, form.RoleId).RecordNotFound() {
return http.StatusNotFound, errors.New("Role is not found.")
}
log.Debugf("user email : %s", user.Email)
log.Debugf("Role name : %s", role.Name)
db.ORM.Model(&user).Association("Roles").Append(role)
db.ORM.Model(&user).Association("Roles").Find(&roles)
if db.ORM.Save(&user).Error != nil {
return http.StatusInternalServerError, errors.New("Role not appended to user.")
}
return http.StatusOK, nil
}
// RemoveRoleFromUser removes a role from a user.
func RemoveRoleFromUser(w http.ResponseWriter, r *http.Request, userId string, roleId string) (int, error) {
var user model.User
var role model.Role
if db.ORM.First(&user, userId).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
}
if db.ORM.First(&role, roleId).RecordNotFound() {
return http.StatusNotFound, errors.New("Role is not found.")
}
log.Debugf("user : %v\n", user)
log.Debugf("role : %v\n", role)
if db.ORM.Model(&user).Association("Roles").Delete(role).Error != nil {
return http.StatusInternalServerError, errors.New("Role is not deleted from user.")
}
return http.StatusOK, nil
}
// RetrieveCurrentUser retrieves a current user.
func RetrieveCurrentUser(r *http.Request) (model.User, int, error) {
user, err := CurrentUser(r)
@ -275,7 +213,7 @@ func RetrieveCurrentUser(r *http.Request) (model.User, int, error) {
// RetrieveUserByEmail retrieves a user by an email
func RetrieveUserByEmail(email string) (*model.PublicUser, string, int, error) {
var user model.User
if db.ORM.Unscoped().Select(config.UserPublicFields).Where("email like ?", "%"+email+"%").First(&user).RecordNotFound() {
if db.ORM.Unscoped().Where("email = ?", email).First(&user).RecordNotFound() {
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("User is not found.")
}
return &model.PublicUser{User: &user}, email, http.StatusOK, nil
@ -285,7 +223,7 @@ func RetrieveUserByEmail(email string) (*model.PublicUser, string, int, error) {
func RetrieveUsersByEmail(email string) []*model.PublicUser {
var users []*model.User
var userArr []*model.PublicUser
db.ORM.Select(config.UserPublicFields).Where("email like ?", "%"+email+"%").Find(&users)
db.ORM.Where("email = ?", email).Find(&users)
for _, user := range users {
userArr = append(userArr, &model.PublicUser{User: user})
}
@ -295,7 +233,7 @@ func RetrieveUsersByEmail(email string) []*model.PublicUser {
// RetrieveUserByUsername retrieves a user by username.
func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, error) {
var user model.User
if db.ORM.Unscoped().Select(config.UserPublicFields).Where("username like ?", "%"+username+"%").First(&user).RecordNotFound() {
if db.ORM.Where("username = ?", username).First(&user).RecordNotFound() {
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("User is not found.")
}
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
@ -307,8 +245,7 @@ func RetrieveUserForAdmin(id string) (model.User, int, error) {
if db.ORM.First(&user, id).RecordNotFound() {
return user, http.StatusNotFound, errors.New("User is not found.")
}
db.ORM.Model(&user).Related("Torrents").Find(&model.Torrents{})
db.ORM.Model(&user).Association("Roles").Find(&user.Roles)
db.ORM.Model(&user)
return user, http.StatusOK, nil
}
@ -318,28 +255,12 @@ func RetrieveUsersForAdmin() []model.User {
var userArr []model.User
db.ORM.Find(&users)
for _, user := range users {
db.ORM.Model(&user).Related("Torrents").Find(&model.Torrents{})
db.ORM.Model(&user).Association("Roles").Find(&user.Roles)
db.ORM.Model(&user)
userArr = append(userArr, user)
}
return userArr
}
// ActivateUser toggle activation of a user.
func ActivateUser(r *http.Request, id string) (model.User, int, error) {
var user model.User
var form formStruct.ActivateForm
modelHelper.BindValueForm(&form, r)
if db.ORM.First(&user, id).RecordNotFound() {
return user, http.StatusNotFound, errors.New("User is not found.")
}
user.Activation = form.Activation
if db.ORM.Save(&user).Error != nil {
return user, http.StatusInternalServerError, errors.New("User not activated.")
}
return user, http.StatusOK, nil
}
// CreateUserAuthentication creates user authentication.
func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, error) {
var form formStruct.LoginForm

Voir le fichier

@ -3,15 +3,15 @@ package userService
import (
"errors"
"net/http"
"time"
// "time"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util/crypto"
// "github.com/ewhal/nyaa/util/crypto"
"github.com/ewhal/nyaa/util/email"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/timeHelper"
// "github.com/ewhal/nyaa/util/log"
// "github.com/ewhal/nyaa/util/timeHelper"
"github.com/nicksnyder/go-i18n/i18n"
)
@ -28,7 +28,7 @@ func SendEmailVerfication(to string, token string, locale string) error {
// SendVerificationToUser sends an email verification token to user.
func SendVerificationToUser(user model.User) (int, error) {
var status int
/*var status int
var err error
user.ActivateUntil = timeHelper.TwentyFourHoursLater()
user.ActivationToken, err = crypto.GenerateRandomToken32()
@ -45,12 +45,12 @@ func SendVerificationToUser(user model.User) (int, error) {
if err != nil {
return http.StatusInternalServerError, err
}
return http.StatusOK, err
return http.StatusOK, err*/
return 0, errors.New("NotImpl")
}
// SendVerification sends an email verification token.
func SendVerification(r *http.Request) (int, error) {
var user model.User
currentUser, err := CurrentUser(r)
if err != nil {
@ -65,7 +65,7 @@ func SendVerification(r *http.Request) (int, error) {
// EmailVerification verifies an email of user.
func EmailVerification(token string,w http.ResponseWriter) (int, error) {
var user model.User
/*var user model.User
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.")
@ -85,5 +85,6 @@ func EmailVerification(token string,w http.ResponseWriter) (int, error) {
return status, err
}
status, err = SetCookie(w, user.Token)
return status, err
return status, err*/
return 0, errors.New("NotImpl")
}

Voir le fichier

@ -3,8 +3,7 @@
<ul class="nav navbar-nav navbar-right badgemenu">
<li class="dropdown">
{{if gt .Id 0}}
<a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}" class="dropdown-toggle profile-image" data-toggle="dropdown">
<img src="{{ getAvatar .Md5 50 }}" class="img-circle special-img"> {{ .Username }} <b class="caret"></b></a>
<a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}" class="dropdown-toggle" data-toggle="dropdown">{{ .Username }} <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}"><i class="fa fa-cog"></i> {{T "profile"}}</a></li>
<li class="divider"></li>

Voir le fichier

@ -1,48 +0,0 @@
{{define "profile_content"}}
{{with .UserProfile}}
<div class="table-responsive">
<table class="table custom-table-hover">
<tr>
<th>{{T "category"}}</th>
<th>{{T "name"}}</th>
<th>{{T "date"}}</th>
<th>{{T "size"}}</th>
<th>{{T "links"}}</th>
</tr>
{{ range .Torrents }}
<tr class="torrent-info
{{if eq .Status 2}}remake{{end}}
{{if eq .Status 3}}trusted{{end}}
{{if eq .Status 4}}aplus{{end}}">
<!-- forced width because the <td> gets bigger randomly otherwise -->
<td style="width:80px">
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .Sub_Category) }}">
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .Sub_Category) }}">
</a>
</td>
<td class="name">
<a href="{{genRoute "view_torrent" "id" .Id }}">
{{.Name}}
</a>
</td>
<td class="date date-short">{{.Date}}</td>
<td class="filesize">{{.Filesize}}</td>
<td>
<a href="{{.Magnet}}" title="Magnet link">
<span class="glyphicon glyphicon-magnet" aria-hidden="true"></span>
</a>
<a href="http://anicache.com/torrent/{{.Hash}}.torrent" title="Torrent file">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</a>
</td>
</tr>
{{end}}
</table>
<nav class="torrentNav" aria-label="Page navigation">
<ul class="pagination">
<li><a href="{{ genRoute "search" }}?userId={{ .Id }}" aria-label="Next"><span class="glyphicon glyphicon-add"></span> {{ T "see_more_torrents_from" .Username }}</a></li>
</ul>
</nav>
</div>
{{end}}
{{end}}

Voir le fichier

@ -7,7 +7,7 @@
{{ genNav .Navigation .URL 10 }}
</ul>
</nav>
{{ if gt (len .ListTorrents) 0 }}
<div class="table-responsive">
<table class="table custom-table-hover">
<tr>
@ -52,8 +52,5 @@
</ul>
</nav>
</div>
{{else}}
<h2 style="text-align: center;">{{T "no_results_found"}}</h2>
{{end}}
</div>
{{end}}

Voir le fichier

@ -1,62 +0,0 @@
{{define "title"}}{{ T "profile_page" .UserProfile.Username }}{{end}}
{{define "contclass"}}cont-view{{end}}
{{define "content"}}
<div class="row profile">
{{with .UserProfile}}
<div class="col-md-3">
<div class="profile-sidebar">
<!-- SIDEBAR USERPIC -->
<div class="profile-userpic">
<img src="{{ getAvatar .Md5 130 }}" class="img-responsive" alt="{{.Username}}">
</div>
<!-- END SIDEBAR USERPIC -->
<!-- SIDEBAR USER TITLE -->
<div class="profile-usertitle">
<div class="profile-usertitle-name">
{{.Username}}
</div>
<div class="profile-usertitle-job">
{{if .Roles }}{{index .Roles 0 }}{{end}}
</div>
</div>
<!-- END SIDEBAR USER TITLE -->
<!-- SIDEBAR BUTTONS -->
<div class="profile-userbuttons">
{{if gt $.User.Id 0 }}
{{if not (CurrentUserIdentical $.User .Id) }}
<button type="button" class="btn btn-success btn-sm">{{ T "follow"}}</button>
{{end}}
{{end}}
<!-- <button type="button" class="btn btn-danger btn-sm">Message</button> -->
</div>
<!-- END SIDEBAR BUTTONS -->
<!-- SIDEBAR MENU -->
<div class="profile-usermenu">
<ul class="nav">
<li class="active">
<a href="#">
<i class="glyphicon glyphicon-home"></i>
{{T "torrents"}} </a>
</li>
{{if gt $.User.Id 0 }}
{{if CurrentOrAdmin $.User .Id }}
<li>
<a href="#">
<i class="glyphicon glyphicon-user"></i>
{{T "settings"}} </a>
</li>
{{end}}
{{end}}
</ul>
</div>
<!-- END MENU -->
</div>
</div>
{{end}}
<div class="col-md-9">
<div class="profile-content">
{{ block "profile_content" . }}{{end}}
</div>
</div>
</div>
{{end}}

Voir le fichier

@ -3,15 +3,14 @@ package languages
import (
"github.com/nicksnyder/go-i18n/i18n"
"html/template"
"fmt"
"net/http"
)
func SetTranslation(tmpl *template.Template, language string, languages ...string) {
T, _ := i18n.Tfunc(language, languages...)
tmpl.Funcs(map[string]interface{}{
"T": func(str string, args ...interface{}) template.HTML {
return template.HTML(fmt.Sprintf(T(str), args...))
"T": func(str string) template.HTML {
return template.HTML(T(str))
},
})
}

Voir le fichier

@ -19,7 +19,6 @@ type SearchParam struct {
Max int
Status string
Sort string
UserId string
}
func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents, int) {
@ -38,7 +37,6 @@ func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents,
search_param.Status = r.URL.Query().Get("s")
search_param.Sort = r.URL.Query().Get("sort")
search_param.Order = r.URL.Query().Get("order")
search_param.UserId = r.URL.Query().Get("userId")
catsSplit := strings.Split(search_param.Category, "_")
// need this to prevent out of index panics
@ -95,11 +93,6 @@ func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents,
}
parameters.Params = append(parameters.Params, search_param.Status)
}
if search_param.UserId != "" {
conditions = append(conditions, "owner_id = ?")
parameters.Params = append(parameters.Params, search_param.UserId)
}
searchQuerySplit := strings.Fields(search_param.Query)
for i, word := range searchQuerySplit {
firstRune, _ := utf8.DecodeRuneInString(word)