some changes ;]]]]]

This commit is contained in:
Aleksander Cynarski 2020-01-15 20:40:53 +01:00
parent f24c030d8f
commit ab802985e9
12 changed files with 449 additions and 204 deletions

View File

@ -2,6 +2,7 @@ package controller
import ( import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"fmt"
"gitea-issue/giteaClient" "gitea-issue/giteaClient"
"gitea-issue/model" "gitea-issue/model"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -9,11 +10,11 @@ import (
"github.com/savaki/swag/swagger" "github.com/savaki/swag/swagger"
"net/http" "net/http"
"strconv" "strconv"
"fmt"
) )
func PostIssue(c *gin.Context) { func PostIssue(c *gin.Context) {
var issueProxy model.PostCreateIssueProxy var issueProxy model.PostCreateIssueProxy
if err := c.BindJSON(&issueProxy); err != nil { if err := c.BindJSON(&issueProxy); err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{ c.AsciiJSON(http.StatusBadRequest, gin.H{
"message": "CREATE_ISSUE_ERROR", "message": "CREATE_ISSUE_ERROR",
@ -22,6 +23,10 @@ func PostIssue(c *gin.Context) {
return return
} }
sudo := c.GetHeader("X-Sudo")
if (sudo != "") {
giteaClient.SudoUser(sudo)
}
giteaIssue, err := issueProxy.TransformToGiteaCreateIssueOption() giteaIssue, err := issueProxy.TransformToGiteaCreateIssueOption()
if err != nil { if err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{ c.AsciiJSON(http.StatusBadRequest, gin.H{
@ -39,7 +44,7 @@ func PostIssue(c *gin.Context) {
}) })
return return
} }
c.AsciiJSON(http.StatusOK, response) c.AsciiJSON(http.StatusOK, model.IssueTransformFromGitea(response))
} }
func PostIssueSwagger() (*swagger.Endpoint) { func PostIssueSwagger() (*swagger.Endpoint) {
@ -48,7 +53,7 @@ func PostIssueSwagger() (*swagger.Endpoint){
endpoint.Description("Post new issue"), endpoint.Description("Post new issue"),
endpoint.Body(model.PostCreateIssueProxy{}, "Issue object", true), endpoint.Body(model.PostCreateIssueProxy{}, "Issue object", true),
endpoint.Tags("issues"), endpoint.Tags("issues"),
endpoint.Response(http.StatusOK, gitea.Issue{}, "Gitea Issue list"), endpoint.Response(http.StatusOK, model.GetCreateIssueProxy{}, "Gitea Issue list"),
) )
} }
@ -70,6 +75,7 @@ func GetIssuesSwagger() (*swagger.Endpoint){
return endpoint.New("get", "/issues", "List project issues", return endpoint.New("get", "/issues", "List project issues",
endpoint.Handler(GetIssues), endpoint.Handler(GetIssues),
endpoint.Description("Get all issues"), endpoint.Description("Get all issues"),
endpoint.Security("token", "USER"),
endpoint.Tags("issues"), endpoint.Tags("issues"),
endpoint.Response(http.StatusOK, []model.GetCreateIssueProxy{}, "Gitea Issue list"), endpoint.Response(http.StatusOK, []model.GetCreateIssueProxy{}, "Gitea Issue list"),
) )
@ -85,13 +91,14 @@ func GetIssue(c *gin.Context) {
if err != nil { if err != nil {
c.AbortWithStatus(http.StatusNotFound) c.AbortWithStatus(http.StatusNotFound)
} }
c.AsciiJSON(http.StatusOK, issue) c.AsciiJSON(http.StatusOK, model.IssueTransformFromGitea(issue))
} }
func GetIssueSwagger() (*swagger.Endpoint) { func GetIssueSwagger() (*swagger.Endpoint) {
return endpoint.New("get", "/issue/:id", "Get one issue", return endpoint.New("get", "/issues/:id", "Get one issue",
endpoint.Handler(GetIssue), endpoint.Handler(GetIssue),
endpoint.Description("Get one issue"), endpoint.Description("Get one issue"),
endpoint.Security("token", "USER"),
endpoint.Tags("issues"), endpoint.Tags("issues"),
endpoint.Response(http.StatusOK, model.GetCreateIssueProxy{}, "Gitea Issue"), endpoint.Response(http.StatusOK, model.GetCreateIssueProxy{}, "Gitea Issue"),
) )
@ -104,6 +111,17 @@ func GetIssueComments(c *gin.Context) {
c.AsciiJSON(http.StatusNotFound, err.Error()) c.AsciiJSON(http.StatusNotFound, err.Error())
} }
issueComments, err := giteaClient.GetIssueComments(issueId) issueComments, err := giteaClient.GetIssueComments(issueId)
proxyComments := []model.GetCommentProxy{}
for _, comment := range issueComments {
proxyComments = append(proxyComments, model.CommentTransformFromGitea(comment))
}
if (err != nil) {
c.AbortWithStatus(http.StatusNotFound)
}
c.AsciiJSON(http.StatusOK, proxyComments)
if err != nil { if err != nil {
c.AbortWithStatus(http.StatusNotFound) c.AbortWithStatus(http.StatusNotFound)
} }
@ -111,10 +129,61 @@ func GetIssueComments(c *gin.Context) {
} }
func GetIssueCommentsSwagger() (*swagger.Endpoint) { func GetIssueCommentsSwagger() (*swagger.Endpoint) {
return endpoint.New("get", "/issue/:id/comments", "Get issue comments", return endpoint.New("get", "/issues/:id/comments", "Get issue comments",
endpoint.Handler(GetIssue), endpoint.Handler(GetIssueComments),
endpoint.Description("Get issue comments"), endpoint.Description("Get issue comments"),
endpoint.Security("token", "USER"),
endpoint.Tags("issues"), endpoint.Tags("issues"),
endpoint.Response(http.StatusOK, []gitea.Comment{}, "Gitea issue comments"), endpoint.Response(http.StatusOK, []gitea.Comment{}, "Gitea issue comments"),
) )
} }
func PostIssueComment(c *gin.Context) {
var commentProxy model.PostCommentProxy
if err := c.BindJSON(&commentProxy); err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{
"message": "CREATE_COMMENT_ERROR",
"error": err.Error(),
})
return
}
issueId, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
fmt.Println(fmt.Sprintf("ParseInt err: %+v", err))
c.AsciiJSON(http.StatusNotFound, err.Error())
}
giteaComment, err := commentProxy.TransformToGiteaComment()
if err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{
"message": "CREATE_COMMENT_ERROR",
"error": err.Error(),
})
return
}
sudo := c.GetHeader("X-Sudo")
if (sudo != "") {
giteaClient.SudoUser(sudo)
}
response, err := giteaClient.CreateComment(issueId, giteaComment)
if err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{
"message": "CREATE_ISSUE_ERROR",
"error": err.Error(),
})
return
}
c.AsciiJSON(http.StatusOK, model.CommentTransformFromGitea(response))
}
func PostIssueCommentSwagger() (*swagger.Endpoint) {
return endpoint.New("post", "/issues/:id/comments", "Create issue comment",
endpoint.Handler(PostIssueComment),
endpoint.Description("Add issue comment"),
endpoint.Body(model.PostCommentProxy{}, "Comment object", true),
endpoint.Security("token", "USER"),
endpoint.Tags("issues"),
endpoint.Response(http.StatusOK, model.GetCommentProxy{}, "Gitea issue comments"),
)
}

