home
login
Self-hosted software development platform with Git VCS.
summary browse commits releases contributors
e2e9c3c529f9e6d27305c9aa4ecbf779d43fe68f
7 months ago
Nirmal Almara
Implement idiomatic folder structure based on Golang suggestions
@@ -9,14 +9,13 @@ import (

"strings"

"syscall"

- errorhandler "sorcia/error"

- "sorcia/handler"

- "sorcia/model"

- "sorcia/setting"

+ "sorcia/internal"

+ "sorcia/models"

+ "sorcia/pkg"

)

// UserMod ...

-func UserMod(conf *setting.BaseStruct) {

+func UserMod(conf *pkg.BaseStruct) {

// Open postgres database

db := conf.DBConn

defer db.Close()

@@ -27,7 +26,7 @@ func UserMod(conf *setting.BaseStruct) {

fmt.Println("[1] Reset username of a user\n[2] Reset password of a user\n[3] Delete user\n[4] Delete repository")

fmt.Print("Enter your option [1/2/3/4]: ")

optionInput, err := reader.ReadString('\n')

- errorhandler.CheckError("User mod", err)

+ pkg.CheckError("User mod", err)

option := strings.TrimSpace(optionInput)

@@ -56,20 +55,20 @@ func resetUserName(db *sql.DB) {

for {

fmt.Println("Enter the current username of a user")

usernameInput, err := reader.ReadString('\n')

- errorhandler.CheckError("Usermod: Reset username of a user", err)

+ pkg.CheckError("Usermod: Reset username of a user", err)

username := strings.TrimSpace(usernameInput)

- userID := model.GetUserIDFromUsername(db, username)

+ userID := models.GetUserIDFromUsername(db, username)

if userID > 0 {

fmt.Println("Enter the new username")

newUsernameInput, err := reader.ReadString('\n')

- errorhandler.CheckError("Usermod: new username error", err)

+ pkg.CheckError("Usermod: new username error", err)

newUsername := strings.TrimSpace(newUsernameInput)

- model.ResetUsernameByUserID(db, newUsername, userID)

+ models.ResetUsernameByUserID(db, newUsername, userID)

fmt.Println("Username has been successfully changed.")

return

}

@@ -83,30 +82,30 @@ func resetUserPassword(db *sql.DB) {

for {

fmt.Println("Enter the username")

usernameInput, err := reader.ReadString('\n')

- errorhandler.CheckError("Usermod: Reset password of a user - enter username", err)

+ pkg.CheckError("Usermod: Reset password of a user - enter username", err)

username := strings.TrimSpace(usernameInput)

- userID := model.GetUserIDFromUsername(db, username)

+ userID := models.GetUserIDFromUsername(db, username)

if userID > 0 {

newPassword := getPassword("Enter the password")

// Generate password hash using bcrypt

- passwordHash, err := handler.HashPassword(newPassword)

- errorhandler.CheckError("Error on usermod hash password", err)

+ passwordHash, err := internal.HashPassword(newPassword)

+ pkg.CheckError("Error on usermod hash password", err)

// Generate JWT token using the hash password above

- token, err := handler.GenerateJWTToken(passwordHash)

- errorhandler.CheckError("Error on usermod generate jwt token", err)

+ token, err := internal.GenerateJWTToken(passwordHash)

+ pkg.CheckError("Error on usermod generate jwt token", err)

- rsp := model.ResetUserPasswordbyUsernameStruct{

+ rsp := models.ResetUserPasswordbyUsernameStruct{

Username: username,

PasswordHash: passwordHash,

JwtToken: token,

}

- model.ResetUserPasswordbyUsername(db, rsp)

+ models.ResetUserPasswordbyUsername(db, rsp)

fmt.Println("Password has been successfully changed.")

return

@@ -118,7 +117,7 @@ func resetUserPassword(db *sql.DB) {

func getPassword(prompt string) string {

fmt.Println(prompt)

- // Common settings and variables for both stty calls.

+ // Common internals and variables for both stty calls.

attrs := syscall.ProcAttr{

Dir: "",

Env: []string{},

@@ -166,51 +165,51 @@ func getPassword(prompt string) string {

return strings.TrimSpace(text)

}

-func deleteUser(db *sql.DB, conf *setting.BaseStruct) {

+func deleteUser(db *sql.DB, conf *pkg.BaseStruct) {

reader := bufio.NewReader(os.Stdin)

for {

fmt.Println("Enter the username (this will delete all the repositories that this user has ownership of)")

usernameInput, err := reader.ReadString('\n')

- errorhandler.CheckError("Usermod: Reset username of a user", err)

+ pkg.CheckError("Usermod: Reset username of a user", err)

username := strings.TrimSpace(usernameInput)

- userID := model.GetUserIDFromUsername(db, username)

+ userID := models.GetUserIDFromUsername(db, username)

if userID > 0 {

- isAdmin := model.CheckifUserIsAnAdmin(db, userID)

+ isAdmin := models.CheckifUserIsAnAdmin(db, userID)

if isAdmin {

fmt.Println("You cannot delete an admin user of Sorcia.")

return

}

- rds := model.GetReposFromUserID(db, userID)

+ rds := models.GetReposFromUserID(db, userID)

for _, repo := range rds.Repositories {

refsPattern := filepath.Join(conf.Paths.RefsPath, repo.Name+"*")

files, err := filepath.Glob(refsPattern)

- errorhandler.CheckError("Error on post repo meta delete filepath.Glob", err)

+ pkg.CheckError("Error on post repo meta delete filepath.Glob", err)

for _, f := range files {

err := os.Remove(f)

- errorhandler.CheckError("Error on removing ref files", err)

+ pkg.CheckError("Error on removing ref files", err)

}

repoDir := filepath.Join(conf.Paths.RepoPath, repo.Name+".git")

err = os.RemoveAll(repoDir)

- errorhandler.CheckError("Error on removing repository directory", err)

+ pkg.CheckError("Error on removing repository directory", err)

}

- rmi := model.GetRepoMemberIDFromUserID(db, userID)

+ rmi := models.GetRepoMemberIDFromUserID(db, userID)

for _, m := range rmi {

- model.DeleteRepoMemberByID(db, m)

+ models.DeleteRepoMemberByID(db, m)

}

- model.DeleteUserbyUsername(db, username)

+ models.DeleteUserbyUsername(db, username)

fmt.Println("Username has been successfully deleted.")

return

@@ -219,31 +218,31 @@ func deleteUser(db *sql.DB, conf *setting.BaseStruct) {

}

}

-func deleteRepository(db *sql.DB, conf *setting.BaseStruct) {

+func deleteRepository(db *sql.DB, conf *pkg.BaseStruct) {

reader := bufio.NewReader(os.Stdin)

for {

fmt.Println("Enter the repository name")

reponameInput, err := reader.ReadString('\n')

- errorhandler.CheckError("Usermod: Delete repository", err)

+ pkg.CheckError("Usermod: Delete repository", err)

reponame := strings.TrimSpace(reponameInput)

- if model.CheckRepoExists(db, reponame) {

- model.DeleteRepobyReponame(db, reponame)

+ if models.CheckRepoExists(db, reponame) {

+ models.DeleteRepobyReponame(db, reponame)

refsPattern := filepath.Join(conf.Paths.RefsPath, reponame+"*")

files, err := filepath.Glob(refsPattern)

- errorhandler.CheckError("Error on post repo meta delete filepath.Glob", err)

+ pkg.CheckError("Error on post repo meta delete filepath.Glob", err)

for _, f := range files {

err := os.Remove(f)

- errorhandler.CheckError("Error on removing ref files", err)

+ pkg.CheckError("Error on removing ref files", err)

}

repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

err = os.RemoveAll(repoDir)

- errorhandler.CheckError("Error on removing repository directory", err)

+ pkg.CheckError("Error on removing repository directory", err)

fmt.Println("Repository has been successfully deleted.")

return

@@ -1,153 +1,42 @@

package cmd

import (

- "database/sql"

"fmt"

- "html/template"

"log"

"net/http"

- "path"

- "path/filepath"

- errorhandler "sorcia/error"

- "sorcia/handler"

- "sorcia/middleware"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

+ "sorcia/internal"

+ "sorcia/models"

+ "sorcia/pkg"

+ "sorcia/routes"

"github.com/gorilla/handlers"

"github.com/gorilla/mux"

- "github.com/gorilla/schema"

)

-var decoder = schema.NewDecoder()

-

// RunWeb ...

-func RunWeb(conf *setting.BaseStruct) {

+func RunWeb(conf *pkg.BaseStruct) {

// Create necessary directories

- util.CreateDir(conf.Paths.RepoPath)

- util.CreateDir(conf.Paths.RefsPath)

- util.CreateDir(conf.Paths.UploadAssetPath)

- util.CreateSSHDirAndGenerateKey(conf.Paths.SSHPath)

-

- // Mux initiate

- m := mux.NewRouter()

+ pkg.CreateDir(conf.Paths.RepoPath)

+ pkg.CreateDir(conf.Paths.RefsPath)

+ pkg.CreateDir(conf.Paths.UploadAssetPath)

+ pkg.CreateSSHDirAndGenerateKey(conf.Paths.SSHPath)

// Open postgres database

db := conf.DBConn

defer db.Close()

- model.CreateAccount(db)

- model.CreateSiteSettings(db)

- model.CreateSSHPubKey(db)

- model.CreateRepo(db)

- model.CreateRepoMembers(db)

-

- go handler.RunSSH(conf, db)

+ models.CreateAccount(db)

+ models.CreateSiteSettings(db)

+ models.CreateSSHPubKey(db)

+ models.CreateRepo(db)

+ models.CreateRepoMembers(db)

- m.Use(middleware.Middleware)

+ go internal.RunSSH(conf, db)

- // Web handlers

- m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

- GetHome(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {

- handler.GetLogin(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {

- handler.PostLogin(w, r, db, conf, decoder)

- }).Methods("POST")

- m.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {

- handler.GetLogout(w, r)

- }).Methods("GET")

- m.HandleFunc("/create-repo", func(w http.ResponseWriter, r *http.Request) {

- handler.GetCreateRepo(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/create-repo", func(w http.ResponseWriter, r *http.Request) {

- handler.PostCreateRepo(w, r, db, decoder, conf)

- }).Methods("POST")

- m.HandleFunc("/meta", func(w http.ResponseWriter, r *http.Request) {

- handler.GetMeta(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/meta/password", func(w http.ResponseWriter, r *http.Request) {

- handler.MetaPostPassword(w, r, db, decoder)

- }).Methods("POST")

- m.HandleFunc("/meta/site", func(w http.ResponseWriter, r *http.Request) {

- handler.MetaPostSiteSettings(w, r, db, conf)

- }).Methods("POST")

- m.HandleFunc("/meta/keys", func(w http.ResponseWriter, r *http.Request) {

- handler.GetMetaKeys(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/meta/keys/delete/{keyID}", func(w http.ResponseWriter, r *http.Request) {

- handler.DeleteMetaKey(w, r, db)

- }).Methods("GET")

- m.HandleFunc("/meta/keys", func(w http.ResponseWriter, r *http.Request) {

- handler.PostAuthKey(w, r, db, conf, decoder)

- }).Methods("POST")

- m.HandleFunc("/meta/users", func(w http.ResponseWriter, r *http.Request) {

- handler.GetMetaUsers(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/meta/users", func(w http.ResponseWriter, r *http.Request) {

- handler.PostUser(w, r, db, conf, decoder)

- }).Methods("POST")

- m.HandleFunc("/meta/user/revoke-access/{username}", func(w http.ResponseWriter, r *http.Request) {

- handler.RevokeCreateRepoAccess(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/meta/user/add-access/{username}", func(w http.ResponseWriter, r *http.Request) {

- handler.AddCreateRepoAccess(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepo(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/meta", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoMeta(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/meta", func(w http.ResponseWriter, r *http.Request) {

- handler.PostRepoMeta(w, r, db, conf, decoder)

- }).Methods("POST")

- m.HandleFunc("/r/{reponame}/meta/user", func(w http.ResponseWriter, r *http.Request) {

- handler.PostRepoMetaUser(w, r, db, conf, decoder)

- }).Methods("POST")

- m.HandleFunc("/r/{reponame}/meta/user/remove/{username}", func(w http.ResponseWriter, r *http.Request) {

- handler.RemoveRepoMetaUser(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/meta/delete", func(w http.ResponseWriter, r *http.Request) {

- handler.PostRepoMetaDelete(w, r, db, conf)

- }).Methods("POST")

- m.HandleFunc("/r/{reponame}/tree/{branch}", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoTree(w, r, db, conf)

- }).Methods("GET")

- m.PathPrefix("/r/{reponame}/tree/{branchorhash}/{path:[[\\d\\w-_\\.]+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoTreePath(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/log/{branch}", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoLog(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/commit/{branch}/{hash}", func(w http.ResponseWriter, r *http.Request) {

- handler.GetCommitDetail(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/refs", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoRefs(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/r/{reponame}/contributors", func(w http.ResponseWriter, r *http.Request) {

- handler.GetRepoContributors(w, r, db, conf)

- }).Methods("GET")

- m.HandleFunc("/dl/{file}", func(w http.ResponseWriter, r *http.Request) {

- handler.ServeRefFile(w, r, conf)

- }).Methods("GET")

- m.PathPrefix("/r/{reponame[\\d\\w-_\\.]+\\.git$}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

- handler.GitviaHTTP(w, r, db, conf)

- }).Methods("GET", "POST")

-

- staticDir := filepath.Join(conf.Paths.ProjectRoot, "public")

- staticFileHandler := http.StripPrefix("/public/", http.FileServer(http.Dir(staticDir)))

- // The "PathPrefix" method acts as a matcher, and matches all routes starting

- // with "/public/", instead of the absolute route itself

- m.PathPrefix("/public/").Handler(staticFileHandler).Methods("GET")

-

- uploadFileHandler := http.StripPrefix("/uploads/", http.FileServer(http.Dir(conf.Paths.UploadAssetPath)))

- m.PathPrefix("/uploads/").Handler(uploadFileHandler).Methods("GET")

+ // Mux initiate

+ m := mux.NewRouter()

+ m = routes.Router(m, db, conf)

http.Handle("/", m)

@@ -156,154 +45,3 @@ func RunWeb(conf *setting.BaseStruct) {

log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", conf.Server.HTTPPort), handlers.CORS(handlers.AllowedOrigins(allowedOrigins), handlers.AllowedMethods(allowedMethods))(m)))

}

-

-// IndexPageResponse struct

-type IndexPageResponse struct {

- IsLoggedIn bool

- ShowLoginMenu bool

- HeaderActiveMenu string

- SorciaVersion string

- CanCreateRepo bool

- Repos GetReposStruct

- SiteSettings util.SiteSettings

-}

-

-// GetReposStruct struct

-type GetReposStruct struct {

- Repositories []RepoDetailStruct

-}

-

-// ReposDetailStruct struct

-type RepoDetailStruct struct {

- ID int

- Name string

- Description string

- IsPrivate bool

- Permission string

-}

-

-// GetHome ...

-func GetHome(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- repos := model.GetAllPublicRepos(db)

- var grs GetReposStruct

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- for _, repo := range repos.Repositories {

- rd := RepoDetailStruct{

- ID: repo.ID,

- Name: repo.Name,

- Description: repo.Description,

- IsPrivate: repo.IsPrivate,

- Permission: repo.Permission,

- }

- if model.CheckRepoMemberExistFromUserIDAndRepoID(db, userID, repo.ID) {

- rd.Permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, userID, repo.ID)

- } else if model.CheckRepoOwnerFromUserIDAndReponame(db, userID, repo.Name) {

- rd.Permission = "read/write"

- }

-

- grs.Repositories = append(grs.Repositories, rd)

- }

-

- var reposAsMember model.GetReposStruct

- var repoAsMember model.RepoDetailStruct

-

- reposAsMember = model.GetReposFromUserID(db, userID)

-

- repoIDs := model.GetRepoIDsOnRepoMembersUsingUserID(db, userID)

- for _, repoID := range repoIDs {

- repoAsMember = model.GetRepoFromRepoID(db, repoID)

- reposAsMember.Repositories = append(reposAsMember.Repositories, repoAsMember)

- }

-

- for _, repo := range reposAsMember.Repositories {

- repoExistCount := 0

- for _, publicRepo := range grs.Repositories {

- if publicRepo.Name == repo.Name {

- repoExistCount = 1

- }

- }

-

- if repoExistCount == 0 {

- rd := RepoDetailStruct{

- ID: repo.ID,

- Name: repo.Name,

- Description: repo.Description,

- IsPrivate: repo.IsPrivate,

- Permission: repo.Permission,

- }

- if model.CheckRepoMemberExistFromUserIDAndRepoID(db, userID, repo.ID) {

- rd.Permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, userID, repo.ID)

- } else if model.CheckRepoOwnerFromUserIDAndReponame(db, userID, repo.Name) {

- rd.Permission = "read/write"

- }

-

- grs.Repositories = append(grs.Repositories, rd)

- }

- }

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- indexPage := path.Join("./templates", "index.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, indexPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := IndexPageResponse{

- IsLoggedIn: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- CanCreateRepo: model.CheckifUserCanCreateRepo(db, userID),

- Repos: grs,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- } else {

- if !model.CheckIfFirstUserExists(db) {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- for _, repo := range repos.Repositories {

- rd := RepoDetailStruct{

- ID: repo.ID,

- Name: repo.Name,

- Description: repo.Description,

- IsPrivate: repo.IsPrivate,

- Permission: repo.Permission,

- }

- grs.Repositories = append(grs.Repositories, rd)

- }

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- indexPage := path.Join("./templates", "index.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, indexPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := IndexPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: true,

- SorciaVersion: conf.Version,

- Repos: grs,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- }

-}

@@ -1,302 +0,0 @@

-package handler

-

-import (

- "database/sql"

- "encoding/json"

- "fmt"

- "html/template"

- "net/http"

- "path"

- "strings"

- "time"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

-

- "github.com/dgrijalva/jwt-go"

- "github.com/gorilla/schema"

- "golang.org/x/crypto/bcrypt"

-)

-

-// HashPassword ...

-func HashPassword(password string) (string, error) {

- bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)

- return string(bytes), err

-}

-

-// CheckPasswordHash ...

-func CheckPasswordHash(password, hash string) bool {

- err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))

- return err == nil

-}

-

-// GenerateJWTToken ...

-func GenerateJWTToken(passwordHash string) (string, error) {

- token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{})

- tokenString, err := token.SignedString([]byte(passwordHash))

- return tokenString, err

-}

-

-func validateJWTToken(tokenString string, passwordHash string) (bool, error) {

- token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

- if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {

- return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])

- }

-

- return []byte(passwordHash), nil

- })

-

- return token.Valid, err

-}

-

-// LoginPageResponse struct

-type LoginPageResponse struct {

- IsLoggedIn bool

- ShowLoginMenu bool

- HeaderActiveMenu string

- SorciaVersion string

- IsShowSignUp bool

- LoginErrMessage string

- RegisterErrMessage string

- SiteSettings util.SiteSettings

-}

-

-// GetLogin ...

-func GetLogin(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- http.Redirect(w, r, "/", http.StatusFound)

- } else {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- loginPage := path.Join("./templates", "login.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, loginPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- IsShowSignUp: !model.CheckIfFirstUserExists(db),

- LoginErrMessage: "",

- RegisterErrMessage: "",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- }

-}

-

-// LoginRequest struct

-type LoginRequest struct {

- Username string `schema:"username"`

- Password string `schema:"password"`

-}

-

-// PostLogin ...

-func PostLogin(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- // NOTE: Invoke ParseForm or ParseMultipartForm before reading form values

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on post login json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- isRegisterForm := r.FormValue("register")

- if isRegisterForm == "1" {

- postRegister(w, r, db, conf, decoder)

- return

- }

-

- var loginRequest = &LoginRequest{}

- err := decoder.Decode(loginRequest, r.PostForm)

- errorhandler.CheckError("Error on post login decoder", err)

-

- sphjwt := model.SelectPasswordHashAndJWTTokenStruct{

- Username: loginRequest.Username,

- }

- sphjwtr := model.SelectPasswordHashAndJWTToken(db, sphjwt)

-

- if isPasswordValid := CheckPasswordHash(loginRequest.Password, sphjwtr.PasswordHash); isPasswordValid == true {

- isTokenValid, err := validateJWTToken(sphjwtr.Token, sphjwtr.PasswordHash)

- errorhandler.CheckError("Error on validating jwt token", err)

-

- if isTokenValid == true {

- // Set cookie

- now := time.Now()

- duration := now.Add(365 * 24 * time.Hour).Sub(now)

- maxAge := int(duration.Seconds())

- c := &http.Cookie{Name: "sorcia-token", Value: sphjwtr.Token, Path: "/", Domain: strings.Split(r.Host, ":")[0], MaxAge: maxAge}

- http.SetCookie(w, c)

-

- http.Redirect(w, r, "/", http.StatusFound)

- } else {

- invalidLoginCredentials(w, r, db, conf)

- }

- } else {

- invalidLoginCredentials(w, r, db, conf)

- }

-}

-

-func invalidLoginCredentials(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- loginPage := path.Join("./templates", "login.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, loginPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- LoginErrMessage: "Your username or password is incorrect.",

- RegisterErrMessage: "",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

-}

-

-// RegisterRequest struct

-type RegisterRequest struct {

- Username string `schema:"username"`

- Password string `schema:"password"`

- Register string `schema:"register"`

-}

-

-// PostRegister ...

-func postRegister(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- // NOTE: Invoke ParseForm or ParseMultipartForm before reading form values

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on post register json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- var registerRequest = &RegisterRequest{}

- err := decoder.Decode(registerRequest, r.PostForm)

- errorhandler.CheckError("Error on post register decoder", err)

-

- // Generate password hash using bcrypt

- passwordHash, err := HashPassword(registerRequest.Password)

- errorhandler.CheckError("Error on post register hash password", err)

-

- // Generate JWT token using the hash password above

- token, err := GenerateJWTToken(passwordHash)

- errorhandler.CheckError("Error on post register generate jwt token", err)

-

- s := registerRequest.Username

-

- if len(s) > 39 || len(s) < 1 {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- loginPage := path.Join("./templates", "login.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, loginPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- IsShowSignUp: !model.CheckIfFirstUserExists(db),

- LoginErrMessage: "",

- RegisterErrMessage: "Username is too long (maximum is 39 characters).",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- } else if strings.HasPrefix(s, "-") || strings.Contains(s, "--") || strings.HasSuffix(s, "-") || !util.IsAlnumOrHyphen(s) {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- loginPage := path.Join("./templates", "login.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, loginPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- IsShowSignUp: !model.CheckIfFirstUserExists(db),

- LoginErrMessage: "",

- RegisterErrMessage: "Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

-

- rr := model.CreateAccountStruct{

- Username: registerRequest.Username,

- PasswordHash: passwordHash,

- Token: token,

- CanCreateRepo: 1,

- IsAdmin: 1,

- }

-

- model.InsertAccount(db, rr)

-

- // Set cookie

- now := time.Now()

- duration := now.Add(365 * 24 * time.Hour).Sub(now)

- maxAge := int(duration.Seconds())

- c := &http.Cookie{Name: "sorcia-token", Value: token, Path: "/", Domain: strings.Split(r.Host, ":")[0], MaxAge: maxAge}

- http.SetCookie(w, c)

-

- http.Redirect(w, r, "/", http.StatusFound)

-}

-

-// GetLogout ...

-func GetLogout(w http.ResponseWriter, r *http.Request) {

- // Clear the cookie

- c := &http.Cookie{Name: "sorcia-token", Value: "", Path: "/", Domain: strings.Split(r.Host, ":")[0], MaxAge: -1}

- http.SetCookie(w, c)

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

@@ -1,362 +0,0 @@

-package handler

-

-import (

- "bytes"

- "compress/gzip"

- "database/sql"

- "fmt"

- "net/http"

- "os"

- "os/exec"

- "path"

- "path/filepath"

- "regexp"

- "strconv"

- "strings"

- "time"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

-)

-

-type gitHandler struct {

- w http.ResponseWriter

- r *http.Request

- rpc string

- dir string

- file string

- reponame string

- repoGitName string

- repoPath string

- refsPath string

- db *sql.DB

-}

-

-func (gh *gitHandler) basicAuth(realm string) (string, string, bool) {

- user, pass, ok := gh.r.BasicAuth()

-

- return user, pass, ok

-}

-

-func (gh *gitHandler) processRepoAccess(rpc, realm string) bool {

- isRepoPrivate := model.GetRepoType(gh.db, gh.reponame)

-

- if isRepoPrivate && rpc == "upload-pack" {

- username, password, ok := gh.basicAuth(realm)

- if !ok {

- return false

- }

-

- sphjwt := model.SelectPasswordHashAndJWTTokenStruct{

- Username: username,

- }

- sphjwtr := model.SelectPasswordHashAndJWTToken(gh.db, sphjwt)

-

- isPasswordValid := CheckPasswordHash(password, sphjwtr.PasswordHash)

-

- if isPasswordValid {

- userID := model.GetUserIDFromUsername(gh.db, username)

- repoID := model.GetRepoIDFromReponame(gh.db, gh.reponame)

- if model.CheckRepoOwnerFromUserIDAndReponame(gh.db, userID, gh.reponame) {

- return true

- } else if model.CheckRepoMemberExistFromUserIDAndRepoID(gh.db, userID, repoID) {

- permission := model.GetRepoMemberPermissionFromUserIDAndRepoID(gh.db, userID, repoID)

- if permission == "read" || permission == "read/write" {

- return true

- }

- }

- } else {

- return false

- }

- } else if rpc == "upload-pack" {

- return true

- } else if rpc == "receive-pack" {

- username, password, ok := gh.basicAuth(realm)

- if !ok {

- return false

- }

-

- sphjwt := model.SelectPasswordHashAndJWTTokenStruct{

- Username: username,

- }

- sphjwtr := model.SelectPasswordHashAndJWTToken(gh.db, sphjwt)

-

- isPasswordValid := CheckPasswordHash(password, sphjwtr.PasswordHash)

-

- if isPasswordValid {

- userID := model.GetUserIDFromUsername(gh.db, username)

- repoID := model.GetRepoIDFromReponame(gh.db, gh.reponame)

- if model.CheckRepoOwnerFromUserIDAndReponame(gh.db, userID, gh.reponame) {

- return true

- } else if model.CheckRepoMemberExistFromUserIDAndRepoID(gh.db, userID, repoID) {

- permission := model.GetRepoMemberPermissionFromUserIDAndRepoID(gh.db, userID, repoID)

- if permission == "read/write" {

- return true

- }

-

- return false

-

- } else {

- return false

- }

- } else {

- return false

- }

- }

-

- return true

-}

-

-func getServiceType(r *http.Request) string {

- vars := r.URL.Query()

- serviceType := vars["service"][0]

- if !strings.HasPrefix(serviceType, "git-") {

- return ""

- }

- return strings.TrimPrefix(serviceType, "git-")

-}

-

-func gitCommand(dir string, args ...string) []byte {

- cmd := exec.Command("git", args...)

- cmd.Dir = dir

- out, err := cmd.Output()

- errorhandler.CheckError("Error on git command function", err)

-

- return out

-}

-

-func updateServerInfo(dir string) []byte {

- return gitCommand(dir, "update-server-info")

-}

-

-func (gh *gitHandler) sendFile(contentType string) {

- reqFile := path.Join(gh.dir, gh.file)

- fi, err := os.Stat(reqFile)

- if os.IsNotExist(err) {

- gh.w.WriteHeader(http.StatusNotFound)

- return

- }

-

- gh.w.Header().Set("Content-Type", contentType)

- gh.w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))

- gh.w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat))

- http.ServeFile(gh.w, gh.r, reqFile)

-}

-

-func packetWrite(str string) []byte {

- s := strconv.FormatInt(int64(len(str)+4), 16)

- if len(s)%4 != 0 {

- s = strings.Repeat("0", 4-len(s)%4) + s

- }

- return []byte(s + str)

-}

-

-func packetFlush() []byte {

- return []byte("0000")

-}

-

-func (gh *gitHandler) hdrNocache() {

- gh.w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")

- gh.w.Header().Set("Pragma", "no-cache")

- gh.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")

-}

-

-func (gh *gitHandler) hdrCacheForever() {

- now := time.Now().Unix()

- expires := now + 31536000

- gh.w.Header().Set("Date", fmt.Sprintf("%d", now))

- gh.w.Header().Set("Expires", fmt.Sprintf("%d", expires))

- gh.w.Header().Set("Cache-Control", "public, max-age=31536000")

-}

-

-func serviceUploadPack(gh gitHandler) {

- postServiceRPC(gh, "upload-pack")

-}

-

-func serviceReceivePack(gh gitHandler) {

- postServiceRPC(gh, "receive-pack")

-}

-

-func postServiceRPC(gh gitHandler, rpc string) {

- if gh.processRepoAccess(rpc, "Please enter your username and password") {

- if gh.r.Header.Get("Content-Type") != fmt.Sprintf("application/x-git-%s-request", rpc) {

- gh.w.WriteHeader(http.StatusUnauthorized)

- return

- }

-

- gh.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", rpc))

-

- var err error

- reqBody := gh.r.Body

-

- // Handle GZIP

- if gh.r.Header.Get("Content-Encoding") == "gzip" {

- reqBody, err = gzip.NewReader(reqBody)

- if err != nil {

- fmt.Printf("Fail to create gzip reader: %v", err)

- gh.w.WriteHeader(http.StatusInternalServerError)

- return

- }

- }

-

- cmd := exec.Command("git", rpc, "--stateless-rpc", gh.dir)

-

- var stderr bytes.Buffer

-

- cmd.Dir = gh.dir

- cmd.Stdin = reqBody

- cmd.Stdout = gh.w

- cmd.Stderr = &stderr

- if err := cmd.Run(); err != nil {

- fmt.Println(fmt.Sprintf("Fail to serve RPC(%s): %v - %s", rpc, err, stderr.String()))

- return

- }

-

- if rpc == "receive-pack" {

- go util.GenerateRefs(gh.refsPath, gh.repoPath, gh.repoGitName)

- }

- } else {

- gh.w.Header().Set("WWW-Authenticate", "Basic realm=\".\"")

- writeHdr(gh.w, http.StatusUnauthorized, "The repository cannot be accessed with your credentials.\n")

- }

-}

-

-func getInfoRefs(gh gitHandler) {

- gh.hdrNocache()

-

- rpc := getServiceType(gh.r)

-

- if gh.processRepoAccess(rpc, "Please enter your username and password") {

-

- if rpc != "upload-pack" && rpc != "receive-pack" {

- gh := gitHandler{}

- updateServerInfo(gh.dir)

- gh.sendFile("text/plain; charset=utf-8")

- return

- }

-

- refs := gitCommand(gh.dir, rpc, "--stateless-rpc", "--advertise-refs", ".")

- gh.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", rpc))

- gh.w.WriteHeader(http.StatusOK)

- gh.w.Write(packetWrite("# service=git-" + rpc + "\n"))

- gh.w.Write([]byte("0000"))

- gh.w.Write(refs)

-

- if rpc == "receive-pack" {

- go util.GenerateRefs(gh.refsPath, gh.repoPath, gh.repoGitName)

- }

- } else {

- gh.w.Header().Set("WWW-Authenticate", "Basic realm=\".\"")

- writeHdr(gh.w, http.StatusUnauthorized, "The repository cannot be accessed with your credentials.\n")

- }

-}

-

-func getTextFile(gh gitHandler) {

- gh.hdrNocache()

- gh.sendFile("text/plain")

-}

-

-func getInfoPacks(gh gitHandler) {

- gh.hdrCacheForever()

- gh.sendFile("text/plain; charset=utf-8")

-}

-

-func getLooseObject(gh gitHandler) {

- gh.hdrCacheForever()

- gh.sendFile("application/x-git-loose-object")

-}

-

-func getPackFile(gh gitHandler) {

- gh.hdrCacheForever()

- gh.sendFile("application/x-git-packed-objects")

-}

-

-func getIdxFile(gh gitHandler) {

- gh.hdrCacheForever()

- gh.sendFile("application/x-git-packed-objects-toc")

-}

-

-var routes = []struct {

- rxp *regexp.Regexp

- method string

- handler func(gitHandler)

-}{

- {regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack},

- {regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack},

- {regexp.MustCompile("(.*?)/info/refs$"), "GET", getInfoRefs},

- {regexp.MustCompile("(.*?)/HEAD$"), "GET", getTextFile},

- {regexp.MustCompile("(.*?)/objects/info/alternates$"), "GET", getTextFile},

- {regexp.MustCompile("(.*?)/objects/info/http-alternates$"), "GET", getTextFile},

- {regexp.MustCompile("(.*?)/objects/info/packs$"), "GET", getInfoPacks},

- {regexp.MustCompile("(.*?)/objects/info/[^/]*$"), "GET", getTextFile},

- {regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"), "GET", getLooseObject},

- {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"), "GET", getPackFile},

- {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"), "GET", getIdxFile},

-}

-

-func writeHdr(w http.ResponseWriter, status int, text string) {

- w.WriteHeader(status)

- _, err := w.Write([]byte(text))

- errorhandler.CheckError("Error on write hdr function", err)

-}

-

-func getProjectRootDir() string {

- projectRootDir, err := filepath.Abs(filepath.Dir(os.Args[0]))

- errorhandler.CheckError("Error on get project root dir function", err)

- return projectRootDir

-}

-

-// GitviaHTTP ...

-func GitviaHTTP(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- for _, route := range routes {

- reqPath := strings.ToLower(r.URL.Path)

- reqPath = "/" + strings.Split(reqPath, "/r/")[1]

- routeMatch := route.rxp.FindStringSubmatch(reqPath)

-

- if routeMatch == nil {

- continue

- }

-

- if route.method != r.Method {

- if r.Proto == "HTTP/1.1" {

- writeHdr(w, http.StatusMethodNotAllowed, "Method not allowed")

- } else {

- writeHdr(w, http.StatusBadRequest, "Bad request")

- }

- return

- }

-

- var repoDir string

- projectRootDir := getProjectRootDir()

-

- if conf.Paths.RepoPath == "." || conf.Paths.RepoPath == "" || conf.Paths.RepoPath == "./repositories" {

- repoDir = filepath.Join(projectRootDir, "repositories", routeMatch[1])

- } else {

- repoDir = filepath.Join(conf.Paths.RepoPath, routeMatch[1])

- }

-

- file := strings.TrimPrefix(reqPath, routeMatch[1]+"/")

- repoGitName := strings.TrimPrefix(routeMatch[1], "/")

- reponame := strings.TrimSuffix(repoGitName, ".git")

-

- gh := gitHandler{

- w: w,

- r: r,

- dir: repoDir,

- file: file,

- reponame: reponame,

- repoGitName: repoGitName,

- repoPath: conf.Paths.RepoPath,

- refsPath: conf.Paths.RefsPath,

- db: db,

- }

-

- route.handler(gh)

-

- return

- }

-

- writeHdr(w, http.StatusNotFound, "Not found")

-}

@@ -1,147 +0,0 @@

-package handler

-

-import (

- "database/sql"

- "fmt"

- "io"

- "log"

- "os/exec"

- "path/filepath"

- "strconv"

- "strings"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

-

- "github.com/gliderlabs/ssh"

- gossh "golang.org/x/crypto/ssh"

-)

-

-var authorizedKey []byte

-var gitRPC, gitRepo string

-var userID string

-var reponame string

-

-// RunSSH ...

-func RunSSH(conf *setting.BaseStruct, db *sql.DB) {

- ssh.Handle(func(s ssh.Session) {

- authorizedKey = gossh.MarshalAuthorizedKey(s.PublicKey())

-

- if len(s.Command()) == 2 {

- gitRPC = s.Command()[0]

- gitRepo = s.Command()[1]

-

- if strings.HasPrefix(gitRepo, "/") {

- gitRepo = strings.Split(gitRepo, "/")[1]

- }

-

- if !strings.HasSuffix(gitRepo, ".git") {

- log.Printf("ssh: invalid git repository name")

- return

- }

-

- reponame = strings.Split(gitRepo, ".git")[0]

- userIDInt, err := strconv.Atoi(userID)

- if err != nil {

- log.Printf("ssh: cannot convert userID to integer")

- return

- }

- repoID := model.GetRepoIDFromReponame(db, reponame)

-

- if isRepoPrivate := model.GetRepoType(db, reponame); isRepoPrivate && gitRPC == "upload-pack" {

- if !model.CheckRepoOwnerFromUserIDAndReponame(db, userIDInt, reponame) && !model.CheckRepoMemberExistFromUserIDAndRepoID(db, userIDInt, repoID) {

- log.Printf("ssh: no repo access")

- return

- } else if model.CheckRepoMemberExistFromUserIDAndRepoID(db, userIDInt, repoID) {

- permission := model.GetRepoMemberPermissionFromUserIDAndRepoID(db, userIDInt, repoID)

- if permission != "read" && permission != "read/write" {

- log.Printf("ssh: no repo access")

- return

- }

- }

- }

-

- if gitRPC == "git-receive-pack" {

- if !model.CheckRepoOwnerFromUserIDAndReponame(db, userIDInt, reponame) && !model.CheckRepoMemberExistFromUserIDAndRepoID(db, userIDInt, repoID) {

- log.Printf("ssh: no repo access")

- return

- } else if model.CheckRepoMemberExistFromUserIDAndRepoID(db, userIDInt, repoID) {

- permission := model.GetRepoMemberPermissionFromUserIDAndRepoID(db, userIDInt, repoID)

- if permission != "read/write" {

- log.Printf("ssh: no repo access")

- return

- }

- }

- }

- } else {

- log.Printf("ssh: no git command")

- return

- }

-

- cmd := exec.Command(gitRPC, gitRepo)

- cmd.Dir = conf.Paths.RepoPath

-

- stdout, err := cmd.StdoutPipe()

- if err != nil {

- log.Printf("ssh: cant open stdout pipe: %v", err)

- return

- }

-

- stderr, err := cmd.StderrPipe()

- if err != nil {

- log.Printf("ssh: cant open stderr pipe: %v", err)

- return

- }

-

- input, err := cmd.StdinPipe()

- if err != nil {

- log.Printf("ssh: cant open stdin pipe: %v", err)

- return

- }

-

- if err = cmd.Start(); err != nil {

- log.Printf("ssh: start error: %v", err)

- return

- }

-

- go io.Copy(input, s)

- io.Copy(s, stdout)

- io.Copy(s.Stderr(), stderr)

-

- if err = cmd.Wait(); err != nil {

- log.Printf("ssh: command failed: %v", err)

- return

- }

-

- s.SendRequest("exit-status", false, []byte{0, 0, 0, 0})

-

- if gitRPC == "git-receive-pack" {

- go util.GenerateRefs(conf.Paths.RefsPath, conf.Paths.RepoPath, gitRepo)

- }

-

- return

- })

-

- publicKeyOption := ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {

- sshDetail := model.GetSSHAllAuthKeys(db)

-

- for i := 0; i < len(sshDetail.AuthKeys); i++ {

- authKeyByte := []byte(sshDetail.AuthKeys[i])

- allowed, _, _, _, err := gossh.ParseAuthorizedKey(authKeyByte)

- errorhandler.CheckError("Error on Parse authorized key", err)

-

- if ssh.KeysEqual(key, allowed) {

- userID = sshDetail.UserIDs[i]

- return true

- }

- }

- log.Printf("Failed to handshake")

- return false

- })

-

- log.Printf("Starting ssh server on port %s...", conf.Server.SSHPort)

- sshPort := fmt.Sprintf(":%s", conf.Server.SSHPort)

- log.Fatal(ssh.ListenAndServe(sshPort, nil, ssh.NoPty(), publicKeyOption, ssh.HostKeyFile(filepath.Join(conf.Paths.SSHPath, "id_rsa"))))

-}

@@ -0,0 +1,238 @@

+package internal

+

+import (

+ "database/sql"

+ "html/template"

+ "io/ioutil"

+ "net/http"

+ "path"

+ "path/filepath"

+ "sorcia/models"

+ "sorcia/pkg"

+ "strings"

+)

+

+// IndexPageResponse struct

+type IndexPageResponse struct {

+ IsLoggedIn bool

+ ShowLoginMenu bool

+ HeaderActiveMenu string

+ SorciaVersion string

+ CanCreateRepo bool

+ Repos GetReposStruct

+ SiteSettings SiteSettings

+}

+

+// GetReposStruct struct

+type GetReposStruct struct {

+ Repositories []RepoDetailStruct

+}

+

+// RepoDetailStruct struct

+type RepoDetailStruct struct {

+ ID int

+ Name string

+ Description string

+ IsPrivate bool

+ Permission string

+}

+

+// GetHome ...

+func GetHome(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *pkg.BaseStruct) {

+ userPresent := w.Header().Get("user-present")

+

+ repos := models.GetAllPublicRepos(db)

+ var grs GetReposStruct

+

+ if userPresent == "true" {

+ token := w.Header().Get("sorcia-cookie-token")

+ userID := models.GetUserIDFromToken(db, token)

+

+ for _, repo := range repos.Repositories {

+ rd := RepoDetailStruct{

+ ID: repo.ID,

+ Name: repo.Name,

+ Description: repo.Description,

+ IsPrivate: repo.IsPrivate,

+ Permission: repo.Permission,

+ }

+ if models.CheckRepoMemberExistFromUserIDAndRepoID(db, userID, repo.ID) {

+ rd.Permission = models.GetRepoMemberPermissionFromUserIDAndRepoID(db, userID, repo.ID)

+ } else if models.CheckRepoOwnerFromUserIDAndReponame(db, userID, repo.Name) {

+ rd.Permission = "read/write"

+ }

+

+ grs.Repositories = append(grs.Repositories, rd)

+ }

+

+ var reposAsMember models.GetReposStruct

+ var repoAsMember models.RepoDetailStruct

+

+ reposAsMember = models.GetReposFromUserID(db, userID)

+

+ repoIDs := models.GetRepoIDsOnRepoMembersUsingUserID(db, userID)

+ for _, repoID := range repoIDs {

+ repoAsMember = models.GetRepoFromRepoID(db, repoID)

+ reposAsMember.Repositories = append(reposAsMember.Repositories, repoAsMember)

+ }

+

+ for _, repo := range reposAsMember.Repositories {

+ repoExistCount := 0

+ for _, publicRepo := range grs.Repositories {

+ if publicRepo.Name == repo.Name {

+ repoExistCount = 1

+ }

+ }

+

+ if repoExistCount == 0 {

+ rd := RepoDetailStruct{

+ ID: repo.ID,

+ Name: repo.Name,

+ Description: repo.Description,

+ IsPrivate: repo.IsPrivate,

+ Permission: repo.Permission,

+ }

+ if models.CheckRepoMemberExistFromUserIDAndRepoID(db, userID, repo.ID) {

+ rd.Permission = models.GetRepoMemberPermissionFromUserIDAndRepoID(db, userID, repo.ID)

+ } else if models.CheckRepoOwnerFromUserIDAndReponame(db, userID, repo.Name) {

+ rd.Permission = "read/write"

+ }

+

+ grs.Repositories = append(grs.Repositories, rd)

+ }

+ }

+

+ layoutPage := path.Join("./templates", "layout.html")

+ headerPage := path.Join("./templates", "header.html")

+ indexPage := path.Join("./templates", "index.html")

+ footerPage := path.Join("./templates", "footer.html")

+

+ tmpl, err := template.ParseFiles(layoutPage, headerPage, indexPage, footerPage)

+ pkg.CheckError("Error on template parse", err)

+

+ w.Header().Set("Content-Type", "text/html; charset=utf-8")

+ w.WriteHeader(http.StatusOK)

+

+ data := IndexPageResponse{

+ IsLoggedIn: true,

+ HeaderActiveMenu: "",

+ SorciaVersion: conf.Version,

+ CanCreateRepo: models.CheckifUserCanCreateRepo(db, userID),

+ Repos: grs,

+ SiteSettings: GetSiteSettings(db, conf),

+ }

+

+ tmpl.ExecuteTemplate(w, "layout", data)

+ } else {

+ if !models.CheckIfFirstUserExists(db) {

+ http.Redirect(w, r, "/login", http.StatusFound)

+ return

+ }

+

+ for _, repo := range repos.Repositories {

+ rd := RepoDetailStruct{

+ ID: repo.ID,

+ Name: repo.Name,

+ Description: repo.Description,

+ IsPrivate: repo.IsPrivate,

+ Permission: repo.Permission,

+ }

+ grs.Repositories = append(grs.Repositories, rd)

+ }

+

+ layoutPage := path.Join("./templates", "layout.html")

+ headerPage := path.Join("./templates", "header.html")

+ indexPage := path.Join("./templates", "index.html")

+ footerPage := path.Join("./templates", "footer.html")

+

+ tmpl, err := template.ParseFiles(layoutPage, headerPage, indexPage, footerPage)

+ pkg.CheckError("Error on template parse", err)

+

+ w.Header().Set("Content-Type", "text/html; charset=utf-8")

+ w.WriteHeader(http.StatusOK)

+

+ data := IndexPageResponse{

+ IsLoggedIn: false,

+ ShowLoginMenu: true,

+ SorciaVersion: conf.Version,

+ Repos: grs,

+ SiteSettings: GetSiteSettings(db, conf),

+ }

+

+ tmpl.ExecuteTemplate(w, "layout", data)

+ }

+}

+

+// SiteSettings struct

+type SiteSettings struct {

+ IsSiteTitle bool

+ IsSiteFavicon bool

+ IsSiteLogo bool

+ SiteTitle string

+ SiteStyle string

+ SiteFavicon string

+ SiteFaviconExt string

+ SiteLogo string

+ SiteLogoWidth string

+ SiteLogoHeight string

+ IsSiteLogoSVG bool

+ SVGDAT template.HTML

+}

+

+// GetSiteSettings ...

+func GetSiteSettings(db *sql.DB, conf *pkg.BaseStruct) SiteSettings {

+ gssr := models.GetSiteSettings(db, pkg.GetConf())

+

+ isSiteTitle := true

+ if gssr.Title == "" {

+ isSiteTitle = false

+ }

+

+ isSiteFavicon := true

+ if gssr.Favicon == "" {

+ isSiteFavicon = false

+ }

+

+ isSiteLogo := true

+ if gssr.Logo == "" {

+ isSiteLogo = false

+ }

+

+ var faviconExt string

+ faviconSplit := strings.Split(gssr.Favicon, ".")

+ if len(faviconSplit) > 1 {

+ faviconExt = faviconSplit[1]

+ }

+

+ var isSiteLogoSVG bool

+ var svgXML template.HTML

+ var siteLogoExt string

+ siteLogoSplit := strings.Split(gssr.Logo, ".")

+ if len(siteLogoSplit) > 1 {

+ siteLogoExt = siteLogoSplit[1]

+ }

+ if siteLogoExt == "svg" {

+ isSiteLogoSVG = true

+ dat, err := ioutil.ReadFile(filepath.Join(conf.Paths.UploadAssetPath, gssr.Logo))

+ pkg.CheckError("Error on Reading svg logo file", err)

+

+ svgXML = template.HTML(dat)

+ }

+

+ siteSettings := SiteSettings{

+ IsSiteTitle: isSiteTitle,

+ IsSiteFavicon: isSiteFavicon,

+ IsSiteLogo: isSiteLogo,

+ SiteTitle: gssr.Title,

+ SiteStyle: gssr.Style,

+ SiteFavicon: gssr.Favicon,

+ SiteFaviconExt: faviconExt,

+ SiteLogo: gssr.Logo,

+ SiteLogoWidth: gssr.LogoWidth,

+ SiteLogoHeight: gssr.LogoHeight,

+ IsSiteLogoSVG: isSiteLogoSVG,

+ SVGDAT: svgXML,

+ }

+

+ return siteSettings

+}

@@ -1,589 +0,0 @@

-package handler

-

-import (

- "database/sql"

- "encoding/json"

- "fmt"

- "html/template"

- "image"

-

- // jpeg import

- _ "image/jpeg"

-

- // png import

- _ "image/png"

- "io"

- "net/http"

- "os"

- "path"

- "path/filepath"

- "strconv"

- "strings"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

-

- "github.com/gorilla/mux"

- "github.com/gorilla/schema"

-)

-

-// MetaResponse struct

-type MetaResponse struct {

- IsLoggedIn bool

- IsAdmin bool

- HeaderActiveMenu string

- SorciaVersion string

- Username string

- Email string

- Users model.Users

- RegisterErrMessage string

- SiteSettings util.SiteSettings

-}

-

-// GetMeta ...

-func GetMeta(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- username := model.GetUsernameFromToken(db, token)

-

- userID := model.GetUserIDFromToken(db, token)

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- metaPage := path.Join("./templates", "meta.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, metaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := MetaResponse{

- IsLoggedIn: true,

- IsAdmin: model.CheckifUserIsAnAdmin(db, userID),

- HeaderActiveMenu: "meta",

- SorciaVersion: conf.Version,

- Username: username,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- } else {

- http.Redirect(w, r, "/login", http.StatusFound)

- }

-}

-

-// MetaKeysResponse struct

-type MetaKeysResponse struct {

- IsLoggedIn bool

- IsAdmin bool

- HeaderActiveMenu string

- SorciaVersion string

- SSHKeys *model.SSHKeysResponse

- SiteSettings util.SiteSettings

-}

-

-// GetMetaKeys ...

-func GetMetaKeys(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- sshKeys := model.GetSSHKeysFromUserId(db, userID)

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- metaPage := path.Join("./templates", "meta-keys.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, metaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := MetaKeysResponse{

- IsLoggedIn: true,

- IsAdmin: model.CheckifUserIsAnAdmin(db, userID),

- HeaderActiveMenu: "meta",

- SorciaVersion: conf.Version,

- SSHKeys: sshKeys,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- } else {

- http.Redirect(w, r, "/login", http.StatusFound)

- }

-}

-

-// DeleteMetaKey ...

-func DeleteMetaKey(w http.ResponseWriter, r *http.Request, db *sql.DB) {

- vars := mux.Vars(r)

- keyID := vars["keyID"]

-

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- i, err := strconv.Atoi(keyID)

- errorhandler.CheckError("Error on converting SSH key id(string) to int on delete meta keys", err)

-

- model.DeleteMetaKeyByID(db, i)

- http.Redirect(w, r, "/meta/keys", http.StatusFound)

- } else {

- http.Redirect(w, r, "/login", http.StatusFound)

- }

-}

-

-// CreateAuthKeyRequest struct

-type CreateAuthKeyRequest struct {

- Title string `schema:"sshtitle"`

- AuthKey string `schema:"sshkey"`

-}

-

-// PostAuthKey ...

-func PostAuthKey(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

-

- // NOTE: Invoke ParseForm or ParseMultipartForm before reading form values

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- var createAuthKeyRequest = &CreateAuthKeyRequest{}

- err := decoder.Decode(createAuthKeyRequest, r.PostForm)

- errorhandler.CheckError("Error on auth key decode", err)

-

- userID := model.GetUserIDFromToken(db, token)

-

- authKey := strings.TrimSpace(createAuthKeyRequest.AuthKey)

- fingerPrint := util.SSHFingerPrint(authKey)

-

- ispk := model.InsertSSHPubKeyStruct{

- AuthKey: authKey,

- Title: strings.TrimSpace(createAuthKeyRequest.Title),

- Fingerprint: fingerPrint,

- UserID: userID,

- }

-

- model.InsertSSHPubKey(db, ispk)

-

- http.Redirect(w, r, "/meta/keys", http.StatusFound)

- return

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// RevokeCreateRepoAccess ...

-func RevokeCreateRepoAccess(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- username := vars["username"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- if model.CheckifUserIsAnAdmin(db, userID) {

- model.RevokeCanCreateRepo(db, username)

-

- http.Redirect(w, r, "/meta/users", http.StatusFound)

- return

- }

- }

-

- http.Redirect(w, r, "/meta/users", http.StatusFound)

-}

-

-// AddCreateRepoAccess ...

-func AddCreateRepoAccess(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- username := vars["username"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- if model.CheckifUserIsAnAdmin(db, userID) {

- model.AddCanCreateRepo(db, username)

-

- http.Redirect(w, r, "/meta/users", http.StatusFound)

- return

- }

- }

-

- http.Redirect(w, r, "/meta/users", http.StatusFound)

-}

-

-// PostUserRequest struct

-type PostUserRequest struct {

- Username string `schema:"username"`

- Password string `schema:"password"`

- CanCreateRepo string `schema:"createrepo"`

-}

-

-// PostUser ...

-func PostUser(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- var postUserRequest = &PostUserRequest{}

- err := decoder.Decode(postUserRequest, r.PostForm)

- errorhandler.CheckError("Error on meta post user", err)

-

- // Generate password hash using bcrypt

- passwordHash, err := HashPassword(postUserRequest.Password)

- errorhandler.CheckError("Error on post register hash password", err)

-

- // Generate JWT token using the hash password above

- token, err := GenerateJWTToken(passwordHash)

- errorhandler.CheckError("Error on post register generate jwt token", err)

-

- s := postUserRequest.Username

-

- if len(s) > 39 || len(s) < 1 {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- metaUsersPage := path.Join("./templates", "meta-users.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, metaUsersPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- IsShowSignUp: !model.CheckIfFirstUserExists(db),

- LoginErrMessage: "",

- RegisterErrMessage: "Username is too long (maximum is 39 characters).",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- } else if strings.HasPrefix(s, "-") || strings.Contains(s, "--") || strings.HasSuffix(s, "-") || !util.IsAlnumOrHyphen(s) {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- metaUsersPage := path.Join("./templates", "meta-users.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, metaUsersPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := LoginPageResponse{

- IsLoggedIn: false,

- ShowLoginMenu: false,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- IsShowSignUp: !model.CheckIfFirstUserExists(db),

- LoginErrMessage: "",

- RegisterErrMessage: "Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.",

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

-

- canCreateRepo := 0

- if postUserRequest.CanCreateRepo != "" {

- canCreateRepo = 1

- }

-

- rr := model.CreateAccountStruct{

- Username: postUserRequest.Username,

- PasswordHash: passwordHash,

- Token: token,

- CanCreateRepo: canCreateRepo,

- IsAdmin: 0,

- }

-

- model.InsertAccount(db, rr)

-

- http.Redirect(w, r, "/meta/users", http.StatusFound)

- return

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// GetMetaUsers ...

-func GetMetaUsers(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- users := model.GetAllUsers(db)

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- metaPage := path.Join("./templates", "meta-users.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, metaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := MetaResponse{

- IsLoggedIn: true,

- IsAdmin: model.CheckifUserIsAnAdmin(db, userID),

- RegisterErrMessage: "",

- HeaderActiveMenu: "meta",

- SorciaVersion: conf.Version,

- Users: users,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// PostPasswordRequest struct

-type PostPasswordRequest struct {

- Username string `schema:"username"`

- Password string `schema:"password"`

-}

-

-// MetaPostPassword ...

-func MetaPostPassword(w http.ResponseWriter, r *http.Request, db *sql.DB, decoder *schema.Decoder) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

-

- // NOTE: Invoke ParseForm or ParseMultipartForm before reading form values

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- postPasswordRequest := &PostPasswordRequest{}

- err := decoder.Decode(postPasswordRequest, r.PostForm)

- errorhandler.CheckError("Error on post password decoder", err)

-

- username := model.GetUsernameFromToken(db, token)

-

- // Generate password hash using bcrypt

- passwordHash, err := HashPassword(postPasswordRequest.Password)

- errorhandler.CheckError("Error on password hash", err)

-

- // Generate JWT token using the hash password above

- jwtToken, err := GenerateJWTToken(passwordHash)

- errorhandler.CheckError("Error on generating jwt token", err)

-

- resetPass := model.ResetUserPasswordbyUsernameStruct{

- PasswordHash: passwordHash,

- JwtToken: jwtToken,

- Username: username,

- }

- model.ResetUserPasswordbyUsername(db, resetPass)

- http.Redirect(w, r, "/meta", http.StatusFound)

- return

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// MetaPostSiteSettings ...

-func MetaPostSiteSettings(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

-

- siteTitle := r.FormValue("title")

- siteStyle := r.FormValue("style")

-

- gotFavicon, faviconPath := faviconUpload(w, r, db, conf.Paths.UploadAssetPath)

- gotLogo, logoPath, logoWidth, logoHeight := logoUpload(w, r, db, conf.Paths.UploadAssetPath)

-

- if siteTitle == "" && siteStyle == "" && !gotFavicon && !gotLogo {

- http.Redirect(w, r, "/meta", http.StatusFound)

- return

- }

-

- if !model.CheckIFSiteSettingsExists(db) {

- css := model.CreateSiteSettingsStruct{

- Title: siteTitle,

- Favicon: faviconPath,

- Logo: logoPath,

- LogoWidth: logoWidth,

- LogoHeight: logoHeight,

- Style: siteStyle,

- }

- model.InsertSiteSettings(db, css)

-

- http.Redirect(w, r, "/meta", http.StatusFound)

- return

- }

-

- if siteTitle != "" {

- model.UpdateSiteTitle(db, siteTitle)

- }

-

- if siteStyle != "" {

- model.UpdateSiteStyle(db, siteStyle)

- }

-

- if gotFavicon {

- model.UpdateSiteFavicon(db, faviconPath)

- }

-

- if gotLogo {

- model.UpdateSiteLogo(db, logoPath, logoWidth, logoHeight)

- }

-

- http.Redirect(w, r, "/meta", http.StatusFound)

- return

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-func faviconUpload(w http.ResponseWriter, r *http.Request, db *sql.DB, uploadAssetPath string) (bool, string) {

- r.ParseMultipartForm(2)

-

- file, hdlr, err := r.FormFile("favicon")

- if err != nil {

- return false, ""

- }

- defer file.Close()

-

- contentType := hdlr.Header.Get("Content-Type")

-

- if contentType == "image/ico" || contentType == "image/png" || contentType == "image/jpeg" {

-

- oldFavicon := model.GetSiteFavicon(db)

- if oldFavicon != "" {

- err = os.Remove(oldFavicon)

- errorhandler.CheckError("Error on removing old favicon", err)

- }

-

- ext := strings.Split(contentType, "image/")[1]

-

- filePath := filepath.Join(uploadAssetPath, "favicon."+ext)

-

- f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm)

- errorhandler.CheckError("Error on opening favicon path", err)

- defer f.Close()

-

- io.Copy(f, file)

-

- return true, filePath

- }

-

- return false, ""

-}

-

-func logoUpload(w http.ResponseWriter, r *http.Request, db *sql.DB, uploadAssetPath string) (bool, string, string, string) {

- r.ParseMultipartForm(10)

-

- file, hdlr, err := r.FormFile("logo")

- if err != nil {

- return false, "", "", ""

- }

- defer file.Close()

-

- contentType := hdlr.Header.Get("Content-Type")

-

- if contentType == "image/svg+xml" || contentType == "image/png" || contentType == "image/jpeg" {

-

- oldLogo := model.GetSiteLogo(db)

- if oldLogo != "" {

- err = os.Remove(oldLogo)

- errorhandler.CheckError("Error on removing old logo", err)

- }

-

- ext := strings.Split(contentType, "image/")[1]

-

- if ext == "svg+xml" {

- ext = "svg"

- }

-

- filePath := filepath.Join(uploadAssetPath, "logo."+ext)

-

- f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm)

- errorhandler.CheckError("Error on opening favicon path", err)

- defer f.Close()

-

- io.Copy(f, file)

-

- getFile, err := os.Open(filePath)

- errorhandler.CheckError("Error on opening logo upload file", err)

- defer getFile.Close()

-

- var logoWidth, logoHeight string

-

- if ext != "svg" {

- image, _, err := image.DecodeConfig(getFile)

- errorhandler.CheckError("Error on DecodeConfig in logoUpload function", err)

- logoWidth = strconv.Itoa(image.Width)

- logoHeight = strconv.Itoa(image.Height)

- }

-

- return true, filePath, logoWidth, logoHeight

- }

-

- return false, "", "", ""

-}

@@ -1,1655 +0,0 @@

-package handler

-

-import (

- "crypto/md5"

- "database/sql"

- "encoding/hex"

- "encoding/json"

- "fmt"

- "html/template"

- "net/http"

- "os"

- "path"

- "path/filepath"

- "strconv"

- "strings"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

- "sorcia/util"

-

- "github.com/gorilla/mux"

- "github.com/gorilla/schema"

- "github.com/russross/blackfriday/v2"

-)

-

-// GetCreateRepoResponse struct

-type GetCreateRepoResponse struct {

- IsLoggedIn bool

- HeaderActiveMenu string

- ReponameErrMessage string

- SorciaVersion string

- SiteSettings util.SiteSettings

-}

-

-// GetCreateRepo ...

-func GetCreateRepo(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- if !model.CheckifUserCanCreateRepo(db, userID) {

- http.Redirect(w, r, "/", http.StatusFound)

- }

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- createRepoPage := path.Join("./templates", "create-repo.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, createRepoPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := GetCreateRepoResponse{

- IsLoggedIn: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// CreateRepoRequest struct

-type CreateRepoRequest struct {

- Name string `schema:"name"`

- Description string `schema:"description"`

- IsPrivate string `schema:"is_private"`

-}

-

-// PostCreateRepo ...

-func PostCreateRepo(w http.ResponseWriter, r *http.Request, db *sql.DB, decoder *schema.Decoder, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

-

- if !model.CheckifUserCanCreateRepo(db, userID) {

- http.Redirect(w, r, "/", http.StatusFound)

- }

-

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on post create repo json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- var createRepoRequest = &CreateRepoRequest{}

- err := decoder.Decode(createRepoRequest, r.PostForm)

- errorhandler.CheckError("Error on post create repo decoder", err)

-

- s := createRepoRequest.Name

- if len(s) > 100 || len(s) < 1 {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- createRepoPage := path.Join("./templates", "create-repo.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, createRepoPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := GetCreateRepoResponse{

- IsLoggedIn: true,

- HeaderActiveMenu: "",

- ReponameErrMessage: "Repository name is too long (maximum is 100 characters).",

- SorciaVersion: conf.Version,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- } else if strings.HasPrefix(s, "-") || strings.Contains(s, "--") || strings.HasSuffix(s, "-") || !util.IsAlnumOrHyphen(s) {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- createRepoPage := path.Join("./templates", "create-repo.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, createRepoPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := GetCreateRepoResponse{

- IsLoggedIn: true,

- HeaderActiveMenu: "",

- ReponameErrMessage: "Repository name may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.",

- SorciaVersion: conf.Version,

- SiteSettings: util.GetSiteSettings(db, conf),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

-

- var isPrivate int

- if isPrivate = 0; createRepoRequest.IsPrivate == "1" {

- isPrivate = 1

- }

-

- crs := model.CreateRepoStruct{

- Name: createRepoRequest.Name,

- Description: createRepoRequest.Description,

- IsPrivate: isPrivate,

- UserID: userID,

- }

-

- model.InsertRepo(db, crs)

-

- // Create Git bare repository

- bareRepoDir := filepath.Join(conf.Paths.RepoPath, createRepoRequest.Name+".git")

- gitPath := util.GetGitBinPath()

-

- args := []string{"init", "--bare", bareRepoDir}

- _ = util.ForkExec(gitPath, args, ".")

-

- http.Redirect(w, r, "/", http.StatusFound)

- return

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// GetRepoResponse struct

-type GetRepoResponse struct {

- SiteSettings util.SiteSettings

- SiteStyle string

- IsLoggedIn bool

- ShowLoginMenu bool

- HeaderActiveMenu string

- SorciaVersion string

- Username string

- RepoUserAddError string

- Reponame string

- ReponameErrMessage string

- RepoDescription string

- IsRepoPrivate bool

- RepoAccess bool

- RepoPermission string

- RepoEmpty bool

- RepoMembers model.GetRepoMembersStruct

- Host string

- SSHClone string

- TotalCommits string

- TotalRefs int

- RepoDetail RepoDetail

- RepoBranches []string

- IsRepoBranch bool

- RepoLogs RepoLogs

- CommitDetail CommitDetailStruct

- RepoRefs []Refs

- Contributors Contributors

-}

-

-// RepoDetail struct

-type RepoDetail struct {

- Readme template.HTML

- FileContent template.HTML

- LegendPath template.HTML

- WalkPath string

- PathEmpty bool

- RepoDirsDetail []RepoDirDetail

- RepoFilesDetail []RepoFileDetail

-}

-

-// RepoDirDetail struct

-type RepoDirDetail struct {

- DirName string

- DirCommit string

- DirCommitDate string

- DirCommitFullHash string

- DirCommitBranch string

-}

-

-// RepoFileDetail struct

-type RepoFileDetail struct {

- FileName string

- FileCommit string

- FileCommitDate string

- FileCommitFullHash string

- FileCommitBranch string

-}

-

-// RepoLog struct

-type RepoLog struct {

- FullHash string

- Hash string

- Author string

- Date string

- Message string

- DP string

- Branch string

-}

-

-func checkUserLoggedIn(w http.ResponseWriter) bool {

- userPresent := w.Header().Get("user-present")

-

- if userPresent == "true" {

- return true

- }

-

- return false

-}

-

-// GetRepo ...

-func GetRepo(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- userID := model.GetUserIDFromReponame(db, reponame)

- username := model.GetUsernameFromUserID(db, userID)

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

- totalCommits := util.GetCommitCounts(conf.Paths.RepoPath, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Username: username,

- Reponame: reponame,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- Host: r.Host,

- TotalCommits: totalCommits,

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- if strings.Contains(r.Host, ":") || conf.Server.SSHPort != "22" {

- host := strings.Split(r.Host, ":")[0]

- port := conf.Server.SSHPort

- data.SSHClone = fmt.Sprintf("ssh://%s:%s/%s.git", host, port, reponame)

- } else {

- data.SSHClone = fmt.Sprintf("git@%s:%s.git", r.Host, reponame)

- }

-

- if totalCommits == "" {

- data.RepoEmpty = true

- }

-

- data.RepoDetail.Readme = processREADME(repoDir)

-

- commits := getCommits(repoDir, "master", -3)

- data.RepoLogs = *commits

-

- _, totalTags := util.GetGitTags(repoDir)

- data.TotalRefs = totalTags

-

- contributors := getContributors(repoDir, false)

- data.Contributors = *contributors

-

- writeRepoResponse(w, r, db, reponame, "repo-summary.html", data)

- return

-}

-

-func processREADME(repoPath string) template.HTML {

-

- gitPath := util.GetGitBinPath()

- args := []string{"show", "master:README.md"}

-

- out := util.ForkExec(gitPath, args, repoPath)

-

- md := []byte(out)

- output := blackfriday.Run(md)

-

- html := template.HTML(output)

-

- return html

-}

-

-// GetRepoMeta ...

-func GetRepoMeta(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- var token string

- if userPresent == "true" {

- token = w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- username := model.GetUsernameFromToken(db, token)

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

- repoID := model.GetRepoIDFromReponame(db, reponame)

-

- grms := model.GetRepoMembers(db, repoID)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Username: username,

- Reponame: reponame,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoMembers: grms,

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- data.RepoEmpty = true

- }

-

- writeRepoResponse(w, r, db, reponame, "repo-meta.html", data)

- return

-}

-

-// PostRepoMetaDelete ...

-func PostRepoMetaDelete(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

- // username := model.GetUsernameFromToken(db, token)

-

- if model.CheckRepoOwnerFromUserIDAndReponame(db, userID, reponame) {

- model.DeleteRepobyReponame(db, reponame)

- refsPattern := filepath.Join(conf.Paths.RefsPath, reponame+"*")

-

- files, err := filepath.Glob(refsPattern)

- errorhandler.CheckError("Error on post repo meta delete filepath.Glob", err)

-

- for _, f := range files {

- err := os.Remove(f)

- errorhandler.CheckError("Error on removing ref files", err)

- }

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

- err = os.RemoveAll(repoDir)

- errorhandler.CheckError("Error on removing repository directory", err)

- }

- http.Redirect(w, r, "/", http.StatusFound)

- return

- }

- http.Redirect(w, r, "/", http.StatusFound)

-}

-

-// PostRepoMetaStruct struct

-type PostRepoMetaStruct struct {

- Name string `schema:"name"`

- Description string `schema:"description"`

- IsPrivate string `schema:"is_private"`

-}

-

-// PostRepoMeta ...

-func PostRepoMeta(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- userID := model.GetUserIDFromToken(db, token)

- username := model.GetUsernameFromToken(db, token)

-

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on post create repo json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- var postRepoMetaStruct = &PostRepoMetaStruct{}

- err := decoder.Decode(postRepoMetaStruct, r.PostForm)

- errorhandler.CheckError("Error on post repo meta decoder", err)

-

- s := postRepoMetaStruct.Name

- if len(s) > 100 || len(s) < 1 {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- repoMetaPage := path.Join("./templates", "repo-meta.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, repoMetaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Username: username,

- Reponame: reponame,

- ReponameErrMessage: "Repository name is too long (maximum is 100 characters).",

- RepoDescription: model.GetRepoDescriptionFromRepoName(db, reponame),

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, userID, reponame),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- } else if strings.HasPrefix(s, "-") || strings.Contains(s, "--") || strings.HasSuffix(s, "-") || !util.IsAlnumOrHyphen(s) {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- repoMetaPage := path.Join("./templates", "repo-meta.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, repoMetaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Username: username,

- Reponame: reponame,

- ReponameErrMessage: "Repository name may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.",

- RepoDescription: model.GetRepoDescriptionFromRepoName(db, reponame),

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, userID, reponame),

- }

-

- tmpl.ExecuteTemplate(w, "layout", data)

- return

- }

-

- var isPrivate int

- if isPrivate = 0; postRepoMetaStruct.IsPrivate == "1" {

- isPrivate = 1

- }

-

- if model.CheckRepoOwnerFromUserIDAndReponame(db, userID, reponame) == true {

- urs := model.UpdateRepoStruct{

- RepoID: model.GetRepoIDFromReponame(db, reponame),

- NewName: postRepoMetaStruct.Name,

- Description: postRepoMetaStruct.Description,

- IsPrivate: isPrivate,

- }

-

- model.UpdateRepo(db, urs)

-

- // Update repository dir name

- oldRepoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

- newRepoDir := filepath.Join(conf.Paths.RepoPath, urs.NewName+".git")

-

- if _, err := os.Stat(newRepoDir); os.IsNotExist(err) {

- err = os.Rename(oldRepoDir, newRepoDir)

- errorhandler.CheckError("Error on update repository dir name", err)

- }

-

- util.UpdateRefsWithNewName(conf.Paths.RefsPath, conf.Paths.RepoPath, reponame, urs.NewName)

-

- http.Redirect(w, r, "/r/"+urs.NewName+"/meta", http.StatusFound)

- return

- }

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

-}

-

-// RemoveRepoMetaUser ...

-func RemoveRepoMetaUser(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- reponame := vars["reponame"]

- username := vars["username"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID := model.GetUserIDFromToken(db, token)

-

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- userIDToRemove := model.GetUserIDFromUsername(db, username)

- repoID := model.GetRepoIDFromReponame(db, reponame)

- model.RemoveRepoMember(db, userIDToRemove, repoID)

-

- http.Redirect(w, r, "/r/"+reponame+"/meta", http.StatusFound)

- return

- }

- }

- http.Redirect(w, r, "/r/"+reponame+"/meta", http.StatusFound)

-}

-

-// PostRepoMetaMember struct

-type PostRepoMetaMember struct {

- Username string `schema:"username"`

- Permission string `schema:"is_readorwrite"`

-}

-

-// PostRepoMetaUser ...

-func PostRepoMetaUser(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct, decoder *schema.Decoder) {

- userPresent := w.Header().Get("user-present")

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- username := model.GetUsernameFromToken(db, token)

-

- if err := r.ParseForm(); err != nil {

- fmt.Fprintf(w, "ParseForm() err: %v", err)

- errorResponse := &errorhandler.Response{

- Error: err.Error(),

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on post create repo json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

- }

-

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- repoMetaPage := path.Join("./templates", "repo-meta.html")

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, repoMetaPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Username: username,

- Reponame: reponame,

- RepoDescription: model.GetRepoDescriptionFromRepoName(db, reponame),

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, model.GetUserIDFromUsername(db, username), reponame),

- }

-

- var postRepoMetaMember = &PostRepoMetaMember{}

- err = decoder.Decode(postRepoMetaMember, r.PostForm)

- errorhandler.CheckError("Error on post repo meta member decoder", err)

-

- userID := model.GetUserIDFromUsername(db, postRepoMetaMember.Username)

- repoID := model.GetRepoIDFromReponame(db, reponame)

- if userID > 0 {

- if !model.CheckRepoOwnerFromUserIDAndReponame(db, userID, reponame) {

- if !model.CheckRepoMemberExistFromUserIDAndRepoID(db, userID, repoID) {

- crm := model.CreateRepoMember{

- UserID: userID,

- RepoID: repoID,

- Permission: postRepoMetaMember.Permission,

- }

-

- model.InsertRepoMember(db, crm)

-

- http.Redirect(w, r, "/r/"+reponame+"/meta", http.StatusFound)

- return

- }

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

- data.RepoUserAddError = "User is already a member of this repository."

- tmpl.ExecuteTemplate(w, "layout", data)

- }

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

- data.RepoUserAddError = "User is the owner of this repository."

- tmpl.ExecuteTemplate(w, "layout", data)

- }

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

- data.RepoUserAddError = "User does not exist. Check if the username is correct or ask the server/sys admin to add this user."

- tmpl.ExecuteTemplate(w, "layout", data)

- }

-

- http.Redirect(w, r, "/login", http.StatusFound)

- return

-}

-

-// GetRepoTree ...

-func GetRepoTree(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

- branch := vars["branch"]

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoBranches: util.GetGitBranches(repoDir),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- gitPath := util.GetGitBinPath()

-

- dirs, files := walkThrough(repoDir, gitPath, branch, ".", 0)

-

- data.RepoDetail.WalkPath = r.URL.Path

- data.RepoDetail.PathEmpty = true

-

- data.RepoDetail.RepoDirsDetail, data.RepoDetail.RepoFilesDetail = applyDirsAndFiles(dirs, files, repoDir, ".", branch)

-

- commit := getCommits(repoDir, branch, -1)

- data.RepoLogs = *commit

- if len(data.RepoLogs.History) == 1 {

- data.RepoLogs.History[0].Message = util.LimitCharLengthInString(data.RepoLogs.History[0].Message)

- }

-

- writeRepoResponse(w, r, db, reponame, "repo-tree.html", data)

- return

-}

-

-// GetRepoTreePath ...

-func GetRepoTreePath(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

- branchOrHash := vars["branchorhash"]

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoBranch: true,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoBranches: util.GetGitBranches(repoDir),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- gitPath := util.GetGitBinPath()

- frdpath := strings.Split(r.URL.Path, "r/"+reponame+"/tree/"+branchOrHash+"/")[1]

-

- args := []string{"branch"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- ss := strings.Split(out, "\n")

- entries := ss[:len(ss)-1]

-

- legendHref := "\"/r/" + reponame + "/tree/" + branchOrHash + "\""

- legendPath := "<a href=" + legendHref + ">" + reponame + "</a>"

-

- legendPathSplit := strings.Split(frdpath, "/")

-

- for _, s := range legendPathSplit {

- legendHref = strings.TrimSuffix(legendHref, "\"")

- legendHref = fmt.Sprintf("%s/%s\"", legendHref, s)

-

- additionalPath := "<a href=" + legendHref + ">" + s + "</a>"

-

- legendPath = fmt.Sprintf("%s / %s", legendPath, additionalPath)

- }

-

- data.RepoDetail.PathEmpty = false

- data.RepoDetail.WalkPath = r.URL.Path

- data.RepoDetail.LegendPath = template.HTML(legendPath)

-

- for _, entry := range entries {

- entryCheck := strings.TrimSpace(entry)

-

- if entryCheck == branchOrHash || entryCheck == fmt.Sprintf("* %s", branchOrHash) {

- frdPathLen := len(strings.Split(frdpath, "/"))

- dirs, files := walkThrough(repoDir, gitPath, branchOrHash, frdpath, frdPathLen)

-

- if len(dirs) == 0 && len(files) == 0 {

- args := []string{"show", fmt.Sprintf("%s:%s", branchOrHash, frdpath)}

- out := util.ForkExec(gitPath, args, repoDir)

-

- frdSplit := strings.Split(frdpath, "/")

-

- frdFile := frdSplit[len(frdSplit)-1]

-

- fileDotSplit := strings.Split(frdFile, ".")

- var fileContent string

- if len(fileDotSplit) > 1 {

- fileContent = fmt.Sprintf("<pre><code class=\"%s\">%s</code></pre>", fileDotSplit[1], template.HTMLEscaper(out))

- } else {

- fileContent = fmt.Sprintf("<pre><code class=\"plaintext\">%s</code></pre>", template.HTMLEscaper(out))

- }

-

- data.RepoDetail.FileContent = template.HTML(fileContent)

-

- data.SiteStyle = model.GetSiteStyle(db)

-

- writeRepoResponse(w, r, db, reponame, "file-viewer.html", data)

- return

- }

-

- data.RepoDetail.RepoDirsDetail, data.RepoDetail.RepoFilesDetail = applyDirsAndFiles(dirs, files, repoDir, frdpath, branchOrHash)

-

- writeRepoResponse(w, r, db, reponame, "repo-tree.html", data)

- return

- }

- }

-

- data.IsRepoBranch = false

-

- args = []string{"show", branchOrHash, "--pretty=format:", "--", frdpath}

- out = util.ForkExec(gitPath, args, repoDir)

-

- diffLine := strings.Split(out, "\n")[0]

-

- if diffLine == fmt.Sprintf("diff --git a/%s b/%s", frdpath, frdpath) {

- args = []string{"show", fmt.Sprintf("%s:%s", branchOrHash, frdpath)}

- out = util.ForkExec(gitPath, args, repoDir)

- }

-

- frdSplit := strings.Split(frdpath, "/")

-

- frdFile := frdSplit[len(frdSplit)-1]

-

- fileDotSplit := strings.Split(frdFile, ".")

- var fileContent string

- if len(fileDotSplit) > 1 {

- fileContent = fmt.Sprintf("<pre><code class=\"%s\">%s</code></pre>", fileDotSplit[1], template.HTMLEscaper(out))

- } else {

- fileContent = fmt.Sprintf("<pre><code class=\"plaintext\">%s</code></pre>", template.HTMLEscaper(out))

- }

-

- data.RepoDetail.FileContent = template.HTML(fileContent)

-

- data.SiteStyle = model.GetSiteStyle(db)

-

- writeRepoResponse(w, r, db, reponame, "file-viewer.html", data)

- return

-}

-

-// Walk through files and folders

-func walkThrough(repoDir, gitPath, branch, lsTreePath string, lsTreePathLen int) ([]string, []string) {

- var dirs, files []string

-

- args := []string{"ls-tree", "-r", "--name-only", branch, "HEAD", lsTreePath + "/"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- ss := strings.Split(out, "\n")

- entries := ss[:len(ss)-1]

-

- for _, entry := range entries {

- entrySplit := strings.Split(entry, "/")

-

- if len(entrySplit) == 1 {

- files = append(files, entrySplit[0])

- } else if lsTreePathLen == 0 && !util.ContainsValueInArr(dirs, entrySplit[0]) {

- dirs = append(dirs, entrySplit[0])

- } else {

- newPath := strings.Join(entrySplit[:lsTreePathLen+1], "/")

- args = []string{"ls-tree", "-r", "--name-only", branch, "HEAD", newPath}

- out = util.ForkExec(gitPath, args, repoDir)

- ss = strings.Split(out, "\n")

- newEntries := ss[:len(ss)-1]

-

- for _, newEntry := range newEntries {

- newEntrySplit := strings.Split(newEntry, "/")

-

- if len(newEntrySplit) == (lsTreePathLen + 1) {

- files = append(files, newEntrySplit[lsTreePathLen])

- } else {

- if !util.ContainsValueInArr(dirs, newEntrySplit[lsTreePathLen]) {

- dirs = append(dirs, newEntrySplit[lsTreePathLen])

- }

- }

- }

- }

- }

-

- return dirs, files

-}

-

-// applyDirsAndFiles ...

-func applyDirsAndFiles(dirs, files []string, repoDir, frdpath, branch string) ([]RepoDirDetail, []RepoFileDetail) {

- gitPath := util.GetGitBinPath()

- repoDetail := RepoDetail{}

-

- for _, dir := range dirs {

- dirPath := fmt.Sprintf("%s/%s", frdpath, dir)

- repoDirDetail := RepoDirDetail{}

-

- args := []string{"log", branch, "-n", "1", "--pretty=format:%s||srca-sptra||%cr||srca-sptra||%H", "--", dirPath}

- out := util.ForkExec(gitPath, args, repoDir)

-

- ss := strings.Split(out, "||srca-sptra||")

-

- repoDirDetail.DirName = dir

- commit := ss[0]

- if len(commit) > 50 {

- commit = util.LimitCharLengthInString(commit)

- }

-

- repoDirDetail.DirCommit = commit

- repoDirDetail.DirCommitDate = ss[1]

- repoDirDetail.DirCommitFullHash = ss[2]

- repoDirDetail.DirCommitBranch = branch

- repoDetail.RepoDirsDetail = append(repoDetail.RepoDirsDetail, repoDirDetail)

- }

-

- for _, file := range files {

- filePath := fmt.Sprintf("%s/%s", frdpath, file)

- repoFileDetail := RepoFileDetail{}

-

- args := []string{"log", branch, "-n", "1", "--pretty=format:%s||srca-sptra||%cr||srca-sptra||%H", "--", filePath}

- out := util.ForkExec(gitPath, args, repoDir)

-

- ss := strings.Split(out, "||srca-sptra||")

-

- repoFileDetail.FileName = file

- commit := ss[0]

- if len(commit) > 50 {

- commit = util.LimitCharLengthInString(commit)

- }

-

- repoFileDetail.FileCommit = commit

- repoFileDetail.FileCommitDate = ss[1]

- repoFileDetail.FileCommitFullHash = ss[2]

- repoFileDetail.FileCommitBranch = branch

- repoDetail.RepoFilesDetail = append(repoDetail.RepoFilesDetail, repoFileDetail)

- }

-

- return repoDetail.RepoDirsDetail, repoDetail.RepoFilesDetail

-}

-

-// GetRepoLog ...

-func GetRepoLog(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

- branch := vars["branch"]

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- q := r.URL.Query()

- qFrom := q["from"]

-

- var fromHash string

-

- if len(qFrom) > 0 {

- fromHash = qFrom[0]

- }

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- RepoBranches: util.GetGitBranches(repoDir),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- commits := getCommitsFromHash(repoDir, branch, fromHash, 11)

- data.RepoLogs = *commits

-

- writeRepoResponse(w, r, db, reponame, "repo-log.html", data)

- return

-}

-

-// Refs struct

-type Refs struct {

- Version string

- Targz string

- TargzPath string

- Zip string

- ZipPath string

- Message string

-}

-

-// GetRepoRefs ...

-func GetRepoRefs(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- gitPath := util.GetGitBinPath()

- args := []string{"for-each-ref", "--sort=-taggerdate", "--format", "%(refname) %(contents:subject)", "refs/tags"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- lineSplit := strings.Split(out, "\n")

- lines := lineSplit[:len(lineSplit)-1]

-

- var rfs []Refs

-

- for _, line := range lines {

- var rf Refs

-

- refFields := strings.Fields(line)

-

- rf.Version = strings.Split(refFields[0], "/")[2]

-

- rf.Message = strings.Join(refFields[1:], " ")

-

- tagname := rf.Version

-

- // Remove 'v' prefix from version

- if strings.HasPrefix(tagname, "v") {

- tagname = strings.Split(tagname, "v")[1]

- }

-

- // Generate tar.gz file

- tarFilename := fmt.Sprintf("%s-%s.tar.gz", reponame, tagname)

- tarRefPath := filepath.Join(conf.Paths.RefsPath, tarFilename)

-

- if _, err := os.Stat(tarRefPath); !os.IsNotExist(err) {

- rf.Targz = tarFilename

- rf.TargzPath = fmt.Sprintf("/dl/%s", tarFilename)

- }

-

- // Generate zip file

- zipFilename := fmt.Sprintf("%s-%s.zip", reponame, tagname)

- zipRefPath := filepath.Join(conf.Paths.RefsPath, zipFilename)

-

- if _, err := os.Stat(zipRefPath); !os.IsNotExist(err) {

- rf.Zip = zipFilename

- rf.ZipPath = fmt.Sprintf("/dl/%s", zipFilename)

- }

-

- rfs = append(rfs, rf)

- }

-

- data.RepoRefs = rfs

-

- writeRepoResponse(w, r, db, reponame, "repo-refs.html", data)

- return

-}

-

-// ServeRefFile ...

-func ServeRefFile(w http.ResponseWriter, r *http.Request, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- fileName := vars["file"]

- dlPath := filepath.Join(conf.Paths.RefsPath, fileName)

- http.ServeFile(w, r, dlPath)

-}

-

-// GetRepoContributors ...

-func GetRepoContributors(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- contributors := getContributors(repoDir, true)

-

- data.Contributors = *contributors

-

- writeRepoResponse(w, r, db, reponame, "repo-contributors.html", data)

- return

-}

-

-// CommitDetailStruct struct

-type CommitDetailStruct struct {

- DP string

- Name string

- Message string

- Hash string

- Branch string

- Date string

- CommitStatus string

- Files []CommitFile

-}

-

-// CommitFile struct

-type CommitFile struct {

- Filename string

- State string

- PreviousHash string

- Ampersands []CommitAmpersand

-}

-

-// CommitAmpersand struct

-type CommitAmpersand struct {

- Ampersand template.HTML

- CodeLines template.HTML

- FileExt string

-}

-

-// GetCommitDetail ...

-func GetCommitDetail(w http.ResponseWriter, r *http.Request, db *sql.DB, conf *setting.BaseStruct) {

- vars := mux.Vars(r)

- reponame := vars["reponame"]

- commitHash := vars["hash"]

- branch := vars["branch"]

-

- repoDir := filepath.Join(conf.Paths.RepoPath, reponame+".git")

-

- if repoExists := model.CheckRepoExists(db, reponame); !repoExists {

- w.WriteHeader(http.StatusNotFound)

- return

- }

-

- if util.GetCommitCounts(conf.Paths.RepoPath, reponame) == "" {

- http.Redirect(w, r, "/r/"+reponame, http.StatusFound)

- return

- }

-

- userPresent := w.Header().Get("user-present")

- var loggedInUserID int

- if userPresent == "true" {

- token := w.Header().Get("sorcia-cookie-token")

- loggedInUserID = model.GetUserIDFromToken(db, token)

- }

-

- repoDescription := model.GetRepoDescriptionFromRepoName(db, reponame)

-

- var permission string

- if model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame) {

- permission = "read/write"

- } else {

- permission = model.GetRepoMemberPermissionFromUserIDAndRepoID(db, loggedInUserID, model.GetRepoIDFromReponame(db, reponame))

- }

-

- data := GetRepoResponse{

- SiteSettings: util.GetSiteSettings(db, conf),

- SiteStyle: model.GetSiteStyle(db),

- IsLoggedIn: checkUserLoggedIn(w),

- ShowLoginMenu: true,

- HeaderActiveMenu: "",

- SorciaVersion: conf.Version,

- Reponame: reponame,

- RepoAccess: model.CheckRepoOwnerFromUserIDAndReponame(db, loggedInUserID, reponame),

- RepoPermission: permission,

- RepoDescription: repoDescription,

- IsRepoPrivate: model.GetRepoType(db, reponame),

- }

-

- if !data.IsLoggedIn && data.IsRepoPrivate {

- http.Redirect(w, r, "/login", http.StatusFound)

- return

- }

-

- gitPath := util.GetGitBinPath()

-

- args := []string{"show", commitHash, "--name-status", "--pretty=format:%ae||srca-sptra||%an||srca-sptra||%s||srca-sptra||%ar"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- lines := strings.Split(out, "\n")

- // Remove empty last line

- lines = lines[:len(lines)-1]

-

- //filesChanged := strings.TrimSpace(lines[len(lines)-1])

- ss := strings.Split(lines[0], "||srca-sptra||")

- var cds CommitDetailStruct

- cds.Branch = branch

-

- if len(ss) > 1 {

- cds.Hash = commitHash

-

- email := ss[0]

- gravatarHash := md5.Sum([]byte(email))

- stringHash := hex.EncodeToString(gravatarHash[:])

- cds.DP = fmt.Sprintf("https://www.gravatar.com/avatar/%s", stringHash)

-

- cds.Name = ss[1]

- cds.Message = ss[2]

- cds.Date = ss[3]

- }

-

- for _, file := range lines[1:] {

- cf := CommitFile{}

- ca := CommitAmpersand{}

-

- cf.State = strings.Fields(file)[0]

- cf.Filename = strings.Fields(file)[1]

-

- fileDotSplit := strings.Split(cf.Filename, ".")

- ca.FileExt = "plaintext"

- if len(fileDotSplit) > 1 {

- ca.FileExt = fileDotSplit[1]

- }

-

- args := []string{"show", commitHash, commitHash, "--pretty=format:", "--full-index", "--", cf.Filename}

- out := util.ForkExec(gitPath, args, repoDir)

-

- lines = strings.Split(out, "\n")

-

- // Get PreviousHash and Ampersand

- for i, line := range lines {

- ts := strings.TrimSpace(line)

-

- if strings.HasPrefix(ts, fmt.Sprintf("diff --git a/%s b/%s", cf.Filename, cf.Filename)) {

- indexSplit := strings.Fields(strings.TrimSpace(lines[i+1]))

- cf.PreviousHash = strings.Split(indexSplit[1], "..")[0]

- }

-

- if strings.HasPrefix(ts, "@@") {

- ts = fmt.Sprintf("<div>%s</div>", ts)

- ca.Ampersand = template.HTML(ts)

- codeLines := ""

- for j, newLine := range lines[i+1:] {

- if strings.HasPrefix(newLine, "@@") {

- ca.CodeLines = template.HTML(codeLines)

- cf.Ampersands = append(cf.Ampersands, ca)

- newLine = fmt.Sprintf("<div>%s</div>", newLine)

- ca.Ampersand = template.HTML(newLine)

- codeLines = ""

- } else if j != len(lines[i+1:len(lines)-1]) {

- if strings.HasPrefix(newLine, "+") {

- codeLines = fmt.Sprintf("%s\n<p class=\"green\">%s</p>", codeLines, template.HTMLEscaper(newLine))

- } else if strings.HasPrefix(newLine, "-") {

- codeLines = fmt.Sprintf("%s\n<p class=\"red\">%s</p>", codeLines, template.HTMLEscaper(newLine))

- } else {

- codeLines = fmt.Sprintf("%s\n<p>%s</p>", codeLines, template.HTMLEscaper(newLine))

- }

- } else {

- ca.CodeLines = template.HTML(codeLines)

- cf.Ampersands = append(cf.Ampersands, ca)

- }

- }

- break

- }

- }

-

- cds.Files = append(cds.Files, cf)

- }

-

- // Get commit status

- args = []string{"show", commitHash, "--stat", "--pretty=format:"}

- out = util.ForkExec(gitPath, args, repoDir)

-

- lines = strings.Split(out, "\n")

- // Remove empty last line

- lines = lines[:len(lines)-1]

- commitStatus := strings.TrimSpace(lines[len(lines)-1])

- cds.CommitStatus = commitStatus

-

- data.CommitDetail = cds

-

- writeRepoResponse(w, r, db, reponame, "repo-commit.html", data)

- return

-}

-

-// Contributors struct

-type Contributors struct {

- Detail []Contributor

- Total string

-}

-

-// Contributor struct

-type Contributor struct {

- Name string

- DP string

- Commits string

-}

-

-func getContributors(repoDir string, getDetail bool) *Contributors {

- gitPath := util.GetGitBinPath()

-

- args := []string{"shortlog", "HEAD", "-sne"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- cStringRmLastLn := strings.TrimSuffix(out, "\n")

- lines := strings.Split(cStringRmLastLn, "\n")

-

- var contributors Contributors

-

- contributors.Total = strconv.Itoa(len(lines))

-

- if getDetail {

- for _, line := range lines {

- lineDetail := strings.Fields(line)

- var contributor Contributor

- if len(lineDetail) > 1 {

- contributor.Commits = lineDetail[0]

- lineFurther := strings.Join(lineDetail[1:], " ")

- contributor.Name = strings.Split(lineFurther, " <")[0]

- emailSplit := strings.Split(lineFurther, " <")[1]

- email := strings.Split(emailSplit, ">")[0]

-

- hash := md5.Sum([]byte(email))

- stringHash := hex.EncodeToString(hash[:])

- contributor.DP = fmt.Sprintf("https://www.gravatar.com/avatar/%s", stringHash)

-

- contributors.Detail = append(contributors.Detail, contributor)

- }

- }

- }

-

- return &contributors

-}

-

-func noRepoAccess(w http.ResponseWriter) {

- errorResponse := &errorhandler.Response{

- Error: "You don't have access to this repository.",

- }

-

- errorJSON, err := json.Marshal(errorResponse)

- errorhandler.CheckError("Error on no repo access function json marshal", err)

-

- w.Header().Set("Content-Type", "application/json")

- w.WriteHeader(http.StatusBadRequest)

-

- w.Write(errorJSON)

-}

-

-func writeRepoResponse(w http.ResponseWriter, r *http.Request, db *sql.DB, reponame string, mainPage string, data GetRepoResponse) {

- // Check if repository is not private

- if isRepoPrivate := model.GetRepoType(db, reponame); !isRepoPrivate {

- tmpl := parseTemplates(w, mainPage)

- tmpl.ExecuteTemplate(w, "layout", data)

- } else {

- userPresent := w.Header().Get("user-present")

-

- if userPresent != "" {

- token := w.Header().Get("sorcia-cookie-token")

- userIDFromToken := model.GetUserIDFromToken(db, token)

-

- // Check if the logged in user has access to view the repository.

- hasRepoAccess := model.CheckRepoOwnerFromUserIDAndReponame(db, userIDFromToken, reponame)

- if !hasRepoAccess {

- repoID := model.GetRepoIDFromReponame(db, reponame)

- hasRepoAccess = model.CheckRepoMemberExistFromUserIDAndRepoID(db, userIDFromToken, repoID)

- }

- if hasRepoAccess {

- data.IsRepoPrivate = true

- tmpl := parseTemplates(w, mainPage)

- tmpl.ExecuteTemplate(w, "layout", data)

- } else {

- noRepoAccess(w)

- }

- } else {

- http.Redirect(w, r, "/login", http.StatusFound)

- }

- }

-}

-

-func parseTemplates(w http.ResponseWriter, mainPage string) *template.Template {

- layoutPage := path.Join("./templates", "layout.html")

- headerPage := path.Join("./templates", "header.html")

- repoLogPage := path.Join("./templates", mainPage)

- footerPage := path.Join("./templates", "footer.html")

-

- tmpl, err := template.ParseFiles(layoutPage, headerPage, repoLogPage, footerPage)

- errorhandler.CheckError("Error on template parse", err)

-

- w.Header().Set("Content-Type", "text/html; charset=utf-8")

- w.WriteHeader(http.StatusOK)

-

- return tmpl

-}

-

-// RepoLogs struct

-type RepoLogs struct {

- History []RepoLog

- HashLink string

- IsNext bool

-}

-

-func getCommits(repoDir, branch string, commitCount int) *RepoLogs {

- rla := RepoLogs{}

- rl := RepoLog{}

-

- gitPath := util.GetGitBinPath()

-

- var args []string

- args = []string{"log", branch, strconv.Itoa(commitCount), "--pretty=format:%H||srca-sptra||%h||srca-sptra||%d||srca-sptra||%s||srca-sptra||%cr||srca-sptra||%an||srca-sptra||%ae"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- ss := strings.Split(out, "\n")

-

- for i := 0; i < len(ss); i++ {

- st := strings.Split(ss[i], "||srca-sptra||")

- if len(st) > 1 {

- rl.FullHash = st[0]

- rl.Hash = st[1]

- rl.Message = st[3]

- rl.Date = st[4]

- rl.Author = st[5]

- rl.Branch = branch

-

- hash := md5.Sum([]byte(st[6]))

- stringHash := hex.EncodeToString(hash[:])

- rl.DP = fmt.Sprintf("https://www.gravatar.com/avatar/%s", stringHash)

-

- rla = RepoLogs{

- History: append(rla.History, rl),

- }

- }

- }

-

- return &rla

-}

-

-func getCommitsFromHash(repoDir, branch, fromHash string, commitCount int) *RepoLogs {

- rla := RepoLogs{}

- rl := RepoLog{}

-

- var hashLink string

-

- ss := getGitCommits(commitCount, branch, fromHash, repoDir)

-

- for i := 0; i < len(ss); i++ {

- if i == (len(ss) - 1) {

- hashLink = strings.Split(ss[i], "||srca-sptra||")[0]

-

- gitPath := util.GetGitBinPath()

- args := []string{"rev-list", branch, "--max-parents=0", "HEAD"}

- out := util.ForkExec(gitPath, args, repoDir)

-

- lastHash := strings.Split(out, "\n")[0]

-

- if hashLink != lastHash {

- rla.IsNext = true

- break

- }

- }

- st := strings.Split(ss[i], "||srca-sptra||")

- if len(st) > 1 {

- rl.FullHash = st[0]

- rl.Hash = st[1]

- rl.Message = st[3]

- rl.Date = st[4]

- rl.Author = st[5]

- rl.Branch = branch

-

- hash := md5.Sum([]byte(st[6]))

- stringHash := hex.EncodeToString(hash[:])

- rl.DP = fmt.Sprintf("https://www.gravatar.com/avatar/%s", stringHash)

-

- rla = RepoLogs{

- History: append(rla.History, rl),

- }

- }

- }

-

- rla.HashLink = hashLink

-

- return &rla

-}

-

-func getGitCommits(commitCount int, branch, fromHash, dirPath string) []string {

- gitPath := util.GetGitBinPath()

-

- var args []string

- if fromHash == "" {

- args = []string{"log", branch, fmt.Sprintf("--max-count=%s", strconv.Itoa(commitCount)), "--pretty=format:%H||srca-sptra||%h||srca-sptra||%d||srca-sptra||%s||srca-sptra||%cr||srca-sptra||%an||srca-sptra||%ae"}

- } else {

- args = []string{"log", fmt.Sprintf("--max-count=%s", strconv.Itoa(commitCount)), fromHash, "--pretty=format:%H||srca-sptra||%h||srca-sptra||%d||srca-sptra||%s||srca-sptra||%cr||srca-sptra||%an||srca-sptra||%ae"}

- }

- out := util.ForkExec(gitPath, args, dirPath)

-

- ss := strings.Split(out, "\n")

-

- return ss

-}

@@ -4,8 +4,8 @@ import (

"database/sql"

"net/http"

- "sorcia/model"

- "sorcia/setting"

+ "sorcia/models"

+ "sorcia/pkg"

// SQLite3 driver

_ "github.com/mattn/go-sqlite3"

@@ -15,9 +15,8 @@ var middlewareDB *sql.DB

func init() {

// Get config values

- conf := setting.GetConf()

+ conf := pkg.GetConf()

- // Open postgres database

db := conf.DBConn

middlewareDB = db

@@ -38,7 +37,7 @@ func userMiddleware(w http.ResponseWriter, r *http.Request, db *sql.DB) http.Res

for _, cookie := range r.Cookies() {

if cookie.Name == cookieName && cookie.Value != "" {

cookieValue = cookie.Value

- userID := model.GetUserIDFromToken(db, cookie.Value)

+ userID := models.GetUserIDFromToken(db, cookie.Value)

if userID != 0 {

userPresent = "true"

}

@@ -1,533 +0,0 @@

-package model

-

-import (

- "database/sql"

- "strings"

-

- errorhandler "sorcia/error"

- "sorcia/setting"

-)

-

-// CreateAccount ...

-func CreateAccount(db *sql.DB) {

- stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS account (id INTEGER PRIMARY KEY, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, jwt_token TEXT NOT NULL, can_create_repo BOOLEAN DEFAULT 0, is_admin BOOLEAN DEFAULT 0)")

- errorhandler.CheckError("Error on model create account", err)

-

- _, err = stmt.Exec()

- errorhandler.CheckError("Error on model create account exec", err)

-}

-

-// CreateAccountStruct struct

-type CreateAccountStruct struct {

- Username string

- PasswordHash string

- Token string

- CanCreateRepo int

- IsAdmin int

-}

-

-// InsertAccount ...

-func InsertAccount(db *sql.DB, cas CreateAccountStruct) {

- stmt, err := db.Prepare("INSERT INTO account (username, password_hash, jwt_token, can_create_repo, is_admin) VALUES (?, ?, ?, ?, ?)")

- errorhandler.CheckError("Error on model insert account", err)

-

- _, err = stmt.Exec(cas.Username, cas.PasswordHash, cas.Token, cas.CanCreateRepo, cas.IsAdmin)

- errorhandler.CheckError("Error on model insert account exec", err)

-}

-

-// RevokeCanCreateRepo ...

-func RevokeCanCreateRepo(db *sql.DB, username string) {

- stmt, err := db.Prepare("UPDATE account SET can_create_repo = ? WHERE username = ?")

- errorhandler.CheckError("Error on model revoke can create repo", err)

-

- _, err = stmt.Exec(false, username)

- errorhandler.CheckError("Error on model revoke can create repo exec", err)

-}

-

-// AddCanCreateRepo ...

-func AddCanCreateRepo(db *sql.DB, username string) {

- stmt, err := db.Prepare("UPDATE account SET can_create_repo = ? WHERE username = ?")

- errorhandler.CheckError("Error on model revoke can create repo", err)

-

- _, err = stmt.Exec(true, username)

- errorhandler.CheckError("Error on model revoke can create repo exec", err)

-}

-

-type Users struct {

- Users []User

-}

-

-type User struct {

- Username string

- CanCreateRepo bool

- IsAdmin bool

-}

-

-// GetAllUsers

-func GetAllUsers(db *sql.DB) Users {

- rows, err := db.Query("SELECT username, can_create_repo, is_admin FROM account")

- errorhandler.CheckError("Error on model get all users", err)

-

- var user User

- var users Users

-

- for rows.Next() {

- err = rows.Scan(&user.Username, &user.CanCreateRepo, &user.IsAdmin)

- errorhandler.CheckError("Error on model get all users rows scan", err)

-

- users.Users = append(users.Users, user)

- }

- rows.Close()

-

- return users

-}

-

-// CheckifUserCanCreateRepo ...

-func CheckifUserCanCreateRepo(db *sql.DB, userID int) bool {

- rows, err := db.Query("SELECT can_create_repo FROM account WHERE id = ?", userID)

- errorhandler.CheckError("Error on model check if user can create repo", err)

-

- var canCreateRepo bool

-

- if rows.Next() {

- err = rows.Scan(&canCreateRepo)

- errorhandler.CheckError("Error on model check if user can create repo rows scan", err)

- }

- rows.Close()

-

- return canCreateRepo

-}

-

-// CheckifUserCanCreateRepo ...

-func CheckifUserIsAnAdmin(db *sql.DB, userID int) bool {

- rows, err := db.Query("SELECT is_admin FROM account WHERE id = ?", userID)

- errorhandler.CheckError("Error on model check if user is an admin", err)

-

- var isAdmin bool

-

- if rows.Next() {

- err = rows.Scan(&isAdmin)

- errorhandler.CheckError("Error on model check if user is an admin rows scan", err)

- }

- rows.Close()

-

- return isAdmin

-}

-

-// GetUserIDFromToken ...

-func GetUserIDFromToken(db *sql.DB, token string) int {

- rows, err := db.Query("SELECT id FROM account WHERE jwt_token = ?", token)

- errorhandler.CheckError("Error on model get userid from token", err)

-

- var userID int

-

- if rows.Next() {

- err = rows.Scan(&userID)

- errorhandler.CheckError("Error on model get userid from token rows scan", err)

- }

- rows.Close()

-

- return userID

-}

-

-// GetUsernameFromToken ...

-func GetUsernameFromToken(db *sql.DB, token string) string {

- rows, err := db.Query("SELECT username FROM account WHERE jwt_token = ?", token)

- errorhandler.CheckError("Error on model get username from token", err)

-

- var username string

-

- if rows.Next() {

- err = rows.Scan(&username)

- errorhandler.CheckError("Error on model get username from token row scan", err)

- }

- rows.Close()

-

- return username

-}

-

-// GetUsernameFromUserID ...

-func GetUsernameFromUserID(db *sql.DB, userID int) string {

- rows, err := db.Query("SELECT username FROM account WHERE id = ?", userID)

- errorhandler.CheckError("Error on model get username from userid", err)

-

- var username string

-

- if rows.Next() {

- err = rows.Scan(&username)

- errorhandler.CheckError("Error on model get username from userid rows scan", err)

- }

- rows.Close()

-

- return username

-}

-

-// GetUserIDFromUsername ...

-func GetUserIDFromUsername(db *sql.DB, username string) int {

- rows, err := db.Query("SELECT id FROM account WHERE username = ?", username)

- errorhandler.CheckError("Error on model get userid from username", err)

-

- var userID int

-

- if rows.Next() {

- err = rows.Scan(&userID)

- errorhandler.CheckError("Error on model get userid from username rows scan", err)

- }

- rows.Close()

-

- return userID

-}

-

-// SelectPasswordHashAndJWTTokenStruct struct

-type SelectPasswordHashAndJWTTokenStruct struct {

- Username string

-}

-

-// SelectPasswordHashAndJWTTokenResponse struct

-type SelectPasswordHashAndJWTTokenResponse struct {

- PasswordHash string

- Token string

-}

-

-// SelectPasswordHashAndJWTToken ...

-func SelectPasswordHashAndJWTToken(db *sql.DB, sphjwt SelectPasswordHashAndJWTTokenStruct) *SelectPasswordHashAndJWTTokenResponse {

- // Search for username in the 'account' table with the given string

- rows, err := db.Query("SELECT password_hash, jwt_token FROM account WHERE username = ?", sphjwt.Username)

- errorhandler.CheckError("Error on model select password hash and jwt token", err)

-

- var sphjwtr SelectPasswordHashAndJWTTokenResponse

-

- if rows.Next() {

- err = rows.Scan(&sphjwtr.PasswordHash, &sphjwtr.Token)

- errorhandler.CheckError("Error on model select password hash and jwt token rows scan", err)

- }

- rows.Close()

-

- return &sphjwtr

-}

-

-// CheckIfFirstUserExists ...

-func CheckIfFirstUserExists(db *sql.DB) bool {

- rows, err := db.Query("SELECT username from account WHERE id = ?", 1)

- errorhandler.CheckError("Error on model check if first user exists", err)

-

- var username string

- userExists := false

-

- if rows.Next() {

- err = rows.Scan(&username)

- errorhandler.CheckError("Error on model check if first user exists rows scan", err)

- }

- rows.Close()

-

- if username != "" {

- userExists = true

- }

-

- return userExists

-}

-

-// ResetUsernameByUserID ...

-func ResetUsernameByUserID(db *sql.DB, newUsername string, userID int) {

- stmt, err := db.Prepare("UPDATE account SET username = ? WHERE id = ?")

- errorhandler.CheckError("Error on model reset username by userID", err)

-

- _, err = stmt.Exec(newUsername, userID)

- errorhandler.CheckError("Error on model reset username by userID exec", err)

-}

-

-// ResetUserPasswordbyUsernameStruct struct

-type ResetUserPasswordbyUsernameStruct struct {

- PasswordHash string

- JwtToken string

- Username string

-}

-

-// ResetUserPasswordbyUsername ...

-func ResetUserPasswordbyUsername(db *sql.DB, resetPass ResetUserPasswordbyUsernameStruct) {

- stmt, err := db.Prepare("UPDATE account SET password_hash = ?, jwt_token = ? WHERE username = ?")

- errorhandler.CheckError("Error on model reset user password by username", err)

-

- _, err = stmt.Exec(resetPass.PasswordHash, resetPass.JwtToken, resetPass.Username)

- errorhandler.CheckError("Error on model reset user password by username exec", err)

-}

-

-// DeleteUserbyUsername ...

-func DeleteUserbyUsername(db *sql.DB, username string) {

- stmt, err := db.Prepare("DELETE FROM account WHERE username = ?")

- errorhandler.CheckError("Error on model delete user by username", err)

-

- _, err = stmt.Exec(username)

- errorhandler.CheckError("Error on model delete user by username exec", err)

-}

-

-// CreateSSHPubKey ...

-func CreateSSHPubKey(db *sql.DB) {

- stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS ssh (id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, title TEXT NOT NULL, authorized_key TEXT UNIQUE NOT NULL, fingerprint TEXT UNIQUE NOT NULL, FOREIGN KEY (user_id) REFERENCES account (id) ON DELETE CASCADE)")

- errorhandler.CheckError("Error on model create ssh pub key", err)

-

- _, err = stmt.Exec()

- errorhandler.CheckError("Error on model create ssh pub key exec", err)

-}

-

-// InsertSSHPubKey struct

-type InsertSSHPubKeyStruct struct {

- AuthKey string

- Title string

- Fingerprint string

- UserID int

-}

-

-// InsertRepo ...

-func InsertSSHPubKey(db *sql.DB, ispk InsertSSHPubKeyStruct) {

- stmt, err := db.Prepare("INSERT INTO ssh (user_id, title, authorized_key, fingerprint) VALUES (?, ?, ?, ?)")

- errorhandler.CheckError("Error on model insert ssh pub key", err)

-

- _, err = stmt.Exec(ispk.UserID, ispk.Title, ispk.AuthKey, ispk.Fingerprint)

- errorhandler.CheckError("Error on model insert ssh pub key exec", err)

-}

-

-// DeleteMetaKeyByID ...

-func DeleteMetaKeyByID(db *sql.DB, id int) {

- stmt, err := db.Prepare("DELETE FROM ssh WHERE id = ?")

- errorhandler.CheckError("Error on model delete meta key by id", err)

-

- _, err = stmt.Exec(id)

- errorhandler.CheckError("Error on model delete meta key by id exec", err)

-}

-

-// SSHKeysResponse struct

-type SSHKeysResponse struct {

- SSHKeys []SSHDetail

-}

-

-// SSHDetail struct

-type SSHDetail struct {

- ID int

- Title string

- Fingerprint string

-}

-

-// GetSSHKeysFromUserID ...

-func GetSSHKeysFromUserId(db *sql.DB, userID int) *SSHKeysResponse {

- rows, err := db.Query("SELECT id, title, fingerprint FROM ssh WHERE user_id = ?", userID)

- errorhandler.CheckError("Error on model get ssh key from userid", err)

-

- var sdr SSHDetail

- var skr SSHKeysResponse

-

- for rows.Next() {

- err = rows.Scan(&sdr.ID, &sdr.Title, &sdr.Fingerprint)

- errorhandler.CheckError("Error on model get ssh key from userid rows scan", err)

-

- skr.SSHKeys = append(skr.SSHKeys, sdr)

- }

- rows.Close()

-

- return &skr

-}

-

-type SSHAllAuthKeysResponse struct {

- UserIDs []string

- AuthKeys []string

-}

-

-// GetSSHAllAuthKeys ...

-func GetSSHAllAuthKeys(db *sql.DB) *SSHAllAuthKeysResponse {

- rows, err := db.Query("SELECT user_id, authorized_key FROM ssh")

- errorhandler.CheckError("Error on model get ssh all auth keys", err)

-

- var userID, authKey string

- var userIDs, authKeys []string

-

- for rows.Next() {

- err = rows.Scan(&userID, &authKey)

- errorhandler.CheckError("Error on model get ssh all auth keys rows scan", err)

-

- userIDs = append(userIDs, userID)

- authKeys = append(authKeys, authKey)

- }

- rows.Close()

-

- saks := &SSHAllAuthKeysResponse{

- userIDs,

- authKeys,

- }

-

- return saks

-}

-

-// CreateSiteSettings ...

-func CreateSiteSettings(db *sql.DB) {

- stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS site_settings (id INTEGER PRIMARY KEY, title TEXT NOT NULL, favicon TEXT, logo TEXT, logo_width TEXT, logo_height TEXT, style TEXT DEFAULT 'default')")

- errorhandler.CheckError("Error on model create site", err)

-

- _, err = stmt.Exec()

- errorhandler.CheckError("Error on model create site exec", err)

-}

-

-// CreateSiteSettingsStruct struct

-type CreateSiteSettingsStruct struct {

- Title string

- Favicon string

- Logo string

- LogoWidth string

- LogoHeight string

- Style string

-}

-

-// InsertSiteSettings ...

-func InsertSiteSettings(db *sql.DB, css CreateSiteSettingsStruct) {

- stmt, err := db.Prepare("INSERT INTO site_settings (title, favicon, logo, logo_width, logo_height, style) VALUES (?, ?, ?, ?, ?, ?)")

- errorhandler.CheckError("Error on model insert site", err)

-

- _, err = stmt.Exec(css.Title, css.Favicon, css.Logo, css.LogoWidth, css.LogoHeight, css.Style)

- errorhandler.CheckError("Error on model insert site exec", err)

-}

-

-// CheckIFSiteSettingsExists ...

-func CheckIFSiteSettingsExists(db *sql.DB) bool {

- rows, err := db.Query("SELECT title FROM site_settings WHERE id = ?", 1)

- errorhandler.CheckError("Error on model check if site settings exists", err)

-

- var title string

- isExists := false

-

- if rows.Next() {

- err = rows.Scan(&title)

- errorhandler.CheckError("Error on model check if site_settings settings exists rows scan", err)

- }

- rows.Close()

-

- if title != "" {

- isExists = true

- }

-

- return isExists

-}

-

-type GetSiteSettingsResponse struct {

- Title string

- Favicon string

- Logo string

- LogoWidth string

- LogoHeight string

- Style string

-}

-

-// GetSiteSettings ...

-func GetSiteSettings(db *sql.DB, conf *setting.BaseStruct) *GetSiteSettingsResponse {

- rows, err := db.Query("SELECT title, favicon, logo, logo_width, logo_height, style FROM site_settings WHERE id = ?", 1)

- errorhandler.CheckError("Error on model get site settings", err)

-

- var title, favicon, logo, logoWidth, logoHeight, style string

- gssr := GetSiteSettingsResponse{}

-

- if rows.Next() {

- err = rows.Scan(&title, &favicon, &logo, &logoWidth, &logoHeight, &style)

- errorhandler.CheckError("Error on model get site_settings settings rows scan", err)

-

- faviconSplit := strings.Split(favicon, conf.Paths.UploadAssetPath)

- if len(faviconSplit) > 1 {

- favicon = faviconSplit[1]

- }

-

- logoSplit := strings.Split(logo, conf.Paths.UploadAssetPath)

- if len(logoSplit) > 1 {

- logo = logoSplit[1]

- }

-

- gssr = GetSiteSettingsResponse{

- Title: title,

- Favicon: favicon,

- Logo: logo,

- LogoWidth: logoWidth,

- LogoHeight: logoHeight,

- Style: style,

- }

- }

- rows.Close()

-

- return &gssr

-}

-

-// GetSiteStyle ...

-func GetSiteStyle(db *sql.DB) string {

- rows, err := db.Query("SELECT style FROM site_settings WHERE id = ?", 1)

- errorhandler.CheckError("Error on model get site style", err)

-

- style := "default"

- if rows.Next() {

- err = rows.Scan(&style)

- errorhandler.CheckError("Error on model get site style rows scan", err)

- }

- rows.Close()

-

- return style

-}

-

-// GetSiteFavicon

-func GetSiteFavicon(db *sql.DB) string {

- rows, err := db.Query("SELECT favicon FROM site_settings WHERE id = ?", 1)

- errorhandler.CheckError("Error on model get site favicon", err)

-

- var favicon string

- if rows.Next() {

- err = rows.Scan(&favicon)

- errorhandler.CheckError("Error on model get site favicon rows scan", err)

- }

- rows.Close()

-

- return favicon

-}

-

-// GetSiteLogo

-func GetSiteLogo(db *sql.DB) string {

- rows, err := db.Query("SELECT logo FROM site_settings WHERE id = ?", 1)

- errorhandler.CheckError("Error on model get site logo", err)

-

- var logo string

- if rows.Next() {

- err = rows.Scan(&logo)

- errorhandler.CheckError("Error on model get site logo rows scan", err)

- }

- rows.Close()

-

- return logo

-}

-

-// UpdateSiteTitle ...

-func UpdateSiteTitle(db *sql.DB, title string) {

- stmt, err := db.Prepare("UPDATE site_settings SET title = ? WHERE id = 1")

- errorhandler.CheckError("Error on model update site title", err)

-

- _, err = stmt.Exec(title)

- errorhandler.CheckError("Error on model update site title exec", err)

-}

-

-// UpdateSiteFavicon ...

-func UpdateSiteFavicon(db *sql.DB, favicon string) {

- stmt, err := db.Prepare("UPDATE site_settings SET favicon = ? WHERE id = 1")

- errorhandler.CheckError("Error on model update site favicon", err)

-

- _, err = stmt.Exec(favicon)

- errorhandler.CheckError("Error on model update site favicon exec", err)

-}

-

-// UpdateSiteLogo ...

-func UpdateSiteLogo(db *sql.DB, logo, logoWidth, logoHeight string) {

- stmt, err := db.Prepare("UPDATE site_settings SET logo = ? WHERE id = 1")

- errorhandler.CheckError("Error on model update site logo", err)

-

- _, err = stmt.Exec(logo)

- errorhandler.CheckError("Error on model update site logo exec", err)

-}

-

-// UpdateSiteStyle ...

-func UpdateSiteStyle(db *sql.DB, style string) {

- stmt, err := db.Prepare("UPDATE site_settings SET style = ? WHERE id = 1")

- errorhandler.CheckError("Error on model update site style", err)

-

- _, err = stmt.Exec(style)

- errorhandler.CheckError("Error on model update site style exec", err)

-}

@@ -1,396 +0,0 @@

-package model

-

-import (

- "database/sql"

-

- errorhandler "sorcia/error"

-)

-

-// CreateRepo ...

-func CreateRepo(db *sql.DB) {

- stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS repository (id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, name TEXT UNIQUE NOT NULL, description TEXT, is_private BOOLEAN DEFAULT 0, FOREIGN KEY (user_id) REFERENCES account (id) ON DELETE CASCADE)")

- errorhandler.CheckError("Error on model create repo", err)

-

- _, err = stmt.Exec()

- errorhandler.CheckError("Error on model create repo exec", err)

-}

-

-// CreateRepoStruct struct

-type CreateRepoStruct struct {

- Name string

- Description string

- IsPrivate int

- UserID int

-}

-

-// InsertRepo ...

-func InsertRepo(db *sql.DB, crs CreateRepoStruct) {

- stmt, err := db.Prepare("INSERT INTO repository (user_id, name, description, is_private) VALUES (?, ?, ?, ?)")

- errorhandler.CheckError("Error on model insert repo", err)

-

- _, err = stmt.Exec(crs.UserID, crs.Name, crs.Description, crs.IsPrivate)

- errorhandler.CheckError("Error on model insert repo exec", err)

-}

-

-// DeleteRepobyReponame ...

-func DeleteRepobyReponame(db *sql.DB, reponame string) {

- stmt, err := db.Prepare("DELETE FROM repository WHERE name = ?")

- errorhandler.CheckError("Error on model delete repository by reponame", err)

-

- _, err = stmt.Exec(reponame)

- errorhandler.CheckError("Error on model delete repository by reponame exec", err)

-}

-

-// UpdateRepoStruct struct

-type UpdateRepoStruct struct {

- RepoID int

- NewName string

- Description string

- IsPrivate int

-}

-

-// UpdateRepo ...

-func UpdateRepo(db *sql.DB, urs UpdateRepoStruct) {

- stmt, err := db.Prepare("UPDATE repository SET name = ?, description = ?, is_private = ? WHERE id = ?")

- errorhandler.CheckError("Error on model update repo", err)

-

- _, err = stmt.Exec(urs.NewName, urs.Description, urs.IsPrivate, urs.RepoID)

- errorhandler.CheckError("Error on model update repo exec", err)

-}

-

-// CreateRepoMembers ...

-func CreateRepoMembers(db *sql.DB) {

- stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS repository_members (id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, repo_id INTEGER NOT NULL, permission TEXT NOT NULL, FOREIGN KEY (repo_id) REFERENCES repository (id) ON DELETE CASCADE)")

- errorhandler.CheckError("Error on model create repo members", err)

-

- _, err = stmt.Exec()

- errorhandler.CheckError("Error on model create repo members exec", err)

-}

-

-// CreateRepoMember struct

-type CreateRepoMember struct {

- UserID int

- RepoID int

- Permission string

-}

-

-// InsertRepoMember ...

-func InsertRepoMember(db *sql.DB, crm CreateRepoMember) {

- stmt, err := db.Prepare("INSERT INTO repository_members (user_id, repo_id, permission) VALUES (?, ?, ?)")

- errorhandler.CheckError("Error on model insert repo member", err)

-

- _, err = stmt.Exec(crm.UserID, crm.RepoID, crm.Permission)

- errorhandler.CheckError("Error on model insert repo member exec", err)

-}

-

-// RemoveRepoMember ...

-func RemoveRepoMember(db *sql.DB, userID, repoID int) {

- stmt, err := db.Prepare("DELETE FROM repository_members WHERE user_id = ? AND repo_id = ?")

- errorhandler.CheckError("Error on model remove repo member", err)

-

- _, err = stmt.Exec(userID, repoID)

- errorhandler.CheckError("Error on model remove repo member exec", err)

-}

-

-// GetRepoMembersStruct struct

-type GetRepoMembersStruct struct {

- RepoMembers []RepoMember

-}

-

-// RepoMember struct

-type RepoMember struct {

- UserID int

- Username string

- Permission string

- IsOwner bool

-}

-

-// GetRepoMembers ...

-func GetRepoMembers(db *sql.DB, repoID int) GetRepoMembersStruct {

- rows, err := db.Query("SELECT user_id, permission FROM repository_members WHERE repo_id = ?", repoID)

- errorhandler.CheckError("Error on model get repos members", err)

-

- var rm RepoMember

- var grms GetRepoMembersStruct

-

- for rows.Next() {

- err := rows.Scan(&rm.UserID, &rm.Permission)

- errorhandler.CheckError("Error on model get repo members rows scan", err)

-

- rm.Username = GetUsernameFromUserID(db, rm.UserID)

- rm.IsOwner = false

-

- grms.RepoMembers = append(grms.RepoMembers, rm)

- }

- rows.Close()

-

- rows, err = db.Query("SELECT user_id FROM repository WHERE id = ?", repoID)

- errorhandler.CheckError("Error on model get repos members - repository", err)

-

- if rows.Next() {

- err := rows.Scan(&rm.UserID)

- errorhandler.CheckError("Error on model get repo members rows scan", err)

-

- rm.Username = GetUsernameFromUserID(db, rm.UserID)

- rm.Permission = "read/write"

- rm.IsOwner = true

-

- grms.RepoMembers = append(grms.RepoMembers, rm)

- }

- rows.Close()

-

- return grms

-}

-

-// GetRepoIDsOnRepoMembersUsingUserID ...

-func GetRepoIDsOnRepoMembersUsingUserID(db *sql.DB, userID int) []int {

- rows, err := db.Query("SELECT repo_id FROM repository_members WHERE user_id = ?", userID)

- errorhandler.CheckError("Error on model get repoids on repomembers using user id", err)

-

- var repoIDs []int

- var repoID int

- for rows.Next() {

- err := rows.Scan(&repoID)

- errorhandler.CheckError("Error on model get repoids on repomembers using user id rows scan", err)

-

- repoIDs = append(repoIDs, repoID)

- }

-

- return repoIDs

-}

-

-// GetRepoMemberIDFromUserID ...

-func GetRepoMemberIDFromUserID(db *sql.DB, userID int) []int {

- rows, err := db.Query("SELECT id FROM repository_members WHERE user_id = ?", userID)

- errorhandler.CheckError("Error on model get repos members id from user id", err)

-

- var repoMembersID []int

- var repoMemberID int

-

- for rows.Next() {

- err := rows.Scan(&repoMemberID)

- errorhandler.CheckError("Error on model get repo members id from user id rows scan", err)

-

- repoMembersID = append(repoMembersID, repoMemberID)

- }

- rows.Close()

-

- return repoMembersID

-}

-

-// DeleteRepoMemberByID ...

-func DeleteRepoMemberByID(db *sql.DB, id int) {

- stmt, err := db.Prepare("DELETE FROM repository_members WHERE id = ?")

- errorhandler.CheckError("Error on model delete repository_member by id", err)

-

- _, err = stmt.Exec(id)

- errorhandler.CheckError("Error on model delete repository_member by id exec", err)

-}

-

-// GetReposStruct struct

-type GetReposStruct struct {

- Repositories []RepoDetailStruct

-}

-

-// ReposDetailStruct struct

-type RepoDetailStruct struct {

- ID int

- Name string

- Description string

- IsPrivate bool

- Permission string

-}

-

-// GetReposFromUserID ...

-func GetReposFromUserID(db *sql.DB, userID int) GetReposStruct {

- rows, err := db.Query("SELECT id, name, description, is_private FROM repository WHERE user_id = ?", userID)

- errorhandler.CheckError("Error on model get repos from user id", err)

-

- var grfur GetReposStruct

- var rds RepoDetailStruct

-

- for rows.Next() {

- err = rows.Scan(&rds.ID, &rds.Name, &rds.Description, &rds.IsPrivate)

- errorhandler.CheckError("Error on model get repos from user id rows scan", err)

-

- rds.Permission = "read/write"

-

- grfur.Repositories = append(grfur.Repositories, rds)

- }

- rows.Close()

-

- return grfur

-}

-

-// GetReposFromRepoID ...

-func GetRepoFromRepoID(db *sql.DB, repoID int) RepoDetailStruct {

- rows, err := db.Query("SELECT id, name, description, is_private FROM repository WHERE id = ?", repoID)

- errorhandler.CheckError("Error on model get repos from user id", err)

-

- var rds RepoDetailStruct

-

- for rows.Next() {

- err = rows.Scan(&rds.ID, &rds.Name, &rds.Description, &rds.IsPrivate)

- errorhandler.CheckError("Error on model get repos from user id rows scan", err)

- }

- rows.Close()

-

- return rds

-}

-

-// GetAllPublicRepos ...

-func GetAllPublicRepos(db *sql.DB) GetReposStruct {

- rows, err := db.Query("SELECT id, name, description FROM repository WHERE is_private = ?", false)

- errorhandler.CheckError("Error on model get all public repos", err)

-

- var grfur GetReposStruct

- var rds RepoDetailStruct

-

- for rows.Next() {

- err = rows.Scan(&rds.ID, &rds.Name, &rds.Description)

- errorhandler.CheckError("Error on model get all public repos rows scan", err)

-

- grfur.Repositories = append(grfur.Repositories, rds)

- }

- rows.Close()

-

- return grfur

-}

-

-// GetRepoDescriptionFromRepoName ...

-func GetRepoDescriptionFromRepoName(db *sql.DB, reponame string) string {

- rows, err := db.Query("SELECT description FROM repository WHERE name = ?", reponame)

- errorhandler.CheckError("Error on model get repo description from reponame", err)

-

- var repoDescription string

- if rows.Next() {

- err = rows.Scan(&repoDescription)

- errorhandler.CheckError("Error on model get repo description from reponame rows scan", err)

- }

- rows.Close()

-

- return repoDescription

-}

-

-// GetRepoIDFromReponame ...

-func GetRepoIDFromReponame(db *sql.DB, reponame string) int {

- rows, err := db.Query("SELECT id FROM repository WHERE name = ?", reponame)

- errorhandler.CheckError("Error on model get repo id from reponame", err)

-

- var repoID int

- if rows.Next() {

- err = rows.Scan(&repoID)

- errorhandler.CheckError("Error on model get repo id from reponame rows scan", err)

- }

- rows.Close()

-

- return repoID

-}

-

-// CheckRepoExists ...

-func CheckRepoExists(db *sql.DB, reponame string) bool {

- rows, err := db.Query("SELECT id FROM repository WHERE name = ?", reponame)

- errorhandler.CheckError("Error on model check repo exists", err)

-

- var repoID int

-

- if rows.Next() {

- err = rows.Scan(&repoID)

- errorhandler.CheckError("Error on model check repo exists rows scan", err)

- }

- rows.Close()

-

- if repoID != 0 {

- return true

- }

-

- return false

-}

-

-// GetRepoType ...

-func GetRepoType(db *sql.DB, reponame string) bool {

- rows, err := db.Query("SELECT is_private FROM repository WHERE name = ?", reponame)

- errorhandler.CheckError("Error on model get repo type", err)

-

- var isPrivate bool

-

- if rows.Next() {

- err = rows.Scan(&isPrivate)

- errorhandler.CheckError("Error on model get repo type rows scan", err)

- }

- rows.Close()

-

- return isPrivate

-}

-

-// CheckRepoOwnerFromUserID ...

-func CheckRepoOwnerFromUserIDAndReponame(db *sql.DB, userID int, reponame string) bool {

- rows, err := db.Query("SELECT id FROM repository WHERE user_id = ? AND name = ?", userID, reponame)

- errorhandler.CheckError("Error on model check repo owner from userid and reponame", err)

-

- var id int

-

- if rows.Next() {

- err = rows.Scan(&id)

- errorhandler.CheckError("Error on model check repo owner from userid and reponame rows scan", err)

- }

- rows.Close()

-

- if id > 0 {

- return true

- }

-

- return false

-}

-

-// CheckRepoMemberExistFromUserIDAndRepoID ...

-func CheckRepoMemberExistFromUserIDAndRepoID(db *sql.DB, userID, repoID int) bool {

- rows, err := db.Query("SELECT id FROM repository_members WHERE user_id = ? AND repo_id = ?", userID, repoID)

- errorhandler.CheckError("Error on model check repo member exist from userid and repoid", err)

-

- var id int

-

- if rows.Next() {

- err = rows.Scan(&id)

- errorhandler.CheckError("Error on model check repo member exist from userid and repoid rows scan", err)

- }

- rows.Close()

-

- if id > 0 {

- return true

- }

-

- return false

-}

-

-// GetRepoMemberPermissionFromUserIDAndRepoID ...

-func GetRepoMemberPermissionFromUserIDAndRepoID(db *sql.DB, userID, repoID int) string {

- rows, err := db.Query("SELECT permission FROM repository_members WHERE user_id = ? AND repo_id = ?", userID, repoID)

- errorhandler.CheckError("Error on model check repo permissions from userid and repoid", err)

-

- var permission string

-

- if rows.Next() {

- err = rows.Scan(&permission)

- errorhandler.CheckError("Error on model check repo permissions from userid and repoid rows scan", err)

- }

- rows.Close()

-

- return permission

-}

-

-// GetUserIDFromReponame ...

-func GetUserIDFromReponame(db *sql.DB, reponame string) int {

- rows, err := db.Query("SELECT user_id FROM repository WHERE name = ?", reponame)

- errorhandler.CheckError("Error on model get userid from reponame", err)

-

- var userID int

-

- if rows.Next() {

- err = rows.Scan(&userID)

- errorhandler.CheckError("Error on model get userid from reponame rows scan", err)

- }

- rows.Close()

-

- return userID

-}

@@ -1,26 +0,0 @@

-package error

-

-import (

- "io"

- "log"

- "os"

-)

-

-// CheckError ...

-func CheckError(errMessage string, err error) {

- if err != nil {

- f, fError := os.OpenFile("./error.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm)

- if fError != nil {

- log.Fatalf("Error opening error.log file: %v", fError)

- }

- defer f.Close()

- wrt := io.MultiWriter(os.Stdout, f)

- log.SetOutput(wrt)

- log.Printf("%s: %v", errMessage, err)

- }

-}

-

-// Response struct

-type Response struct {

- Error string `json:"error"`

-}

@@ -1,148 +0,0 @@

-package util

-

-import (

- "bytes"

- "fmt"

- "log"

- "os"

- "os/exec"

- "path/filepath"

- "strings"

-

- errorhandler "sorcia/error"

-)

-

-func GetGitBranches(repoDir string) []string {

- var branches = []string{"master"}

-

- refPath := filepath.Join(repoDir, "refs", "heads")

-

- err := filepath.Walk(refPath, func(path string, info os.FileInfo, err error) error {

- branchName := info.Name()

- if branchName != "heads" && branchName != "master" {

- branches = append(branches, branchName)

- }

- return nil

- })

- errorhandler.CheckError("Error on util get git branches filepath walk", err)

-

- return branches

-}

-

-func GetGitTags(repoDir string) ([]string, int) {

- gitPath := GetGitBinPath()

-

- args := []string{"for-each-ref", "--sort=-taggerdate", "--format", "%(refname)", "refs/tags"}

- out := ForkExec(gitPath, args, repoDir)

-

- lines := strings.Fields(out)

-

- var tags []string

-

- for _, line := range lines {

- tags = append(tags, strings.Split(line, "/")[2])

- }

-

- return tags, len(tags)

-}

-

-// GenerateRefs

-func GenerateRefs(refsPath, repoPath, repoGitName string) {

- gitPath := GetGitBinPath()

-

- repoDir := filepath.Join(repoPath, repoGitName)

- tags, _ := GetGitTags(repoDir)

-

- // example.git -> example

- repoName := strings.TrimSuffix(repoGitName, ".git")

-

- for _, tag := range tags {

-

- tagname := tag

-

- // Remove 'v' prefix from version

- if strings.HasPrefix(tag, "v") {

- tagname = strings.Split(tag, "v")[1]

- }

-

- // Generate tar.gz file

- tarFilename := fmt.Sprintf("%s-%s.tar.gz", repoName, tagname)

- tarRefPath := filepath.Join(refsPath, tarFilename)

-

- if _, err := os.Stat(tarRefPath); os.IsNotExist(err) {

- args := []string{"archive", "--format=tar.gz", "-o", tarRefPath, tag}

- _ = ForkExec(gitPath, args, repoDir)

- }

-

- // Generate zip file

- zipFilename := fmt.Sprintf("%s-%s.zip", repoName, tagname)

- zipRefPath := filepath.Join(refsPath, zipFilename)

-

- if _, err := os.Stat(zipRefPath); os.IsNotExist(err) {

- args := []string{"archive", "--format=zip", "-o", zipRefPath, tag}

- _ = ForkExec(gitPath, args, repoDir)

- }

- }

-}

-

-// UpdateRefsWithNewName ...

-func UpdateRefsWithNewName(refsPath, repoPath, oldRepoGitName, newRepoGitName string) {

- if oldRepoGitName != newRepoGitName {

- refsPattern := filepath.Join(refsPath, oldRepoGitName+"*")

-

- files, err := filepath.Glob(refsPattern)

- errorhandler.CheckError("Error on updaterefspath filepath.Glob", err)

-

- for _, f := range files {

- err := os.Remove(f)

- errorhandler.CheckError("Error on removing ref files", err)

- }

-

- go GenerateRefs(refsPath, repoPath, newRepoGitName+".git")

- }

-}

-

-// GetCommitCounts ...

-func GetCommitCounts(repoPath, reponame string) string {

- dirPath := filepath.Join(repoPath, reponame+".git")

- gitPath := GetGitBinPath()

-

- args := []string{"rev-list", "--count", "HEAD"}

- out := ForkExec(gitPath, args, dirPath)

-

- return strings.TrimSpace(out)

-}

-

-// GetGitBinPath ...

-func GetGitBinPath() string {

- gitPath := "/usr/bin/git"

- if _, err := os.Stat(gitPath); err != nil {

- gitPath = "/bin/git"

- if _, err = os.Stat(gitPath); err != nil {

- gitPath = "/usr/local/bin/git"

- if _, err = os.Stat(gitPath); err != nil {

- fmt.Printf("Error: %v\n", err)

- os.Exit(1)

- }

- }

- }

-

- return gitPath

-}

-

-// ForkExec ...

-func ForkExec(legendArg string, restArgs []string, dirPath string) string {

- cmd := exec.Command(legendArg, restArgs...)

- cmd.Dir = dirPath

-

- var out, stderr bytes.Buffer

- cmd.Stderr = &stderr

- cmd.Stdout = &out

-

- err := cmd.Run()

- if err != nil {

- log.Printf(stderr.String())

- }

-

- return out.String()

-}

@@ -0,0 +1,85 @@

+package pkg

+

+import (

+ "crypto/md5"

+ "encoding/base64"

+ "fmt"

+ "log"

+ "os"

+ "path/filepath"

+ "strings"

+)

+

+// IsAlnumOrHyphen ...

+func IsAlnumOrHyphen(s string) bool {

+ for _, r := range s {

+ if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0' || r > '9') && r != '-' {

+ return false

+ }

+ }

+ return true

+}

+

+// SSHFingerPrint ...

+func SSHFingerPrint(authKey string) string {

+ parts := strings.Fields(string(authKey))

+ if len(parts) < 2 {

+ log.Printf("bad key")

+ }

+

+ k, err := base64.StdEncoding.DecodeString(parts[1])

+ CheckError("Error on util ssh fingerprint decode string", err)

+

+ fp := md5.Sum([]byte(k))

+ var fingerPrint string

+ for i, b := range fp {

+ fingerPrint = fmt.Sprintf("%s%02x", fingerPrint, b)

+ if i < len(fp)-1 {

+ fingerPrint = fmt.Sprintf("%s:", fingerPrint)

+ }

+ }

+

+ return fingerPrint

+}

+

+// CreateDir ...

+func CreateDir(dir string) {

+ if _, err := os.Stat(dir); os.IsNotExist(err) {

+ err := os.MkdirAll(dir, os.ModePerm)

+ CheckError("Error on util create dir", err)

+ }

+}

+

+// CreateSSHDirAndGenerateKey ...

+func CreateSSHDirAndGenerateKey(sshPath string) {

+ if _, err := os.Stat(sshPath); os.IsNotExist(err) {

+ err := os.MkdirAll(sshPath, os.ModePerm)

+ CheckError("Error on util create ssh dir and generate ssh key", err)

+ }

+

+ keyPath := filepath.Join(sshPath, "id_rsa")

+ if _, err := os.Stat(keyPath); os.IsNotExist(err) {

+ args := []string{"-f", keyPath, "-t", "rsa", "-m", "PEM", "-N", ""}

+ _ = ForkExec("ssh-keygen", args, ".")

+ }

+}

+

+// LimitCharLengthInString ...

+func LimitCharLengthInString(limitString string) string {

+ if len(limitString) > 50 {

+ limitString = fmt.Sprintf("%s...", string(limitString[:50]))

+ return limitString

+ }

+

+ return limitString

+}

+

+// ContainsValueInArr tells whether a contains x.

+func ContainsValueInArr(a []string, x string) bool {

+ for _, n := range a {

+ if x == n {

+ return true

+ }

+ }

+ return false

+}

@@ -1,81 +0,0 @@

-package setting

-

-import (

- "database/sql"

- "fmt"

- "os"

- "path"

-

- errorhandler "sorcia/error"

-

- // SQLite3 driver

- _ "github.com/mattn/go-sqlite3"

-

- "gopkg.in/ini.v1"

-)

-

-var conf BaseStruct

-

-// BaseStruct struct

-type BaseStruct struct {

- AppMode string

- Version string

- Paths PathsStruct

- Server ServerStruct

- DBConn *sql.DB

-}

-

-// PathsStruct struct

-type PathsStruct struct {

- ProjectRoot string

- RepoPath string

- RefsPath string

- DBPath string

- SSHPath string

- UploadAssetPath string

-}

-

-// ServerStruct struct

-type ServerStruct struct {

- HTTPPort string

- SSHPort string

-}

-

-func init() {

- cfg, err := ini.Load("config/app.ini")

- if err != nil {

- cfg, err = ini.Load("/home/git/sorcia/config/app.ini")

- if err != nil {

- fmt.Printf("Fail to read file: %v", err)

- os.Exit(1)

- }

- }

-

- conf = BaseStruct{

- AppMode: cfg.Section("").Key("app_mode").String(),

- Version: cfg.Section("").Key("version").String(),

- Paths: PathsStruct{

- ProjectRoot: cfg.Section("paths").Key("project_root").String(),

- RepoPath: cfg.Section("paths").Key("repo_path").String(),

- RefsPath: cfg.Section("paths").Key("refs_path").String(),

- DBPath: cfg.Section("paths").Key("db_path").String(),

- SSHPath: cfg.Section("paths").Key("ssh_path").String(),

- UploadAssetPath: cfg.Section("paths").Key("upload_asset_path").String(),

- },

- Server: ServerStruct{

- HTTPPort: cfg.Section("server").Key("http_port").String(),

- SSHPort: cfg.Section("server").Key("ssh_port").String(),

- },

- DBConn: nil,

- }

-

- db, err := sql.Open("sqlite3", path.Join(conf.Paths.DBPath, "sorcia.db?_foreign_keys=on"))

- errorhandler.CheckError("Error on opening sqlite3", err)

-

- conf.DBConn = db

-}

-

-// GetConf ...

-func GetConf() *BaseStruct {

- return &conf

-}

@@ -1,28 +0,0 @@

-{{define "title"}}Create repo{{end}}

-{{define "content"}}

-<main class="container create-repo">

- <form method="post" action="/create-repo" class="form create-repo__form">

- <div class="form__title">create new repository</div>

- <div class="create-repo__error">{{ .ReponameErrMessage }}</div>

- <div class="form__group">

- <label for="repoName">Name<i>*</i></label>

- <input type="text" class="form__input" id="repoName" name="name" maxlength="100" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <div class="form__group">

- <label for="repoDescription">Description</label>

- <input type="text" class="form__input" id="repoDescription" name="description" autocomplete="off" spellcheck="false" />

- </div>

- <div class="form__group form__radio-group">

- <div class="form__radio">

- <input type="radio" name="is_private" value="0" id="repoPublic" checked />

- <label for="repoPublic">Public</label>

- </div>

- <div class="form__radio">

- <input type="radio" name="is_private" value="1" id="repoPrivate" />

- <label for="repoPrivate">Private</label>

- </div>

- </div>

- <input type="submit" class="button button--primary" value="Create" />

- </form>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,72 +0,0 @@

-{{define "title"}}{{ .Reponame }} - File viewer{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item repo__menu__item--active">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{if .IsLoggedIn}}

- {{if .RepoAccess}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- {{end}}

- </div>

- {{if .IsRepoBranch}}

- <div class="repo__sub-menu">

- <div class="repo__sub-menu__item branch">

- <form method="get" action="" class="form">

- <div class="form__group">

- <label for="branchSelect">branch:</label>

- <select id="branchSelect" onchange="branchChange(this.value)">

- {{range .RepoBranches}}

- <option value="{{.}}">{{.}}</option>

- {{end}}

- </select>

- </div>

- </form>

- </div>

- </div>

- {{end}}

- <div class="path">

- {{if .RepoDetail.PathEmpty}}

- {{else}}

- <p>path:</p>

- <div>{{.RepoDetail.LegendPath}}</div>

- {{end}}

- </div>

- <div class="file-viewer">

- {{.RepoDetail.FileContent}}

- </div>

- <script src="/public/js/branch-selection.js"></script>

- {{if eq .SiteStyle "dark"}}

- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/railscasts.min.css">

- {{else}}

- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/github.min.css">

- {{end}}

- <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>

- <script src="//cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.7.0/highlightjs-line-numbers.min.js"></script>

- <script src="/public/js/codelines-selection.js"></script>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,5 +0,0 @@

-{{define "footer"}}

-<footer class="footer">

- powered by <a href="https://sorcia.mysticmode.org">sorcia</a> [v{{.SorciaVersion}}]

-</footer>

-{{end}}

\ No newline at end of file

@@ -1,67 +0,0 @@

-{{define "favicon"}}

- {{if .SiteSettings.IsSiteFavicon}}

- <link rel="icon" type="image/{{.SiteSettings.SiteFaviconExt}}" href="/uploads{{.SiteSettings.SiteFavicon}}" />

- {{else}}

- <link rel="icon" type="image/{{.SiteSettings.SiteFaviconExt}}" href="/public/img/sorcia_favicon.png" />

- {{end}}

-{{end}}

-{{define "style"}}

- {{if eq .SiteSettings.SiteStyle "classic"}}

- <link rel="stylesheet" href="/public/css/style_classic.min.css" />

- {{else if eq .SiteSettings.SiteStyle "dark"}}

- <link rel="stylesheet" href="/public/css/style_dark.min.css" />

- {{else}}

- <link rel="stylesheet" href="/public/css/style.min.css" />

- {{end}}

-{{end}}

-{{define "header"}}

- {{if .IsLoggedIn}}

- <header class="header">

- <div class="header__left">

- <a href="/" class="header__logo">

- {{if .SiteSettings.IsSiteLogo}}

- {{if .SiteSettings.IsSiteLogoSVG}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" />

- <!-- {{.SiteSettings.SVGDAT}} -->

- {{else}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" width="{{.SiteSettings.SiteLogoWidth}}px" height="{{.SiteSettings.SiteLogoHeight}}px" />

- {{end}}

- {{else}}

- <img src="/public/img/sorcia.svg" width="81px" height="18px" />

- {{end}}

- </a>

- </div>

- <div class="header__right">

- {{if eq .HeaderActiveMenu "meta"}}

- <a href="/meta" class="header__right__item header__right__item--active">meta</a>

- <a href="/logout" class="header__right__item">logout</a>

- {{else}}

- <a href="/meta" class="header__right__item">meta</a>

- <a href="/logout" class="header__right__item">logout</a>

- {{end}}

- </div>

- </header>

- {{else}}

- <header class="header">

- <div class="header__left">

- <a href="/" class="header__logo">

- {{if .SiteSettings.IsSiteLogo}}

- {{if .SiteSettings.IsSiteLogoSVG}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" />

- <!-- {{.SiteSettings.SVGDAT}} -->

- {{else}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" width="{{.SiteSettings.SiteLogoWidth}}px" height="{{.SiteSettings.SiteLogoHeight}}px" />

- {{end}}

- {{else}}

- <img src="/public/img/sorcia.svg" width="81px" height="18px" />

- {{end}}

- </a>

- </div>

- {{if .ShowLoginMenu}}

- <div class="header__right">

- <a href="/login" class="header__right__item">login</a>

- </div>

- {{end}}

- </header>

- {{end}}

-{{end}}

\ No newline at end of file

@@ -1,54 +0,0 @@

-{{define "title"}}

- {{if .SiteSettings.IsSiteTitle}}

- {{.SiteSettings.SiteTitle}}

- {{else}}

- sorcia - Self-hosted web frontend for git repositories written in Go

- {{end}}

-{{end}}

-{{define "content"}}

-<main class="container git">

- {{if .IsLoggedIn}}

- {{if .CanCreateRepo}}

- <div class="container__info">

- <div class="container__info__top">

- <a href="/create-repo" class="button button--primary">Create new repository</a>

- </div>

- </div>

- {{end}}

- <div class="git__repos">

- <div class="git__repos__title">repositories</div>

- <ul class="repos">

- {{range .Repos.Repositories}}

- <li>

- <a href="/r/{{.Name}}">

- <p>{{.Name}}</p>

- {{if .IsPrivate}}<i>private</i>{{end}}

- {{if eq .Permission "read"}}<i>read</i>{{end}}

- {{if eq .Permission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsPrivate}}

- {{if eq .Permission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- </a>

- <p>{{.Description}}</p>

- </li>

- {{end}}

- </ul>

- </div>

- {{else}}

- <div class="git__repos" style="width: 100%;">

- <div class="git__repos__title">repositories</div>

- <ul class="repos">

- {{range .Repos.Repositories}}

- <li>

- <a href="/r/{{.Name}}">{{.Name}}</a>

- <p>{{.Description}}</p>

- </li>

- {{end}}

- </ul>

- </div>

- {{end}}

-</main>

-{{end}}

\ No newline at end of file

@@ -1,21 +0,0 @@

-{{define "layout"}}

-<!DOCTYPE html>

-<html lang="en">

-

-<head>

- <meta charset="UTF-8">

- <meta name="viewport" content="width=device-width, initial-scale=1.0">

- <meta http-equiv="X-UA-Compatible" content="ie=edge">

- {{template "favicon" .}}

- <title>{{template "title" .}}</title>

- {{template "style" .}}

-</head>

-

-<body>

- {{template "header" .}}

- {{template "content" .}}

- {{template "footer" .}}

-</body>

-

-</html>

-{{end}}

\ No newline at end of file

@@ -1,41 +0,0 @@

-{{define "title"}}

- {{if .SiteSettings.IsSiteTitle}}

- {{.SiteSettings.SiteTitle}}

- {{else}}

- sorcia - Self-hosted web frontend for git repositories written in git__repos

- {{end}}

-{{end}}

-{{define "content"}}

-<main class="container onboard">

- {{if .IsShowSignUp}}

- <form method="post" action="/login" class="onboard__form">

- <div class="onboard__form__title">create account</div>

- <div class="onboard__form__error">{{ .RegisterErrMessage }}</div>

- <div class="onboard__form__group">

- <label for="registerUsername">Username<i>*</i></label>

- <input type="text" class="onboard__form__input" id="registerUsername" name="username" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <div class="onboard__form__group">

- <label for="registerPassword">Password<i>*</i></label>

- <input type="password" class="onboard__form__input" id="registerPassword" name="password" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <input type="hidden" name="register" value="1" />

- <input type="submit" class="button button--primary" value="Create account" />

- </form>

- {{else}}

- <form method="post" action="/login" class="onboard__form">

- <div class="onboard__form__title">login</div>

- <div class="onboard__form__error">{{ .LoginErrMessage }}</div>

- <div class="onboard__form__group">

- <label for="loginUsername">Username<i>*</i></label>

- <input type="text" class="onboard__form__input" id="loginUsername" name="username" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <div class="onboard__form__group">

- <label for="loginPassword">Password<i>*</i></label>

- <input type="password" class="onboard__form__input" id="loginPassword" name="password" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <input type="submit" class="button button--primary" value="Login" />

- </form>

- {{end}}

-</main>

-{{end}}

\ No newline at end of file

@@ -1,36 +0,0 @@

-{{define "title"}}meta - Keys{{end}}

-{{define "content"}}

-<main class="container meta">

- <div class="repo__menu">

- <a href="/meta" class="repo__menu__item">general</a>

- <a href="" class="repo__menu__item repo__menu__item--active">keys</a>

- <a href="/meta/users" class="repo__menu__item">users</a>

- </div>

- <div class="meta__detail">

- <form class="form meta__detail__form" method="POST" action="/meta/keys">

- <div class="form__title">add new ssh key</div>

- <div class="form__group">

- <label for="sshTitle">Title<i>*</i></label>

- <input type="text" class="form__input" id="sshTitle" name="sshtitle" value="" autocomplete="off" spellcheck="false" required="required" />

- </div>

- <div class="form__group">

- <label for="sshKey">Key<i>*</i></label>

- <textarea name="sshkey" id="sshKey" required="required"></textarea>

- </div>

- <input type="submit" class="button button--primary" value="Save" />

- </form>

- <div class="meta__keys">

- <div class="meta__keys__title">your ssh keys</div>

- {{range .SSHKeys.SSHKeys}}

- <div class="meta__keys__item">

- <div>Title</div>

- <p>{{.Title}}</p>

- <div>Fingerprint</div>

- <p>{{.Fingerprint}}</p>

- <a href="/meta/keys/delete/{{.ID}}" class="button button--danger">Delete</a>

- </div>

- {{end}}

- </div>

- </div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,66 +0,0 @@

-{{define "title"}}meta - Users{{end}}

-{{define "content"}}

-<main class="container meta">

- <div class="repo__menu">

- <a href="/meta" class="repo__menu__item">general</a>

- <a href="/meta/keys" class="repo__menu__item">keys</a>

- <a href="" class="repo__menu__item repo__menu__item--active">users</a>

- </div>

- <div class="meta__detail">

- {{if .IsAdmin}}

- <form class="form meta__detail__form" method="POST" action="/meta/users">

- <div class="form__title">add new user</div>

- <div class="meta__detail__form__error">{{ .RegisterErrMessage }}</div>

- <div class="meta__error"></div>

- <div class="form__group">

- <label for="newUsername">Username<i>*</i></label>

- <input type="text" class="form__input" id="newUsername" name="username" value="" autocomplete="off" spellcheck="false"/>

- </div>

- <div class="form__group">

- <label for="newPassword">Password<i>*</i></label>

- <input type="password" class="form__input" id="newPassword" name="password" value="" autocomplete="off" spellcheck="false" />

- </div>

- <div class="form__group checkbox__group">

- <input type="checkbox" id="canCreateRepo" name="createrepo" value="yes" />

- <label for="canCreateRepo">Access to create repository</label>

- </div>

- <input type="submit" class="button button--primary" value="Save" />

- </form>

- {{end}}

- <div class="meta__users">

- <div class="meta__users__title">users</div>

- {{if .IsAdmin}}

- {{range .Users.Users}}

- <div class="meta__users__item">

- <div>Username {{if .IsAdmin}} [Admin] {{end}}</div>

- <p>{{.Username}}</p>

- {{if not .IsAdmin}}

- {{if .CanCreateRepo}}

- <p class="create-repo-access">This user can create repositories. <a onclick="return confirm('Are you sure, you want to revoke create repository access for this user?');" href="/meta/user/revoke-access/{{.Username}}" class="button button--danger">Revoke access</a></p>

- {{else}}

- <a href="/meta/user/add-access/{{.Username}}" class="button button--primary">Add create repo access</a>

- {{end}}

- {{else}}

- <p class="create-repo-access">This user is an admin, hence he can create repositories.</p>

- {{end}}

- </div>

- {{end}}

- {{else}}

- {{range .Users.Users}}

- <div class="meta__users__item">

- <div>Username {{if .IsAdmin}} [Admin] {{end}}</div>

- <p>{{.Username}}</p>

- {{if not .IsAdmin}}

- {{if .CanCreateRepo}}

- <p class="create-repo-access">This user can create repositories.</p>

- {{end}}

- {{else}}

- <p class="create-repo-access">This user is an admin, hence he can create repositories.</p>

- {{end}}

- </div>

- {{end}}

- {{end}}

- </div>

- </div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,111 +0,0 @@

-{{define "title"}}meta - General{{end}}

-{{define "content"}}

-<main class="container meta">

- <div class="repo__menu">

- <a href="" class="repo__menu__item repo__menu__item--active">general</a>

- <a href="/meta/keys" class="repo__menu__item">keys</a>

- <a href="/meta/users" class="repo__menu__item">users</a>

- </div>

- <div class="meta__detail">

- <form class="form meta__detail__form" method="POST" action="/meta/password">

- <div class="form__title">your profile</div>

- <div class="meta__error"></div>

- <div class="form__group">

- <label for="profileUsername">Username (You can't edit this - ask the server/sys admin to change username)</label>

- <input type="text" class="form__input" id="profileUsername" name="username" value="{{.Username}}" autocomplete="off" spellcheck="false" readonly="" />

- </div>

- <div class="form__group">

- <label for="profilePassword">Password (Type in your new password in order to update)<i>*</i></label>

- <input type="password" class="form__input" id="profilePassword" name="password" value="" autocomplete="off" spellcheck="false" required />

- </div>

- <input type="submit" class="button button--primary" value="Save" />

- </form>

- {{if .IsAdmin}}

- <form class="form meta__detail__form meta__detail__form--site-settings" method="POST" action="/meta/site" enctype="multipart/form-data">

- <div class="form__title">site settings</div>

- <div class="meta__detail__form__info">None of these form fields are mandatory, you can change any one of these or all of it below if you wish.</div>

- <div class="meta__error"></div>

- <div class="form__group">

- <label for="siteTitle">Title</label>

- {{if .SiteSettings.IsSiteTitle}}

- <input type="text" class="form__input" id="siteTitle" name="title" value="{{.SiteSettings.SiteTitle}}" autocomplete="off" spellcheck="false" />

- {{else}}

- <input type="text" class="form__input" id="siteTitle" name="title" value="sorcia - Self-hosted web frontend for git repositories written in Go" autocomplete="off" spellcheck="false" />

- {{end}}

- </div>

- <div class="form__group">

- <label for="siteFavicon">Favicon (Supports png/jpg formats. Max-size: 2 MB)</label>

- <div class="meta__detail__form__current">

- {{if .SiteSettings.IsSiteFavicon}}

- <div>Current favicon:</div>

- <img src="/uploads{{.SiteSettings.SiteFavicon}}" width="20px" height="20px" />

- {{end}}

- </div>

- <input type="file" class="form__input" id="siteFavicon" name="favicon" />

- </div>

- <div class="form__group">

- <label for="siteLogo">Logo (Supports svg/png/jpg formats. Max-height: 30px, Max-width: 200px. Max-size: 10 MB)</label>

- <div class="meta__detail__form__current">

- {{if .SiteSettings.IsSiteFavicon}}

- <div>Current logo:</div>

- {{if .SiteSettings.IsSiteLogoSVG}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" />

- <!-- {{.SiteSettings.SVGDAT}} -->

- {{else}}

- <img src="/uploads{{.SiteSettings.SiteLogo}}" width="{{.SiteSettings.SiteLogoWidth}}px" height="{{.SiteSettings.SiteLogoHeight}}px" />

- {{end}}

- {{end}}

- </div>

- <input type="file" class="form__input" id="siteLogo" name="logo" />

- </div>

- <div class="form__group">

- <label>Appearance</label>

- <div class="radio__group">

- {{if eq .SiteSettings.SiteStyle "classic"}}

- <div>

- <input type="radio" id="styleDefault" name="style" value="default" />

- <label for="styleDefault">Default</label>

- </div>

- <div>

- <input type="radio" id="styleClassic" name="style" value="classic" checked />

- <label for="styleClassic">Classic</label>

- </div>

- <div>

- <input type="radio" id="styleDark" name="style" value="dark" />

- <label for="styleDark">Dark</label>

- </div>

- {{else if eq .SiteSettings.SiteStyle "dark"}}

- <div>

- <input type="radio" id="styleDefault" name="style" value="default" />

- <label for="styleDefault">Default</label>

- </div>

- <div>

- <input type="radio" id="styleClassic" name="style" value="classic" />

- <label for="styleClassic">Classic</label>

- </div>

- <div>

- <input type="radio" id="styleDark" name="style" value="dark" checked />

- <label for="styleDark">Dark</label>

- </div>

- {{else}}

- <div>

- <input type="radio" id="styleDefault" name="style" value="default" checked />

- <label for="styleDefault">Default</label>

- </div>

- <div>

- <input type="radio" id="styleClassic" name="style" value="classic" />

- <label for="styleClassic">Classic</label>

- </div>

- <div>

- <input type="radio" id="styleDark" name="style" value="dark" />

- <label for="styleDark">Dark</label>

- </div>

- {{end}}

- </div>

- </div>

- <input type="submit" class="button button--primary" value="Save" />

- </form>

- {{end}}

- </div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,91 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Commit{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/{{.CommitDetail.Branch}}" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/{{.CommitDetail.Branch}}" class="repo__menu__item repo__menu__item--active">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- <div class="repo-commit">

- <div class="repo-commit__description">

- <div class="repo-commit__header">

- <div class="repo-commit__hash">{{.CommitDetail.Hash}}</div>

- <div class="repo-commit__date">{{.CommitDetail.Date}}</div>

- </div>

- <div class="repo-commit__profile">

- <img src="{{.CommitDetail.DP}}" width="23px" />

- <div>{{.CommitDetail.Name}}</div>

- </div>

- <div class="repo-commit__message">{{.CommitDetail.Message}}</div>

- </div>

- <div class="repo-commit__status">

- <div class="repo-commit__commit-status">{{.CommitDetail.CommitStatus}}</div>

- <div class="repo-commit__files-changed">

- {{range .CommitDetail.Files}}

- <div>

- <p>{{.State}}</p>

- <a href="/r/{{$.Reponame}}/tree/{{$.CommitDetail.Branch}}/{{.Filename}}">{{.Filename}}</a>

- </div>

- {{end}}

- </div>

- </div>

- <div class="repo-commit__code-lines">

- {{range .CommitDetail.Files}}

- <div class="repo-commit__file">

- <p>{{.State}}</p>

- <div>

- <a href="/r/{{$.Reponame}}/tree/{{.PreviousHash}}/{{.Filename}}">{{.Filename}}</a>

- <i>=></i>

- <a href="/r/{{$.Reponame}}/tree/{{$.CommitDetail.Hash}}/{{.Filename}}">{{.Filename}}</a>

- </div>

- </div>

- <div class="repo-commit__code-line">

- {{range .Ampersands}}

- {{.Ampersand}}

- <pre><code class="{{.FileExt}}">{{.CodeLines}}</code></pre>

- {{end}}

- </div>

- {{end}}

- </div>

- </div>

- {{if eq .SiteStyle "dark"}}

- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/railscasts.min.css">

- {{else}}

- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/github.min.css">

- {{end}}

- <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>

- <script>

- document.addEventListener('DOMContentLoaded', (event) => {

-

-document.querySelectorAll('pre code').forEach((block) => {

- hljs.highlightBlock(block);

-});

-});

- </script>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,46 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Contributors{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item repo__menu__item--active">contributors</a>

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- <div class="repo-contributors">

- {{range .Contributors.Detail}}

- <div class="repo-contributors__info">

- <div class="repo-contributors__title">

- <img src="{{.DP}}" width="23px" />

- <div class="repo-contributors__name">{{.Name}}</div>

- </div>

- <div class="repo-contributors__commits">{{.Commits}} commits</div>

- </div>

- {{end}}

- </div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,68 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Log{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item repo__menu__item--active">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- <div class="repo__sub-menu">

- <div class="repo__sub-menu__item branch">

- <form method="get" action="" class="form">

- <div class="form__group">

- <label for="branchSelect">branch:</label>

- <select id="branchSelect" onchange="branchChange(this.value);">

- {{range .RepoBranches}}

- <option value="{{.}}">{{.}}</option>

- {{end}}

- </select>

- </div>

- </form>

- </div>

- </div>

- <div class="repo__log">

- <ul>

- {{range .RepoLogs.History}}

- <li>

- <div>

- <p class="repo__log__info"><a href="/r/{{ $.Reponame }}/commit/{{.Branch}}/{{.FullHash}}">{{.Hash}}</a> - <img class="repo__log__dp" src="{{.DP}}" width="23px" /><span>{{.Author}}</span></p>

- <p>{{.Date}}</p>

- </div>

- <p class="repo__commit-message">{{.Message}}</p>

- </li>

- {{end}}

- </ul>

- {{if .RepoLogs.IsNext}}

- <div class="repo__pagination">

- <a id="repoPagination" href="/r/{{.Reponame}}/log/master?from={{.RepoLogs.HashLink}}" class="button button--primary">Next</a>

- </div>

- {{end}}

- </div>

- <script src="/public/js/branch-selection.js"></script>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,124 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Meta{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- {{if eq .RepoEmpty false}}

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{end}}

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item repo__menu__item--active">meta</a>

- {{end}}

- </div>

- {{if .IsLoggedIn}}

- <div class="repo__meta">

- {{if .RepoAccess}}

- <form class="form repo__meta__form" method="POST" action="/r/{{.Reponame}}/meta">

- <div class="form__title meta__form__title">general</div>

- <div class="form__error">{{ .ReponameErrMessage }}</div>

- <div class="form__group">

- <label for="repoName">Repository name</label>

- <input type="text" class="form__input" id="repoName" name="name" value="{{.Reponame}}" autocomplete="off" spellcheck="false" />

- </div>

- <div class="form__group">

- <label for="repoDescription">Description<i>*</i></label>

- <input type="text" class="form__input" id="repoDescription" name="description" value="{{.RepoDescription}}" autocomplete="off" spellcheck="false" />

- </div>

- <div class="form__group form__radio-group">

- {{if eq .IsRepoPrivate true}}

- <div class="form__radio">

- <input type="radio" name="is_private" value="0" id="repoPublic" />

- <label for="repoPublic">Public</label>

- </div>

- <div class="form__radio">

- <input type="radio" name="is_private" value="1" id="repoPrivate" checked />

- <label for="repoPrivate">Private</label>

- </div>

- {{else}}

- <div class="form__radio">

- <input type="radio" name="is_private" value="0" id="repoPublic" checked />

- <label for="repoPublic">Public</label>

- </div>

- <div class="form__radio">

- <input type="radio" name="is_private" value="1" id="repoPrivate" />

- <label for="repoPrivate">Private</label>

- </div>

- {{end}}

- </div>

- <input type="submit" class="button button--primary" value="Save" />

- </form>

- <form class="form repo__meta__add-user__form" method="POST" action="/r/{{.Reponame}}/meta/user">

- <div class="form__title meta__add-user__form-title">add user and set access</div>

- <div class="form__error">{{ .RepoUserAddError }}</div>

- <div class="form__group">

- <label for="userName">Username</label>

- <input type="text" class="form__input" id="userName" name="username" value="" autocomplete="off" spellcheck="false" />

- </div>

- <div class="form__group form__radio-group">

- {{if .IsRepoPrivate}}

- <div class="form__radio">

- <input type="radio" name="is_readorwrite" value="read" id="read" checked />

- <label for="read">Read</label>

- </div>

- <div class="form__radio">

- <input type="radio" name="is_readorwrite" value="read/write" id="readOrWrite" />

- <label for="readOrWrite">Read/Write</label>

- </div>

- {{else}}

- <div class="form__radio">

- <input type="radio" name="is_readorwrite" value="read/write" id="readOrWrite" checked />

- <label for="readOrWrite">Read/Write</label>

- </div>

- {{end}}

- </div>

- <input type="submit" class="button button--primary" value="Add user" />

- </form>

- {{end}}

- <div class="repo__meta__users">

- <div class="repo__meta__users__title">Users</div>

- {{range .RepoMembers.RepoMembers}}

- <div class="repo__meta__users__item">

- <p>{{.Username}}</p>

- {{if .IsOwner}}

- <p class="owner">[Owner]</p>

- {{end}}

- <p>({{.Permission}})</p>

- {{if not .IsOwner}}

- <a onclick="return confirm('Are you sure, you want to remove this user?');" href="/r/{{$.Reponame}}/meta/user/remove/{{.Username}}" class="button button--danger">Remove</a>

- {{end}}

- </div>

- {{end}}

- </div>

- {{if .RepoAccess}}

- <form class="form repo__meta__delete__form" method="POST" action="/r/{{.Reponame}}/meta/delete" onsubmit="return confirm('This will permanently delete your repository and cannot be undone. Are you sure?');">

- <div class="form__title meta__delete__form-title">delete this repository</div>

- <input type="submit" class="button button--danger" value="Delete" />

- </form>

- {{end}}

- </div>

- {{end}}

-</main>

-{{end}}

\ No newline at end of file

@@ -1,47 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Refs{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item repo__menu__item--active">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- <div class="repo-refs">

- {{range .RepoRefs}}

- <div class="repo-refs__info">

- <div class="repo-refs__version">{{.Version}}</div>

- <div class="repo-refs__files">

- <a href="{{.TargzPath}}">{{.Targz}}</a>

- <a href="{{.ZipPath}}">{{.Zip}}</a>

- </div>

- <div class="repo-refs__message">{{.Message}}</div>

- </div>

- {{end}}

- </div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,75 +0,0 @@

-{{define "title"}}{{ .Reponame }}{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="" class="repo__menu__item repo__menu__item--active">summary</a>

- {{if eq .RepoEmpty false}}

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{end}}

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- {{if eq .RepoEmpty false}}

- <div class="repo__sub-menu">

- <a href="/r/{{ .Reponame }}/log/master" class="repo__sub-menu__item">{{.TotalCommits}} commits</a>

- <p class="repo__sub-menu__bullet">&bull;</p>

- <a href="/r/{{ .Reponame }}/refs" class="repo__sub-menu__item">{{.TotalRefs}} refs</a>

- <p class="repo__sub-menu__bullet">&bull;</p>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__sub-menu__item">{{.Contributors.Total}} contributors</a>

- </div>

- {{end}}

- <div class="repo__summary">

- {{if eq .RepoEmpty false}}

- <div class="repo__summary__left">

- <ul class="repo__latest-commits">

- {{range .RepoLogs.History}}

- <li>

- <div>

- <p><a href="/r/{{ $.Reponame }}/commit/{{.Branch}}/{{.FullHash}}">{{.Hash}}</a> - <img class="repo__log__dp" src="{{.DP}}" width="23px" /><span>{{.Author}}</span></p>

- <p>{{.Date}}</p>

- </div>

- <p class="repo__commit-message">{{.Message}}</p>

- </li>

- {{end}}

- </ul>

- </div>

- {{end}}

- <div class="repo__summary__right">

- <div class="repo__owner">

- <div class="repo__owner__title">owner</div>

- <div class="repo__owner__detail">{{ .Username }}</div>

- </div>

- <div class="repo__clone">

- <div class="repo__clone__title">clone</div>

- <div class="repo__clone__item"><span>ssh </span><input type="text" onclick="this.select()" value="{{ .SSHClone }}" readonly="" /></div>

- <div class="repo__clone__item"><span>https </span><input type="text" onclick="this.select()" value="https://{{ .Host }}/r/{{ .Reponame }}.git" readonly="" /></div>

- </div>

- </div>

- </div>

- <div class="readme">{{ .RepoDetail.Readme }}</div>

-</main>

-{{end}}

\ No newline at end of file

@@ -1,81 +0,0 @@

-{{define "title"}}{{ .Reponame }} - Tree{{end}}

-{{define "content"}}

-<main class="container repo">

- <div class="repo__header">

- <div>

- <div class="repo__title">

- <a href="/r/{{ .Reponame }}">{{ .Reponame }}

- {{if .IsLoggedIn}}

- {{if .IsRepoPrivate}}<i>private</i>{{end}}

- {{if eq .RepoPermission "read"}}<i>read</i>{{end}}

- {{if eq .RepoPermission "read/write"}}<i>read/write</i>{{end}}

- {{if not .IsRepoPrivate}}

- {{if eq .RepoPermission "read/write"}}

- {{else}}

- <i>read</i>

- {{end}}

- {{end}}

- {{end}}

- </a>

- </div>

- <div class="repo__description">{{ .RepoDescription }}</div>

- </div>

- </div>

- <div class="repo__menu">

- <a href="/r/{{ .Reponame }}" class="repo__menu__item">summary</a>

- <a href="/r/{{ .Reponame }}/tree/master" class="repo__menu__item repo__menu__item--active">tree</a>

- <a href="/r/{{ .Reponame }}/log/master" class="repo__menu__item">log</a>

- <a href="/r/{{ .Reponame }}/refs" class="repo__menu__item">refs</a>

- <a href="/r/{{ .Reponame }}/contributors" class="repo__menu__item">contributors</a>

- {{if .IsLoggedIn}}

- <a href="/r/{{ .Reponame }}/meta" class="repo__menu__item">meta</a>

- {{end}}

- </div>

- <div class="repo__sub-menu">

- <div class="repo__sub-menu__item branch">

- <form method="get" action="" class="form">

- <div class="form__group">

- <label for="branchSelect">branch:</label>

- <select id="branchSelect" onchange="branchChange(this.value)">

- {{range .RepoBranches}}

- <option value="{{.}}">{{.}}</option>

- {{end}}

- </select>

- </div>

- </form>

- </div>

- </div>

- {{if .RepoDetail.PathEmpty}}

- {{range .RepoLogs.History}}

- <div class="latest-commit">

- <img src="{{.DP}}" width="23px">

- <div class="latest-commit__name">{{.Author}}</div>

- <a href="/r/{{ $.Reponame }}/commit/{{.Branch}}/{{.FullHash}}">{{.Message}}</a>

- <div class="latest-commit__date">{{.Date}}</div>

- </div>

- {{end}}

- {{else}}

- <div class="path">

- <p>path:</p>

- <div>{{.RepoDetail.LegendPath}}</div>

- </div>

- {{end}}

- <div class="repo-tree">

- {{range .RepoDetail.RepoDirsDetail}}

- <div class="repo-tree__info">

- <a href="{{ $.RepoDetail.WalkPath }}/{{.DirName}}" class="repo-tree__directory">{{.DirName}}</a>

- <a href="/r/{{ $.Reponame }}/commit/{{.DirCommitBranch}}/{{.DirCommitFullHash}}" class="repo-tree__info__message">{{.DirCommit}}</a>

- <p class="repo-tree__info__date">{{.DirCommitDate}}</p>

- </div>

- {{end}}

- {{range .RepoDetail.RepoFilesDetail}}

- <div class="repo-tree__info">

- <a href="{{ $.RepoDetail.WalkPath }}/{{.FileName}}" class="repo-tree__file">{{.FileName}}</a>

- <a href="/r/{{ $.Reponame }}/commit/{{.FileCommitBranch}}/{{.FileCommitFullHash}}" class="repo-tree__info__message">{{.FileCommit}}</a>

- <p class="repo-tree__info__date">{{.FileCommitDate}}</p>

- </div>

- {{end}}

- </div>

- <script src="/public/js/branch-selection.js"></script>

-</main>

-{{end}}

\ No newline at end of file

@@ -0,0 +1,125 @@

+package routes

+

+import (

+ "database/sql"

+ "net/http"

+ "path/filepath"

+

+ "sorcia/internal"

+ "sorcia/middleware"

+ "sorcia/pkg"

+

+ "github.com/gorilla/mux"

+ "github.com/gorilla/schema"

+)

+

+var decoder = schema.NewDecoder()

+

+// Router ...

+func Router(m *mux.Router, db *sql.DB, conf *pkg.BaseStruct) *mux.Router {

+

+ m.Use(middleware.Middleware)

+

+ // Web handlers

+ m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetHome(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetLogin(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostLogin(w, r, db, conf, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetLogout(w, r)

+ }).Methods("GET")

+ m.HandleFunc("/create-repo", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetCreateRepo(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/create-repo", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostCreateRepo(w, r, db, decoder, conf)

+ }).Methods("POST")

+ m.HandleFunc("/meta", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetMeta(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/meta/password", func(w http.ResponseWriter, r *http.Request) {

+ internal.MetaPostPassword(w, r, db, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/meta/site", func(w http.ResponseWriter, r *http.Request) {

+ internal.MetaPostSiteSettings(w, r, db, conf)

+ }).Methods("POST")

+ m.HandleFunc("/meta/keys", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetMetaKeys(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/meta/keys/delete/{keyID}", func(w http.ResponseWriter, r *http.Request) {

+ internal.DeleteMetaKey(w, r, db)

+ }).Methods("GET")

+ m.HandleFunc("/meta/keys", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostAuthKey(w, r, db, conf, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/meta/users", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetMetaUsers(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/meta/users", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostUser(w, r, db, conf, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/meta/user/revoke-access/{username}", func(w http.ResponseWriter, r *http.Request) {

+ internal.RevokeCreateRepoAccess(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/meta/user/add-access/{username}", func(w http.ResponseWriter, r *http.Request) {

+ internal.AddCreateRepoAccess(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepo(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/meta", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoMeta(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/meta", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostRepoMeta(w, r, db, conf, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/r/{reponame}/meta/user", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostRepoMetaUser(w, r, db, conf, decoder)

+ }).Methods("POST")

+ m.HandleFunc("/r/{reponame}/meta/user/remove/{username}", func(w http.ResponseWriter, r *http.Request) {

+ internal.RemoveRepoMetaUser(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/meta/delete", func(w http.ResponseWriter, r *http.Request) {

+ internal.PostRepoMetaDelete(w, r, db, conf)

+ }).Methods("POST")

+ m.HandleFunc("/r/{reponame}/tree/{branch}", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoTree(w, r, db, conf)

+ }).Methods("GET")

+ m.PathPrefix("/r/{reponame}/tree/{branchorhash}/{path:[[\\d\\w-_\\.]+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoTreePath(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/log/{branch}", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoLog(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/commit/{branch}/{hash}", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetCommitDetail(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/refs", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoRefs(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/r/{reponame}/contributors", func(w http.ResponseWriter, r *http.Request) {

+ internal.GetRepoContributors(w, r, db, conf)

+ }).Methods("GET")

+ m.HandleFunc("/dl/{file}", func(w http.ResponseWriter, r *http.Request) {

+ internal.ServeRefFile(w, r, conf)

+ }).Methods("GET")

+ m.PathPrefix("/r/{reponame[\\d\\w-_\\.]+\\.git$}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

+ internal.GitviaHTTP(w, r, db, conf)

+ }).Methods("GET", "POST")

+

+ staticDir := filepath.Join(conf.Paths.ProjectRoot, "public")

+ staticFileHandler := http.StripPrefix("/public/", http.FileServer(http.Dir(staticDir)))

+ // The "PathPrefix" method acts as a matcher, and matches all routes starting

+ // with "/public/", instead of the absolute route itself

+ m.PathPrefix("/public/").Handler(staticFileHandler).Methods("GET")

+

+ uploadFileHandler := http.StripPrefix("/uploads/", http.FileServer(http.Dir(conf.Paths.UploadAssetPath)))

+ m.PathPrefix("/uploads/").Handler(uploadFileHandler).Methods("GET")

+

+ return m

+}

@@ -1,25 +0,0 @@

-server {

- listen 80;

- listen [::]:80;

- server_name git.example.com;

- return 301 https://git.example.com$request_uri;

-}

-

-server {

- listen 443 ssl;

- listen [::]:443 ssl;

- server_name git.example.com;

-

- # ssl on;

- # ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem; # managed by Certbot

- # ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem; # managed by Certbot

- # include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

- # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

-

- location / {

- proxy_set_header X-Real-IP $remote_addr;

- proxy_set_header X-Forwarded-For $remote_addr;

- proxy_set_header Host $host;

- proxy_pass http://127.0.0.1:1937;

- }

-}

\ No newline at end of file

@@ -1,15 +0,0 @@

-[Unit]

-Description=sorcia web service

-After=network.target

-

-[Service]

-ExecStart=/usr/bin/sudo ./sorcia web

-TimeoutStartSec=3600

-Restart=always

-RestartSec=10

-WorkingDirectory=/home/git/sorcia

-User=root

-Group=root

-

-[Install]

-WantedBy=multi-user.target

\ No newline at end of file

@@ -1,5 +0,0 @@

-Host git

- HostName your-server-ip-address

- User root

- Port 22

-

@@ -5,7 +5,7 @@ import (

"os"

"sorcia/cmd"

- "sorcia/setting"

+ "sorcia/pkg"

)

func main() {

@@ -15,7 +15,7 @@ func main() {

}

// Get config values

- conf := setting.GetConf()

+ conf := pkg.GetConf()

switch os.Args[1] {

case "web":

@@ -1,165 +0,0 @@

-package util

-

-import (

- "crypto/md5"

- "database/sql"

- "encoding/base64"

- "fmt"

- "html/template"

- "io/ioutil"

- "log"

- "os"

- "path/filepath"

- "strings"

-

- errorhandler "sorcia/error"

- "sorcia/model"

- "sorcia/setting"

-)

-

-// IsAlnumOrHyphen ...

-func IsAlnumOrHyphen(s string) bool {

- for _, r := range s {

- if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0' || r > '9') && r != '-' {

- return false

- }

- }

- return true

-}

-

-// SSHFingerPrint ...

-func SSHFingerPrint(authKey string) string {

- parts := strings.Fields(string(authKey))

- if len(parts) < 2 {

- log.Printf("bad key")

- }

-

- k, err := base64.StdEncoding.DecodeString(parts[1])

- errorhandler.CheckError("Error on util ssh fingerprint decode string", err)

-

- fp := md5.Sum([]byte(k))

- var fingerPrint string

- for i, b := range fp {

- fingerPrint = fmt.Sprintf("%s%02x", fingerPrint, b)

- if i < len(fp)-1 {

- fingerPrint = fmt.Sprintf("%s:", fingerPrint)

- }

- }

-

- return fingerPrint

-}

-

-// CreateDir

-func CreateDir(dir string) {

- if _, err := os.Stat(dir); os.IsNotExist(err) {

- err := os.MkdirAll(dir, os.ModePerm)

- errorhandler.CheckError("Error on util create dir", err)

- }

-}

-

-// CreateSSHDirAndGenerateKey ...

-func CreateSSHDirAndGenerateKey(sshPath string) {

- if _, err := os.Stat(sshPath); os.IsNotExist(err) {

- err := os.MkdirAll(sshPath, os.ModePerm)

- errorhandler.CheckError("Error on util create ssh dir and generate ssh key", err)

- }

-

- keyPath := filepath.Join(sshPath, "id_rsa")

- if _, err := os.Stat(keyPath); os.IsNotExist(err) {

- args := []string{"-f", keyPath, "-t", "rsa", "-m", "PEM", "-N", ""}

- _ = ForkExec("ssh-keygen", args, ".")

- }

-}

-

-func LimitCharLengthInString(limitString string) string {

- if len(limitString) > 50 {

- limitString = fmt.Sprintf("%s...", string(limitString[:50]))

- return limitString

- }

-

- return limitString

-}

-

-// Contains tells whether a contains x.

-func ContainsValueInArr(a []string, x string) bool {

- for _, n := range a {

- if x == n {

- return true

- }

- }

- return false

-}

-

-// SiteSettings struct

-type SiteSettings struct {

- IsSiteTitle bool

- IsSiteFavicon bool

- IsSiteLogo bool

- SiteTitle string

- SiteStyle string

- SiteFavicon string

- SiteFaviconExt string

- SiteLogo string

- SiteLogoWidth string

- SiteLogoHeight string

- IsSiteLogoSVG bool

- SVGDAT template.HTML

-}

-

-// GetSiteSettings ...

-func GetSiteSettings(db *sql.DB, conf *setting.BaseStruct) SiteSettings {

- gssr := model.GetSiteSettings(db, conf)

-

- isSiteTitle := true

- if gssr.Title == "" {

- isSiteTitle = false

- }

-

- isSiteFavicon := true

- if gssr.Favicon == "" {

- isSiteFavicon = false

- }

-

- isSiteLogo := true

- if gssr.Logo == "" {

- isSiteLogo = false

- }

-

- var faviconExt string

- faviconSplit := strings.Split(gssr.Favicon, ".")

- if len(faviconSplit) > 1 {

- faviconExt = faviconSplit[1]

- }

-

- var isSiteLogoSVG bool

- var svgXML template.HTML

- var siteLogoExt string

- siteLogoSplit := strings.Split(gssr.Logo, ".")

- if len(siteLogoSplit) > 1 {

- siteLogoExt = siteLogoSplit[1]

- }

- if siteLogoExt == "svg" {

- isSiteLogoSVG = true

- dat, err := ioutil.ReadFile(filepath.Join(conf.Paths.UploadAssetPath, gssr.Logo))

- errorhandler.CheckError("Error on Reading svg logo file", err)

-

- svgXML = template.HTML(dat)

- }

-

- siteSettings := SiteSettings{

- IsSiteTitle: isSiteTitle,

- IsSiteFavicon: isSiteFavicon,

- IsSiteLogo: isSiteLogo,

- SiteTitle: gssr.Title,

- SiteStyle: gssr.Style,

- SiteFavicon: gssr.Favicon,

- SiteFaviconExt: faviconExt,

- SiteLogo: gssr.Logo,

- SiteLogoWidth: gssr.LogoWidth,

- SiteLogoHeight: gssr.LogoHeight,

- IsSiteLogoSVG: isSiteLogoSVG,

- SVGDAT: svgXML,

- }

-

- return siteSettings

-}