github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/profile.go (about)

     1  package routes
     2  
     3  import (
     4  	"database/sql"
     5  	"math"
     6  	"net/http"
     7  	"time"
     8  
     9  	c "github.com/Azareal/Gosora/common"
    10  	"github.com/Azareal/Gosora/common/phrases"
    11  	qgen "github.com/Azareal/Gosora/query_gen"
    12  )
    13  
    14  type ProfileStmts struct {
    15  	getReplies *sql.Stmt
    16  }
    17  
    18  var profileStmts ProfileStmts
    19  
    20  // TODO: Move these DbInits into some sort of abstraction
    21  func init() {
    22  	c.DbInits.Add(func(acc *qgen.Accumulator) error {
    23  		profileStmts = ProfileStmts{
    24  			getReplies: acc.SimpleLeftJoin("users_replies", "users", "users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group", "users_replies.createdBy=users.uid", "users_replies.uid=?", "", ""),
    25  		}
    26  		return acc.FirstError()
    27  	})
    28  }
    29  
    30  // TODO: Remove the View part of the name?
    31  func ViewProfile(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError {
    32  	var reCreatedAt time.Time
    33  	var reContent, reCreatedByName, reAvatar string
    34  	var rid, reCreatedBy, reLastEdit, reLastEditBy, reGroup int
    35  	var reList []*c.ReplyUser
    36  
    37  	// TODO: Do a 301 if it's the wrong username? Do a canonical too?
    38  	_, pid, err := ParseSEOURL(r.URL.Path[len("/user/"):])
    39  	if err != nil {
    40  		return c.SimpleError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, h)
    41  	}
    42  	if pid == 0 {
    43  		return c.NotFound(w, r, h)
    44  	}
    45  
    46  	var puser *c.User
    47  	if pid == user.ID {
    48  		user.IsMod = true
    49  		puser = user
    50  	} else {
    51  		// Fetch the user data
    52  		// TODO: Add a shared function for checking for ErrNoRows and internal erroring if it's not that case?
    53  		puser, err = c.Users.Get(pid)
    54  		if err == sql.ErrNoRows {
    55  			return c.NotFound(w, r, h)
    56  		} else if err != nil {
    57  			return c.InternalError(err, w, r)
    58  		}
    59  	}
    60  	h.Title = phrases.GetTitlePhrasef("profile", puser.Name)
    61  	h.Path = c.BuildProfileURL(c.NameToSlug(puser.Name), puser.ID)
    62  	// TODO: Preload this?
    63  	h.AddSheet(h.Theme.Name + "/profile.css")
    64  	if user.Loggedin {
    65  		h.AddScriptAsync("profile_member.js")
    66  	}
    67  
    68  	// Get the replies..
    69  	rows, err := profileStmts.getReplies.Query(puser.ID)
    70  	if err != nil {
    71  		return c.InternalError(err, w, r)
    72  	}
    73  	defer rows.Close()
    74  
    75  	for rows.Next() {
    76  		err := rows.Scan(&rid, &reContent, &reCreatedBy, &reCreatedAt, &reLastEdit, &reLastEditBy, &reAvatar, &reCreatedByName, &reGroup)
    77  		if err != nil {
    78  			return c.InternalError(err, w, r)
    79  		}
    80  
    81  		reLiked := false
    82  		reLikeCount := 0
    83  		ru := &c.ReplyUser{Reply: c.Reply{rid, puser.ID, reContent, reCreatedBy /*, reGroup*/, reCreatedAt, reLastEdit, reLastEditBy, 0, "", reLiked, reLikeCount, 0, ""}, ContentHtml: c.ParseMessage(reContent, 0, "", user.ParseSettings, user), CreatedByName: reCreatedByName, Avatar: reAvatar, Group: reGroup, Level: 0}
    84  		_, err = ru.Init(user)
    85  		if err != nil {
    86  			return c.InternalError(err, w, r)
    87  		}
    88  		if puser.ID == ru.CreatedBy {
    89  			ru.Tag = phrases.GetTmplPhrase("profile.owner_tag")
    90  		}
    91  
    92  		// TODO: Add a hook here
    93  		reList = append(reList, ru)
    94  	}
    95  	if err := rows.Err(); err != nil {
    96  		return c.InternalError(err, w, r)
    97  	}
    98  
    99  	// Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score
   100  	prevScore := c.GetLevelScore(puser.Level)
   101  	score := puser.Score
   102  	//score = 23
   103  	currentScore := score - prevScore
   104  	nextScore := c.GetLevelScore(puser.Level+1) - prevScore
   105  	perc := int(math.Floor((float64(currentScore) / float64(nextScore)) * 100))
   106  	var blocked, blockedInv bool
   107  	if user.Loggedin {
   108  		blocked, err = c.UserBlocks.IsBlockedBy(user.ID, puser.ID)
   109  		if err != nil {
   110  			return c.InternalError(err, w, r)
   111  		}
   112  		blockedInv, err = c.UserBlocks.IsBlockedBy(puser.ID, user.ID)
   113  		if err != nil {
   114  			return c.InternalError(err, w, r)
   115  		}
   116  	}
   117  
   118  	canMessage := (!blockedInv && user.Perms.UseConvos) || (!blockedInv && puser.IsSuperMod && user.Perms.UseConvosOnlyWithMod) || user.IsSuperMod
   119  	canComment := !blockedInv && user.Perms.CreateProfileReply
   120  	showComments := c.PrivacyCommentsShow(puser, user)
   121  	if !showComments {
   122  		canComment = false
   123  	}
   124  	if !c.PrivacyAllowMessage(puser, user) {
   125  		canMessage = false
   126  	}
   127  
   128  	ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, perc, blocked, canMessage, canComment, showComments}
   129  	return renderTemplate("profile", w, r, h, ppage)
   130  }