42
controller/user.go Normal file
View File

@ -0,0 +1,42 @@
package controller
import (
"code.gitea.io/sdk/gitea"
"gitea-issue/giteaClient"
"gitea-issue/model"
"github.com/gin-gonic/gin"
"github.com/savaki/swag/endpoint"
"github.com/savaki/swag/swagger"
"net/http"
)
func PostUser(c *gin.Context) {
var userProxy model.PostUserProxy
if err := c.BindJSON(&userProxy); err != nil {
c.AsciiJSON(http.StatusBadRequest, gin.H{
"message": "CREATE_USER_ERROR",
"error": err.Error(),
})
return
}
response, err := giteaClient.CreateUser(userProxy.TransformToGiteaUser())
if err != nil {
c.AsciiJSON(http.StatusUnprocessableEntity, gin.H{
"message": "CREATE_USER_ERROR",
"error": err.Error(),
})
return
}
c.AsciiJSON(http.StatusOK, response)
}
func PostUserSwagger() (*swagger.Endpoint) {
return endpoint.New("post", "/user", "Create user",
endpoint.Handler(PostUser),
endpoint.Description("Post new user"),
endpoint.Body(model.PostUserProxy{}, "User object", true),
endpoint.Tags("user"),
endpoint.Response(http.StatusOK, gitea.User{}, "Gitea User"),
)
}

View File

