作者:vichetu
项目:lov3lym
func Photos(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusNotFound)
}
var photos []*models.Photo
if err := ctx.C(P).Find(bson.M{"user": bson.ObjectIdHex(id), "active": true}).All(&photos); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
user := new(models.User)
if err := ctx.C("users").FindId(bson.ObjectIdHex(id)).One(user); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
// find the index of the photo
photoId := req.URL.Query().Get(":photo")
ctx.Data["index"] = 0
var pIds []bson.ObjectId
for i, p := range photos {
if p.Id.Hex() == photoId {
ctx.Data["index"] = i
}
pIds = append(pIds, p.Id)
}
return AJAX("galleria.html").Execute(w, map[string]interface{}{
"photos": photos,
"user": user,
"hash": models.GenUUID(),
"ctx": ctx,
})
}
作者:vichetu
项目:lov3lym
func report(w http.ResponseWriter, req *http.Request, ctx *models.Context, repType string) error {
if ctx.User == nil {
return perform_status(w, req, http.StatusForbidden)
}
if req.URL.Query().Get(":csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
photoId := req.URL.Query().Get(":photo")
if !bson.IsObjectIdHex(photoId) {
return perform_status(w, req, http.StatusForbidden)
}
query := bson.M{"_id": bson.ObjectIdHex(photoId), "active": true, repType + "reporters": bson.M{"$ne": ctx.User.Id}}
update := bson.M{
"$push": bson.M{repType + "reporters": ctx.User.Id},
"$inc": bson.M{repType + "count": 1},
}
if err := ctx.C(P).Update(query, update); err != nil {
// toggle report
// This query succeeds when the voter has already voted on the story.
//query = {_id: ObjectId("4bcc9e697e020f2d44471d27"), voters: user_id};
// Update to remove the user from the array and decrement the number of votes.
//update = {'$pull': {'voters': user_id}, '$inc': {vote_count: -1}}
//db.stories.update(query, update);
}
return nil
}
作者:vichetu
项目:lov3lym
func CommentForm(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
//set up the collection and query
id := req.URL.Query().Get(":id")
kind := req.URL.Query().Get(":kind")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
var object models.Commenter
switch kind {
case "p":
query := ctx.C(P).FindId(bson.ObjectIdHex(id))
//execute the query
photo := &models.Photo{}
if err := query.One(&photo); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
object = photo
case "c":
query := ctx.C(C).FindId(bson.ObjectIdHex(id))
//execute the query
contest := &models.Contest{}
if err := query.One(&contest); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
object = contest
}
//execute the template
return AJAX("comments.html").Execute(w, map[string]interface{}{
"object": object,
"kind": kind,
"ctx": ctx,
})
}
作者:vichetu
项目:lov3lym
func SendMessage(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
to := req.URL.Query().Get(":to")
if !bson.IsObjectIdHex(to) {
return perform_status(w, req, http.StatusForbidden)
}
if to == ctx.User.Id.Hex() {
return perform_status(w, req, http.StatusForbidden)
}
m := models.Message{
Id: bson.NewObjectId(),
From: ctx.User.Id,
To: bson.ObjectIdHex(to),
UserName: ctx.User.FullName(),
Avatar: ctx.User.Avatar,
Subject: req.FormValue("subject"),
Body: req.FormValue("body"),
}
if err := ctx.C(M).Insert(m); err != nil {
models.Log("Error sending message: ", err.Error())
}
return nil
}
作者:vichetu
项目:lov3lym
func GetPhotoVotes(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
match := bson.M{"photo": bson.ObjectIdHex(id)}
if f, ok := ctx.Session.Values["filter"]; ok {
f.(*models.Filter).AddQuery(match)
}
var result bson.M
pipe := ctx.C(V).Pipe([]bson.M{
{"$match": match},
{"$group": bson.M{
"_id": "$photo",
"avg": bson.M{"$avg": "$score"},
"count": bson.M{"$sum": 1},
"user": bson.M{"$addToSet": "$photouser"},
}},
{"$unwind": "$user"},
})
pipe.One(&result)
if result["user"] != nil && result["user"].(bson.ObjectId) != ctx.User.Id {
return perform_status(w, req, http.StatusForbidden)
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"avg": %.1f, "count": %d}`, result["avg"], result["count"])
return nil
}
作者:vichetu
项目:lov3lym
func Messages(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
var messages []*models.Message
ctx.C(M).Find(bson.M{"to": ctx.User.Id}).All(&messages)
return T("messages.html").Execute(w, map[string]interface{}{
"ctx": ctx,
"messages": messages,
})
}
作者:vichetu
项目:lov3lym
func ResetPassword(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
// should not be logged in
if ctx.User != nil {
ctx.Session.AddFlash(models.F(models.SUCCESS, trans("Already logged in!", ctx)))
http.Redirect(w, req, reverse("index"), http.StatusSeeOther)
return nil
}
form := models.UserForm
form.Fields = form.Fields[2:3]
r := (&form).Load(req)
ctx.Data["result"] = r
if r.Err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem reseting password:", ctx), r.Err.Error()))
return ResetPasswordForm(w, req, ctx)
}
if req.FormValue("csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
if len(r.Errors) != 0 {
return ResetPasswordForm(w, req, ctx)
}
email := r.Values["email"]
u := &models.User{}
err := ctx.C(U).Find(bson.M{"email": email}).One(&u)
if err == nil {
pt := &models.PasswordToken{
Uuid: models.GenUUID(),
User: u.Id,
CreatedOn: time.Now(),
}
// set new password to database
if err := ctx.C(PT).Insert(pt); err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem reseting password:", ctx), err.Error()))
models.Log(err.Error())
r.Err = err
return ResetPasswordForm(w, req, ctx)
}
// sending mail
body := fmt.Sprintf("Subject: lov3ly.me password reset\r\n\r\nChange password link: http://%s\n\nIf you have NOT requested this, please ignore. Link available for 24 hours.\n\nHave fun,\nlov3ly.me Team", req.Host+reverse("change_token", "uuid", pt.Uuid))
go func() {
err := models.SendEmail([]byte(body), email)
if err != nil {
models.Log("Error sending mail: ", err.Error())
}
}()
ctx.Session.AddFlash(models.F(models.SUCCESS, trans("Email sent succesfully!", ctx)))
} else {
ctx.Session.AddFlash(models.F(models.NOTICE, trans("Email not in our database:", ctx), err.Error()))
}
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
作者:vichetu
项目:lov3lym
func Admin(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil || !ctx.User.Admin {
return perform_status(w, req, http.StatusForbidden)
}
photoCount, _ := ctx.C(P).Find(nil).Count()
pp := NewPagination(photoCount, req.URL.Query())
photoSkip := pp.PerPage * (pp.Current - 1)
var photos []*models.Photo
if err := ctx.C(P).Find(nil).Skip(photoSkip).Limit(pp.PerPage).All(&photos); err != nil {
models.Log("error getting photos: ", err.Error())
return err
}
userCount, _ := ctx.C(U).Find(nil).Count()
up := NewPagination(userCount, req.URL.Query())
userSkip := up.PerPage * (up.Current - 1)
var users []*models.User
if err := ctx.C(U).Find(nil).Skip(userSkip).Limit(up.PerPage).All(&users); err != nil {
models.Log("error getting users: ", err.Error())
return err
}
return T("admin.html").Execute(w, map[string]interface{}{
"ctx": ctx,
"pp": pp,
"photos": photos,
"up": up,
"users": users,
})
}
作者:vichetu
项目:lov3lym
func Delete(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
if req.URL.Query().Get(":csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
if rc, _ := ctx.C(C).Find(bson.M{"registered.photo": bson.ObjectIdHex(id)}).Count(); rc != 0 {
// the photo is registered in contests
// only mark as deleted
if err := ctx.C(P).UpdateId(bson.ObjectIdHex(id), bson.M{"$set": bson.M{"deleted": true, "active": false}}); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
// delete non contest votes
// delete related votes
if _, err := ctx.C(V).RemoveAll(bson.M{"photo": bson.ObjectIdHex(id), "contest": bson.M{"$exists": false}}); err != nil {
models.Log("Error deleting votes on photo delete: ", err.Error())
}
} else {
// the photo is not registered in any contest
if err := ctx.C(P).RemoveId(bson.ObjectIdHex(id)); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
// delete from disk
err := os.Remove(path.Join(models.DATA_DIR, models.UPLOADS, fmt.Sprintf("%s.jpg", id)))
if err != nil {
models.Log("Error deleting image:", err.Error())
}
err = os.Remove(path.Join(models.DATA_DIR, models.UPLOADS, fmt.Sprintf("%s_thumb.jpg", id)))
if err != nil {
models.Log("Error deleting image:", err.Error())
}
// delete related votes
if _, err := ctx.C(V).RemoveAll(bson.M{"photo": bson.ObjectIdHex(id)}); err != nil {
models.Log("Error deleting votes on photo delete: ", err.Error())
}
}
http.Redirect(w, req, reverse("upload", "id", ""), http.StatusSeeOther)
return nil
}
作者:vichetu
项目:lov3lym
func SetAvatar(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
return perform_status(w, req, http.StatusForbidden)
}
if req.URL.Query().Get(":csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
photoId := req.URL.Query().Get(":photo")
if bson.IsObjectIdHex(photoId) {
newAvatar := models.ImageUrl(photoId, "thumb")
ctx.User.Avatar = newAvatar
ctx.C(U).UpdateId(ctx.User.Id, bson.M{"$set": bson.M{"avatar": newAvatar}})
//ctx.C(P).Update(bson.M{"comments.user": ctx.User.Id}, bson.M{"comments.$.avatar": bson.M{"$set": ctx.User.Gravatar(80)}})
}
return nil
}
作者:vichetu
项目:lov3lym
func typeAhead(field, q string, ctx *models.Context) string {
var users []map[string]string
query := bson.M{field: bson.RegEx{"^" + q, "i"}}
ctx.C(U).Find(query).Select(bson.M{field: 1, "_id": 0}).All(&users)
distinct := make(map[string]bool)
for _, u := range users {
if _, ok := distinct[u[field]]; !ok {
distinct[u[field]] = true
}
}
var result string
for k, _ := range distinct {
result += `"` + k + `",`
}
result = strings.TrimRight(result, ",")
return `{"options":[` + result + `]}`
}
作者:vichetu
项目:lov3lym
func DelMessage(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
if err := ctx.C(M).Remove(bson.M{"_id": bson.ObjectIdHex(id), "to": ctx.User.Id}); err != nil {
models.Log("error removing message: ", err.Error())
return err
}
fmt.Fprint(w, "ok")
return nil
}
作者:vichetu
项目:lov3lym
func ChangePassword(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
if req.FormValue("csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
old_pass := req.FormValue("password")
u := models.User{}
if err := ctx.C(U).Find(bson.M{"email": ctx.User.Email}).One(&u); err != nil {
return perform_status(w, req, http.StatusNotFound)
}
if len(u.Password) > 0 { // if the account was not created with social auth
err := bcrypt.CompareHashAndPassword(u.Password, []byte(old_pass))
if err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Invalid Old Password", ctx)))
return ChangePasswordForm(w, req, ctx)
}
}
new_pass := req.FormValue("password1")
if len(new_pass) < 5 {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Passwords too short (5 chars or more)", ctx)))
return ChangePasswordForm(w, req, ctx)
}
vfy_pass := req.FormValue("password2")
if new_pass != vfy_pass {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Password did not match", ctx)))
return ChangePasswordForm(w, req, ctx)
}
hpass, err := models.EncryptPassword(new_pass)
if err != nil {
return internal_error(w, req, err.Error())
}
// set new password to database
if err := ctx.C(U).UpdateId(ctx.User.Id, bson.M{"$set": bson.M{"password": hpass}}); err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem changing password:", ctx), err.Error()))
models.Log(err.Error())
return ChangePasswordForm(w, req, ctx)
}
ctx.Session.AddFlash(models.F(models.SUCCESS, trans("Password changed succesfully!", ctx)))
http.Redirect(w, req, reverse("index"), http.StatusSeeOther)
return nil
}
作者:vichetu
项目:lov3lym
func DelUser(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil || !ctx.User.Admin {
return perform_status(w, req, http.StatusForbidden)
}
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
if err := ctx.C(U).RemoveId(bson.ObjectIdHex(id)); err != nil {
models.Log("error deleting user: ", err.Error())
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem deleting user:", ctx), err.Error()))
http.Redirect(w, req, reverse("admin"), http.StatusSeeOther)
return err
}
ctx.Session.AddFlash(models.F(models.SUCCESS, trans("User deleted!", ctx)))
http.Redirect(w, req, reverse("admin"), http.StatusSeeOther)
return nil
}
作者:vichetu
项目:lov3lym
func Profile(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
if req.FormValue("csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
ctx.Data["title"] = "Profile"
form := models.UserForm
form.Fields = form.Fields[2:] // remove passwords
r := (&form).Load(req)
ctx.Data["result"] = r
if len(r.Errors) != 0 {
return ProfileForm(w, req, ctx)
}
u := r.Value.(map[string]interface{})
gender := u["gender"].(string)
if gender != "m" && gender != "f" {
r.Errors["gender"] = errors.New("Please select Male or Female")
}
now := time.Now()
oldest := time.Date(now.Year()-120, 1, 1, 0, 0, 0, 0, time.UTC)
bDate := u["birthdate"].(time.Time)
if bDate.Before(oldest) || bDate.After(now) {
r.Errors["birthdate"] = errors.New("Invalid birth date")
}
if r.Err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem editing profile:", ctx), r.Err.Error()))
return ProfileForm(w, req, ctx)
}
if len(r.Errors) != 0 {
return ProfileForm(w, req, ctx)
}
if err := ctx.C(U).UpdateId(ctx.User.Id, bson.M{"$set": u}); err != nil {
ctx.Session.AddFlash(models.F(models.ERROR, trans("Problem editing profile:", ctx), err.Error()))
models.Log(err.Error())
r.Err = err
}
ctx.Session.AddFlash(models.F(models.SUCCESS, trans("Profile updated succesfully!", ctx)))
return ProfileForm(w, req, ctx)
}
作者:vichetu
项目:lov3lym
func Rankings(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
var results models.WilsonSorter
pipe := ctx.C(V).Pipe([]bson.M{
{"$match": bson.M{"active": true}},
{"$group": bson.M{
"_id": "$photo",
"count": bson.M{"$sum": 1},
"avg": bson.M{"$avg": "$score"},
"scores": bson.M{"$push": "$score"},
"title": bson.M{"$addToSet": "$title"},
"description": bson.M{"$addToSet": "$description"},
"user": bson.M{"$addToSet": "$photouser"},
}},
{"$unwind": "$user"},
{"$unwind": "$title"},
{"$unwind": "$description"},
})
pipe.All(&results)
// calculate wilson rating http://www.goproblems.com/test/wilson/wilson-new.php
vc := make([]int, 5)
for _, r := range results {
scores := r["scores"].([]interface{})
for _, s := range scores {
index := int(s.(float64) - 1)
vc[index] += 1
}
sum := 0.0
for i, c := range vc {
w := float64(i) / 4.0
sum += float64(c) * w
}
r["wilson"] = models.Wilson(len(scores), sum)
vc[0], vc[1], vc[2], vc[3], vc[4] = 0, 0, 0, 0, 0
}
sort.Sort(results)
return AJAX("rankings.html").Execute(w, map[string]interface{}{
"results": results,
"ctx": ctx,
})
}
作者:vichetu
项目:lov3lym
func Random(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
page := 1
page, err := strconv.Atoi(req.URL.Query().Get(":page"))
if err != nil && page == 0 {
page = 1
}
skip := ITEMS_PER_PAGE * (page - 1)
query := bson.M{"active": true}
if f, ok := ctx.Session.Values["filter"]; ok {
f.(*models.Filter).AddQuery(query)
}
//execute the query
var photos []*models.Photo
if err := ctx.C("photos").Find(query).Skip(skip).Limit(ITEMS_PER_PAGE).Sort("-_id").All(&photos); err != nil {
return internal_error(w, req, err.Error())
}
data := ""
var layer bytes.Buffer
for _, i := range rand.Perm(len(photos)) {
p := photos[i]
err := layerTemplate.Execute(&layer, map[string]interface{}{"p": p, "ctx": ctx})
if err != nil {
models.Log("layer template: ", err.Error())
}
data += fmt.Sprintf(`{"image":"%s","thumb":"%s","title":"%s","description":"%s","layer":"%s"},`,
models.ImageUrl(p.Id.Hex(), ""),
models.ImageUrl(p.Id.Hex(), "thumb"),
p.Title,
p.Description,
strings.Replace(layer.String(), "\n", "", -1),
)
layer.Reset()
}
data = strings.TrimRight(data, ",")
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, "["+data+"]")
return nil
}
作者:vichetu
项目:lov3lym
func Search(w http.ResponseWriter, req *http.Request, ctx *models.Context) (err error) {
var users []*models.User
q := req.FormValue("q")
query := bson.M{"$or": []bson.M{
{"firstname": bson.RegEx{q, "i"}},
{"lastname": bson.RegEx{q, "i"}},
},
}
if err := ctx.C(U).Find(query).Select(bson.M{"password": 0, "birthdate": 0}).Limit(10).All(&users); err != nil {
return err
}
response := ""
var text bytes.Buffer
for _, u := range users {
responseTemplate.Execute(&text, u)
response += fmt.Sprintf(`{"id":"%s","text":"%s", "name":"%s"},`, u.Id.Hex(), text.String(), u.FullName())
text.Reset()
}
response = strings.TrimRight(response, ",")
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, "["+response+"]")
return nil
}
作者:vichetu
项目:lov3lym
func Comment(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
http.Redirect(w, req, reverse("login"), http.StatusSeeOther)
return nil
}
if req.FormValue("csrf_token") != ctx.Session.Values["csrf_token"] {
return perform_status(w, req, http.StatusForbidden)
}
form := models.CommentForm
r := form.Load(req)
ctx.Data["result"] = r
if len(r.Errors) != 0 {
return CommentForm(w, req, ctx)
}
id := req.URL.Query().Get(":id")
if !bson.IsObjectIdHex(id) {
return perform_status(w, req, http.StatusForbidden)
}
c := &models.Comment{
Id: bson.NewObjectId(),
User: ctx.User.Id,
UserName: ctx.User.FullName(),
Avatar: ctx.User.Avatar,
Body: r.Values["body"],
}
col := P
if req.URL.Query().Get(":kind") == "c" {
col = C
}
if err := ctx.C(col).UpdateId(bson.ObjectIdHex(id), bson.M{"$push": bson.M{"comments": c}}); err != nil {
r.Errors["body"] = err
return CommentForm(w, req, ctx)
}
return CommentForm(w, req, ctx)
}
作者:vichetu
项目:lov3lym
func GetVote(w http.ResponseWriter, req *http.Request, ctx *models.Context) error {
if ctx.User == nil {
return perform_status(w, req, http.StatusForbidden)
}
photoId := req.URL.Query().Get(":photo")
if !bson.IsObjectIdHex(photoId) {
return perform_status(w, req, http.StatusForbidden)
}
contestId := req.URL.Query().Get(":contest")
if contestId != "" && !bson.IsObjectIdHex(contestId) {
return perform_status(w, req, http.StatusForbidden)
}
query := bson.M{"photo": bson.ObjectIdHex(photoId), "user": ctx.User.Id}
if contestId != "" {
query["contest"] = bson.ObjectIdHex(contestId)
}
vote := &models.Vote{}
ctx.C(V).Find(query).One(vote) // on error we still want the stars
hearts := ""
for i := 0; i < 5; i++ {
if float64(i) < vote.Score {
hearts += `<s class="voted">`
} else {
hearts += "<s>"
}
}
return AJAX("vote.html").Execute(w, map[string]interface{}{
"v": vote,
"photoId": photoId,
"contestId": contestId,
"hearts": SafeHtml(hearts),
"ctx": ctx,
})
}