update api.go, auth.go, middleware.go

This commit is contained in:
redtea committed 2024-10-24 12:00:00 +03:00
1 parent be5630cbd9
commit 7493fd4885
3 files changed
+710

No files matched your search

+534
View File
@@ -0,0 +1,534 @@
package handler
import (
"esaccount"
"esaccount/pkg/util"
"fmt"
"io"
"net/http"
"os"
"slices"
"strconv"
"github.com/gin-gonic/gin"
)
// confidential godoc
// @Summary Get all confidential settings
// @Tags confidential
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200
// @Router /api/confidential/ [get]
func (h *Handler) getConfidential(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
c.JSON(http.StatusOK, account.Confidentials)
}
// confidential godoc
// @Summary Set confidential settings
// @Tags confidential
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param confidencial body string true "Confidencial settings"
// @Success 200 {object} esaccount.AuthorizedUser
// @Router /api/confidential/ [post]
func (h *Handler) setConfidential(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
var input esaccount.ConfidentialSettings
if err := c.BindJSON(&input); err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
for k, v := range input {
account.Confidentials[k] = v
}
account.Confidentials["picture_url"] = esaccount.All
h.repo.SaveAccount(account)
c.JSON(http.StatusOK, account)
}
// public godoc
// @Summary Get all public data of users
// @Tags confidential
// @Produce json
// @Param Authorization header string false "JWT Bearer token (authorization)"
// @Param id query int true "user id"
// @Success 200
// @Router /api/public/{id} [get]
func (h *Handler) getPublic(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account, err := h.repo.GetAccount(id)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
header := c.GetHeader(authorizationHeader)
allowedFields := []string{}
isFriend := false
if header != "" {
authorized, err := h.services.Authorization.Authorize(header)
if err == nil {
isFriend = (slices.Contains(account.Followers, authorized.Id) && slices.Contains(account.Follows, authorized.Id))
}
}
for k, v := range account.Confidentials {
if (v == esaccount.All) || (isFriend && (v == esaccount.Friends)) {
allowedFields = append(allowedFields, k)
}
}
res := map[string]any{}
user, _ := h.services.AuthorizeById(id)
// auth user
if slices.Contains(allowedFields, "username") {
res["username"] = user.Username
}
if slices.Contains(allowedFields, "first_name") {
res["first_name"] = user.FirstName
}
if slices.Contains(allowedFields, "last_name") {
res["last_name"] = user.LastName
}
res["picture_url"] = user.LastName
if slices.Contains(allowedFields, "email") {
res["email"] = user.LastName
}
// account
if slices.Contains(allowedFields, "description") {
res["description"] = account.Description
}
if slices.Contains(allowedFields, "date_of_birth") {
res["date_of_birth"] = account.DateOfBirth
}
if slices.Contains(allowedFields, "follows") {
res["follows"] = account.Follows
}
if slices.Contains(allowedFields, "followers") {
res["followers"] = account.Follows
}
c.JSON(http.StatusOK, res)
}
type accountResponce struct {
Description string `json:"description"`
DateOfBirth string `json:"date_of_birth"`
Follows []int64 `json:"follows"`
Followers []int64 `json:"followers"`
}
// account godoc
// @Summary Get account information
// @Tags account
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200 {object} handler.accountResponce
// @Router /api/account [get]
func (h *Handler) getAccount(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
c.JSON(http.StatusOK, accountResponce{
Description: account.Description,
DateOfBirth: account.DateOfBirth,
Follows: account.Follows,
Followers: account.Followers,
})
}
// picture godoc
// @Summary Get account information
// @Tags account
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param file formData file true "Picture"
// @Success 200
// @Router /api/account/picture [post]
func (h *Handler) picture(c *gin.Context) {
id, _ := c.Get(userCtx)
_, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
file, _, err := c.Request.FormFile("file")
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
defer file.Close()
os.Remove(fmt.Sprintf("./public/usercontent/picture/%d.png", id))
picFile, err := os.Create(fmt.Sprintf("./public/usercontent/picture/%d.png", id))
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
defer file.Close()
if _, err := io.Copy(picFile, file); err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
header, _ := c.Get(userHeader)
picUrl := fmt.Sprintf("https://account.easystartup.su/static/picture/%d.png", id)
_, err = h.services.AuthorizeAndUpdatePicture(header.(string), picUrl)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
c.JSON(http.StatusOK, fmt.Sprintf("{ \"url\": %s \"\" }", picUrl))
}
type accountInput struct {
Description string `json:"description"`
DateOfBirth string `json:"date_of_birth"`
}
// account godoc
// @Summary Set account information
// @Tags account
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param account body handler.accountInput true "account info"
// @Success 200 {object} handler.accountInput
// @Router /api/account [post]
func (h *Handler) editAccount(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
var input accountInput
if err := c.BindJSON(&input); err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account.Description = input.Description
account.DateOfBirth = input.DateOfBirth
h.repo.SaveAccount(account)
c.JSON(http.StatusOK, input)
}
// account godoc
// @Summary Get account information by id
// @Tags account
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param id path int true "account id"
// @Success 200 {object} handler.accountResponce
// @Router /api/account/{id} [get]
func (h *Handler) getAccountById(c *gin.Context) {
current, _ := c.Get(userCtx)
currentUser, err := h.services.AuthorizeById(current.(int64))
if (err != nil) || (currentUser.Access != "admin") {
util.NewErrorResponse(c, http.StatusForbidden, err.Error())
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account, err := h.repo.GetAccount(id)
if err != nil {
authorized, err := h.services.AuthorizeById(id)
if (err == nil) && (authorized.Id == id) {
account, err = h.repo.CreateAccount(id)
}
if err != nil {
util.NewErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}
}
c.JSON(http.StatusOK, accountResponce{
Description: account.Description,
DateOfBirth: account.DateOfBirth,
Follows: account.Follows,
Followers: account.Followers,
})
}
// account godoc
// @Summary Set account information by id
// @Tags account
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param account body handler.accountResponce true "account info"
// @Param id path int true "account id"
// @Success 200 {object} handler.accountResponce
// @Router /api/account/{id} [post]
func (h *Handler) editAccountById(c *gin.Context) {
current, _ := c.Get(userCtx)
currentUser, err := h.services.AuthorizeById(current.(int64))
if (err != nil) || (currentUser.Access != "admin") {
util.NewErrorResponse(c, http.StatusForbidden, err.Error())
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account, err := h.repo.GetAccount(id)
if err != nil {
authorized, err := h.services.AuthorizeById(id)
if (err == nil) && (authorized.Id == id) {
account, err = h.repo.CreateAccount(id)
}
if err != nil {
util.NewErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}
}
var input accountResponce
if err := c.BindJSON(&input); err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account.Description = input.Description
account.DateOfBirth = input.DateOfBirth
account.Followers = input.Followers
account.Follows = input.Follows
h.repo.SaveAccount(account)
c.JSON(http.StatusOK, input)
}
// account godoc
// @Summary Delete account by id
// @Tags account
// @Produce json
// @Param id path int true "id of user"
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200
// @Router /api/account/{id} [delete]
func (h *Handler) delete(c *gin.Context) {
current, _ := c.Get(userCtx)
currentUser, err := h.services.AuthorizeById(current.(int64))
if (err != nil) || (currentUser.Access != "admin") {
util.NewErrorResponse(c, http.StatusForbidden, err.Error())
return
}
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
_, err = h.repo.GetAccount(id)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
err = h.repo.DeleteAccount(id)
if err != nil {
util.NewErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, "{ \"status\": \"ok\" }")
}
// confidential godoc
// @Summary Get all confidential settings by id
// @Tags confidential
// @Produce json
// @Param id path int true "id of user"
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200
// @Router /api/confidential/{id} [get]
func (h *Handler) getConfidentialById(c *gin.Context) {
current, _ := c.Get(userCtx)
currentUser, err := h.services.AuthorizeById(current.(int64))
if (err != nil) || (currentUser.Access != "admin") {
util.NewErrorResponse(c, http.StatusForbidden, err.Error())
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account, err := h.repo.GetAccount(id)
if err != nil {
authorized, err := h.services.AuthorizeById(id)
if (err == nil) && (authorized.Id == id) {
account, err = h.repo.CreateAccount(id)
}
if err != nil {
util.NewErrorResponse(c, http.StatusInternalServerError, err.Error())
return
}
}
c.JSON(http.StatusOK, account.Confidentials)
}
// confidential godoc
// @Summary Set confidential settings by id
// @Tags confidential
// @Produce json
// @Param id path int true "id of user"
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Param confidencial body string true "Confidencial settings"
// @Success 200 {object} esaccount.AuthorizedUser
// @Router /api/confidential/{id} [post]
func (h *Handler) setConfidentialById(c *gin.Context) {
current, _ := c.Get(userCtx)
currentUser, err := h.services.AuthorizeById(current.(int64))
if (err != nil) || (currentUser.Access != "admin") {
util.NewErrorResponse(c, http.StatusForbidden, err.Error())
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
account, err := h.repo.GetAccount(id)
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
var input esaccount.ConfidentialSettings
if err := c.BindJSON(&input); err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
for k, v := range input {
account.Confidentials[k] = v
}
account.Confidentials["picture_url"] = esaccount.All
h.repo.SaveAccount(account)
c.JSON(http.StatusOK, account)
}
// following godoc
// @Summary Follow to user
// @Tags following
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200
// @Router /api/following/follow/{id} [put]
func (h *Handler) follow(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
id, err = strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
followed, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
if !slices.Contains(followed.Followers, account.Id) {
followed.Followers = append(followed.Followers, account.Id)
h.repo.SaveAccount(followed)
}
if !slices.Contains(account.Follows, followed.Id) {
account.Follows = append(followed.Follows, followed.Id)
h.repo.SaveAccount(account)
}
c.JSON(http.StatusOK, "{ \"status\": \"ok\" }")
}
// following godoc
// @Summary Unfollow user
// @Tags following
// @Produce json
// @Param Authorization header string true "JWT Bearer token (authorization)"
// @Success 200
// @Router /api/following/unfollow/{id} [put]
func (h *Handler) unfollow(c *gin.Context) {
id, _ := c.Get(userCtx)
account, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
id, err = strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
util.NewErrorResponse(c, http.StatusBadRequest, err.Error())
return
}
followed, err := h.repo.GetAccount(id.(int64))
if err != nil {
util.NewErrorResponse(c, http.StatusNotFound, err.Error())
return
}
followed.Followers = removeElement(followed.Followers, account.Id)
account.Follows = removeElement(followed.Follows, followed.Id)
h.repo.SaveAccount(followed)
h.repo.SaveAccount(account)
c.JSON(http.StatusOK, "{ \"status\": \"ok\" }")
}
func removeElement(slice []int64, value int64) []int64 {
// Find the index of the value
for i, v := range slice {
if v == value {
// Remove the element by slicing around it
return append(slice[:i], slice[i+1:]...)
}
}
// If the value is not found, return the original slice
return slice
}
+36
View File
@@ -0,0 +1,36 @@
package handler
import (
"esaccount/pkg/util"
"net/http"
"github.com/gin-gonic/gin"
)
const (
authorizationHeader = "Authorization"
userCtx = "UserInfo"
userHeader = "UserHeader"
)
func (h *Handler) userIdentity(c *gin.Context) {
header := c.GetHeader(authorizationHeader)
if header == "" {
util.NewErrorResponse(c, http.StatusUnauthorized, "empty auth header")
return
}
user, err := h.services.Authorization.Authorize(header)
if err != nil {
util.NewErrorResponse(c, http.StatusUnauthorized, err.Error())
}
_, err = h.repo.GetAccount(user.Id)
if err != nil {
h.repo.CreateAccount(user.Id)
}
c.Set(userCtx, user.Id)
c.Set(userHeader, header)
}