@ -25,6 +25,10 @@ func GetUserInfo() (*gitea.User, error){
return usr, nil return usr, nil
} }
func SudoUser(username string) {
giteaClient.SetSudo(username)
}
func GetServerInfo() (string, error) { func GetServerInfo() (string, error) {
ver, err := giteaClient.ServerVersion() ver, err := giteaClient.ServerVersion()
if (err != nil) { if (err != nil) {
@ -33,10 +37,20 @@ func GetServerInfo() (string, error) {
return ver, nil return ver, nil
} }
func CreateUser(user gitea.CreateUserOption) (*gitea.User, error) {
giteaUser, err := giteaClient.AdminCreateUser(user)
if (err != nil) {
fmt.Println(fmt.Sprintf("Gitea error: %+v", err.Error()))
return nil, err
}
return giteaUser, nil
}
func GetIssues() ([]*gitea.Issue, error) { func GetIssues() ([]*gitea.Issue, error) {
opt := gitea.ListIssueOption{ opt := gitea.ListIssueOption{
Page: 0, Page: 0,
State: "open", State: "closed",
} }
giteaIssues, err := giteaClient.ListRepoIssues(giteaOwner, giteaRepo, opt) giteaIssues, err := giteaClient.ListRepoIssues(giteaOwner, giteaRepo, opt)
if (err != nil) { if (err != nil) {
@ -81,3 +95,13 @@ func CreateIssue(issue gitea.CreateIssueOption) (*gitea.Issue, error){
} }
return giteaCreateIssue, nil return giteaCreateIssue, nil
} }
func CreateComment(id int64, option gitea.CreateIssueCommentOption) (*gitea.Comment, error) {
giteaComment, err := giteaClient.CreateIssueComment(giteaOwner, giteaRepo, id, option)
if (err != nil) {
fmt.Println(fmt.Sprintf("Gitea create comment error: %+v", err.Error()))
return nil, err
}
return giteaComment, nil
}

46
main.go
View File

@ -4,37 +4,27 @@ import (
"fmt" "fmt"
"gitea-issue/controller" "gitea-issue/controller"
"gitea-issue/giteaClient" "gitea-issue/giteaClient"
"gitea-issue/proxy"
"gitea-issue/security"
"github.com/caarlos0/env" "github.com/caarlos0/env"
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite" _ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/savaki/swag"
"github.com/savaki/swag/swagger"
ginSwagger "github.com/swaggo/gin-swagger" ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles" "github.com/swaggo/gin-swagger/swaggerFiles"
"net/http" "net/http"
"strconv" "strconv"
"github.com/savaki/swag"
"github.com/savaki/swag/swagger"
) )
var ( var (
db *gorm.DB
giteaConfig giteaClient.GiteaConfig giteaConfig giteaClient.GiteaConfig
proxyConfig ProxyConfig proxyConfig proxy.ProxyConfig
) )
type ProxyConfig struct {
ProjectOrigin string `env:"PROJECT_ORIGIN,required"`
}
func init() { func init() {
//open a db connection
var err error
db, err := gorm.Open("sqlite3", "./database.db")
if err != nil {
panic("failed to connect database")
}
if err := env.Parse(&giteaConfig); err != nil { if err := env.Parse(&giteaConfig); err != nil {
panic(fmt.Sprintf("ENV error: %+v", err.Error())) panic(fmt.Sprintf("ENV error: %+v", err.Error()))
} }
@ -43,7 +33,8 @@ func init() {
} }
giteaClient.SetUp(giteaConfig) giteaClient.SetUp(giteaConfig)
db.AutoMigrate(&userModel{}) proxy.SetUp(proxyConfig)
} }
func main() { func main() {
@ -53,6 +44,7 @@ func main() {
config.AllowOrigins = []string{proxyConfig.ProjectOrigin} config.AllowOrigins = []string{proxyConfig.ProjectOrigin}
router.Use(gin.Logger()) router.Use(gin.Logger())
router.Use(cors.New(config)) router.Use(cors.New(config))
router.Use(gin.Recovery())
proxyApi := swag.New( proxyApi := swag.New(
swag.Title("Gitea issues proxy"), swag.Title("Gitea issues proxy"),
@ -62,34 +54,31 @@ func main() {
swag.Tag("issues", "Gitea issues proxy endpoints"), swag.Tag("issues", "Gitea issues proxy endpoints"),
swag.Tag("labels", "Gites labels for issue"), swag.Tag("labels", "Gites labels for issue"),
swag.Endpoints( swag.Endpoints(
controller.PostUserSwagger(),
controller.PostIssueSwagger(), controller.PostIssueSwagger(),
controller.PostIssueCommentSwagger(),
controller.GetIssuesSwagger(), controller.GetIssuesSwagger(),
controller.GetIssueSwagger(), controller.GetIssueSwagger(),
controller.GetIssueCommentsSwagger(), controller.GetIssueCommentsSwagger(),
controller.GetLabelsSwagger()), controller.GetLabelsSwagger()),
) )
authorizedApi := router.Group("/", security.BearerToken())
proxyApi.Walk(func(path string, endpoint *swagger.Endpoint) { proxyApi.Walk(func(path string, endpoint *swagger.Endpoint) {
h := endpoint.Handler.(func(c *gin.Context)) h := endpoint.Handler.(func(c *gin.Context))
path = swag.ColonPath(path) path = swag.ColonPath(path)
router.Handle(endpoint.Method, path, h) authorizedApi.Handle(endpoint.Method, path, h)
}) })
router.GET("/swagger.json", gin.WrapH(proxyApi.Handler(true))) docs := router.Group("/")
docs.GET("/swagger.json", gin.WrapH(proxyApi.Handler(true)))
url := ginSwagger.URL("/swagger.json") url := ginSwagger.URL("/swagger.json")
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url)) docs.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
_ = router.Run() _ = router.Run()
} }
type (
userModel struct {
gorm.Model
Email string `json:"email"`
Token int `json:"token"`
}
)
func getIssues(c *gin.Context) { func getIssues(c *gin.Context) {
issues, err := giteaClient.GetIssues(); issues, err := giteaClient.GetIssues();
if (err != nil) { if (err != nil) {
@ -131,4 +120,3 @@ func getLabels(c *gin.Context) {
} }
c.AsciiJSON(http.StatusOK, labels) c.AsciiJSON(http.StatusOK, labels)
} }

35
model/commentProxy.go Normal file
View File

@ -0,0 +1,35 @@
package model
import (
"code.gitea.io/sdk/gitea"
"time"
)
type GetCommentProxy struct {
Id int64 `json:"id"`
Body string `json:"body"`
OriginalAuthor string `json:"original_author"`
CreatedAt time.Time `json:"created_at"`
}
type PostCommentProxy struct {
Body string `json:"body"`
}
func (c PostCommentProxy) TransformToGiteaComment() (gitea.CreateIssueCommentOption, error) {
giteaObject := gitea.CreateIssueCommentOption{
Body: c.Body,
}
return giteaObject, nil
}
func CommentTransformFromGitea(comment *gitea.Comment) (GetCommentProxy) {
giteaComment := GetCommentProxy{
Id: comment.ID,
Body: comment.Body,
OriginalAuthor: comment.OriginalAuthor,
CreatedAt: comment.Created,
}
return giteaComment
}

View File

@ -7,6 +7,7 @@ import (
) )
type GetCreateIssueProxy struct { type GetCreateIssueProxy struct {
Id int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Body string `json:"body"` Body string `json:"body"`
Labels []*gitea.Label `json:"labels"` Labels []*gitea.Label `json:"labels"`
@ -43,6 +44,7 @@ func (c PostCreateIssueProxy) TransformToGiteaCreateIssueOption() (gitea.CreateI
func IssueTransformFromGitea(issue *gitea.Issue) (GetCreateIssueProxy) { func IssueTransformFromGitea(issue *gitea.Issue) (GetCreateIssueProxy) {
giteaIssue := GetCreateIssueProxy{ giteaIssue := GetCreateIssueProxy{
Id: issue.Index,
Title: issue.Title, Title: issue.Title,
Body: issue.Body, Body: issue.Body,
Labels: issue.Labels, Labels: issue.Labels,

47
model/userProxy.go Normal file
View File

@ -0,0 +1,47 @@
package model
import (
"code.gitea.io/sdk/gitea"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
"math/rand"
"unicode"
)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456!@#$%")
func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
type PostUserProxy struct {
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
func isMn(r rune) bool {
return unicode.Is(unicode.Mn, r)
}
func (c PostUserProxy) TransformToGiteaUser() (gitea.CreateUserOption) {
t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
username, _, _ := transform.String(t, c.FirstName+c.LastName)
giteaObject := gitea.CreateUserOption{
SourceID: 0,
LoginName: c.Email,
Username: username,
FullName: c.FirstName + " " + c.LastName,
Email: c.Email,
Password: randSeq(12),
MustChangePassword: nil,
SendNotify: false,
}
return giteaObject
}

9
proxy/proxyClient.go Normal file
View File

@ -0,0 +1,9 @@
package proxy
var (
Bearer string
)
func SetUp(config ProxyConfig) {
Bearer = config.ProxyToken
}

6
proxy/proxyConfig.go Normal file
View File

@ -0,0 +1,6 @@
package proxy
type ProxyConfig struct {
ProjectOrigin string `env:"PROJECT_ORIGIN,required"`
ProxyToken string `env:"PROXY_TOKEN,required"`
}

View File

@ -0,0 +1,23 @@
package security
import (
"gitea-issue/proxy"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func BearerToken() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if (token == "") {
c.AbortWithStatus(http.StatusBadRequest)
}
var tokenArr []string
tokenArr = strings.Split(token, " ")
if (tokenArr[1] != proxy.Bearer) {
c.AbortWithStatus(http.StatusUnauthorized)
}
c.Next()
}
}