func EditUser(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true uid := com.StrTo(ctx.Params(":userid")).MustInt64() if uid == 0 { ctx.Handle(404, "EditUser", nil) return } u, err := models.GetUserByID(uid) if err != nil { ctx.Handle(500, "GetUserByID", err) return } ctx.Data["User"] = u auths, err := models.GetAuths() if err != nil { ctx.Handle(500, "GetAuths", err) return } ctx.Data["LoginSources"] = auths ctx.HTML(200, USER_EDIT) }
// SendIssueNotifyMail sends mail notification of all watchers of repository. func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *models.Issue) ([]string, error) { ws, err := models.GetWatchers(repo.ID) if err != nil { return nil, errors.New("mail.NotifyWatchers(GetWatchers): " + err.Error()) } tos := make([]string, 0, len(ws)) for i := range ws { uid := ws[i].UserID if u.Id == uid { continue } u, err := models.GetUserByID(uid) if err != nil { return nil, errors.New("mail.NotifyWatchers(GetUserById): " + err.Error()) } tos = append(tos, u.Email) } if len(tos) == 0 { return tos, nil } subject := fmt.Sprintf("[%s] %s (#%d)", repo.Name, issue.Name, issue.Index) content := fmt.Sprintf("%s<br>-<br> <a href=\"%s%s/%s/issues/%d\">View it on Gogs</a>.", base.RenderSpecialLink([]byte(issue.Content), owner.Name+"/"+repo.Name), setting.AppUrl, owner.Name, repo.Name, issue.Index) msg := NewMailMessageFrom(tos, u.Email, subject, content) msg.Info = fmt.Sprintf("Subject: %s, send issue notify emails", subject) SendAsync(&msg) return tos, nil }
func DeleteUser(ctx *middleware.Context) { uid := com.StrTo(ctx.Params(":userid")).MustInt64() if uid == 0 { ctx.Handle(404, "DeleteUser", nil) return } u, err := models.GetUserByID(uid) if err != nil { ctx.Handle(500, "GetUserByID", err) return } if err = models.DeleteUser(u); err != nil { switch { case models.IsErrUserOwnRepos(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo")) ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid")) case models.IsErrUserHasOrgs(err): ctx.Flash.Error(ctx.Tr("admin.users.still_has_org")) ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid")) default: ctx.Handle(500, "DeleteUser", err) } return } log.Trace("Account deleted by admin(%s): %s", ctx.User.Name, u.Name) ctx.Redirect(setting.AppSubUrl + "/admin/users") }
func checkContextUser(ctx *middleware.Context, uid int64) *models.User { if err := ctx.User.GetOrganizations(); err != nil { ctx.Handle(500, "GetOrganizations", err) return nil } ctx.Data["Orgs"] = ctx.User.Orgs // Not equal means current user is an organization. if uid == ctx.User.Id || uid == 0 { return ctx.User } org, err := models.GetUserByID(uid) if models.IsErrUserNotExist(err) { return ctx.User } if err != nil { ctx.Handle(500, "checkContextUser", fmt.Errorf("GetUserById(%d): %v", uid, err)) return nil } // Check ownership of organization. if !org.IsOrganization() || !org.IsOwnedBy(ctx.User.Id) { ctx.Error(403) return nil } return org }
func SearchRepos(ctx *middleware.Context) { opt := models.SearchOption{ Keyword: path.Base(ctx.Query("q")), Uid: com.StrTo(ctx.Query("uid")).MustInt64(), Limit: com.StrTo(ctx.Query("limit")).MustInt(), } if opt.Limit == 0 { opt.Limit = 10 } // Check visibility. if ctx.IsSigned && opt.Uid > 0 { if ctx.User.Id == opt.Uid { opt.Private = true } else { u, err := models.GetUserByID(opt.Uid) if err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) { opt.Private = true } // FIXME: how about collaborators? } } repos, err := models.SearchRepositoryByName(opt) if err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } results := make([]*api.Repository, len(repos)) for i := range repos { if err = repos[i].GetOwner(); err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } results[i] = &api.Repository{ Id: repos[i].ID, FullName: path.Join(repos[i].Owner.Name, repos[i].Name), } } ctx.JSON(200, map[string]interface{}{ "ok": true, "data": results, }) }
func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) { ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true uid := com.StrTo(ctx.Params(":userid")).MustInt64() if uid == 0 { ctx.Handle(404, "EditUser", nil) return } u, err := models.GetUserByID(uid) if err != nil { ctx.Handle(500, "GetUserById", err) return } ctx.Data["User"] = u if ctx.HasError() { ctx.HTML(200, USER_EDIT) return } // FIXME: need password length check if len(form.Password) > 0 { u.Passwd = form.Password u.Salt = models.GetUserSalt() u.EncodePasswd() } u.FullName = form.FullName u.Email = form.Email u.Website = form.Website u.Location = form.Location if len(form.Avatar) == 0 { form.Avatar = form.Email } u.Avatar = base.EncodeMd5(form.Avatar) u.AvatarEmail = form.Avatar u.IsActive = form.Active u.IsAdmin = form.Admin u.AllowGitHook = form.AllowGitHook if err := models.UpdateUser(u); err != nil { if models.IsErrEmailAlreadyUsed(err) { ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_EDIT, &form) } else { ctx.Handle(500, "UpdateUser", err) } return } log.Trace("Account profile updated by admin(%s): %s", ctx.User.Name, u.Name) ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success")) ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid")) }
// SignedInId returns the id of signed in user. func SignedInId(req *http.Request, sess session.Store) int64 { if !models.HasEngine { return 0 } // API calls need to check access token. if IsAPIPath(req.URL.Path) { auHead := req.Header.Get("Authorization") if len(auHead) > 0 { auths := strings.Fields(auHead) if len(auths) == 2 && auths[0] == "token" { t, err := models.GetAccessTokenBySHA(auths[1]) if err != nil { if err != models.ErrAccessTokenNotExist { log.Error(4, "GetAccessTokenBySHA: %v", err) } return 0 } t.Updated = time.Now() if err = models.UpdateAccessToekn(t); err != nil { log.Error(4, "UpdateAccessToekn: %v", err) } return t.UID } } } uid := sess.Get("uid") if uid == nil { return 0 } if id, ok := uid.(int64); ok { if _, err := models.GetUserByID(id); err != nil { if !models.IsErrUserNotExist(err) { log.Error(4, "GetUserById: %v", err) } return 0 } return id } return 0 }
// SignedInUser returns the user object of signed user. // It returns a bool value to indicate whether user uses basic auth or not. func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) { if !models.HasEngine { return nil, false } uid := SignedInId(req, sess) if uid <= 0 { if setting.Service.EnableReverseProxyAuth { webAuthUser := req.Header.Get(setting.ReverseProxyAuthUser) if len(webAuthUser) > 0 { u, err := models.GetUserByName(webAuthUser) if err != nil { if !models.IsErrUserNotExist(err) { log.Error(4, "GetUserByName: %v", err) return nil, false } // Check if enabled auto-registration. if setting.Service.EnableReverseProxyAutoRegister { u := &models.User{ Name: webAuthUser, Email: uuid.NewV4().String() + "@localhost", Passwd: webAuthUser, IsActive: true, } if err = models.CreateUser(u); err != nil { // FIXME: should I create a system notice? log.Error(4, "CreateUser: %v", err) return nil, false } else { return u, false } } } return u, false } } // Check with basic auth. baHead := req.Header.Get("Authorization") if len(baHead) > 0 { auths := strings.Fields(baHead) if len(auths) == 2 && auths[0] == "Basic" { uname, passwd, _ := base.BasicAuthDecode(auths[1]) u, err := models.UserSignIn(uname, passwd) if err != nil { if !models.IsErrUserNotExist(err) { log.Error(4, "UserSignIn: %v", err) } return nil, false } return u, true } } return nil, false } u, err := models.GetUserByID(uid) if err != nil { log.Error(4, "GetUserById: %v", err) return nil, false } return u, false }
func Http(ctx *middleware.Context) { username := ctx.Params(":username") reponame := ctx.Params(":reponame") if strings.HasSuffix(reponame, ".git") { reponame = reponame[:len(reponame)-4] } var isPull bool service := ctx.Query("service") if service == "git-receive-pack" || strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") { isPull = false } else if service == "git-upload-pack" || strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { isPull = true } else { isPull = (ctx.Req.Method == "GET") } repoUser, err := models.GetUserByName(username) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", nil) } else { ctx.Handle(500, "GetUserByName", err) } return } repo, err := models.GetRepositoryByName(repoUser.Id, reponame) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Handle(404, "GetRepositoryByName", nil) } else { ctx.Handle(500, "GetRepositoryByName", err) } return } // Only public pull don't need auth. isPublicPull := !repo.IsPrivate && isPull var ( askAuth = !isPublicPull || setting.Service.RequireSignInView authUser *models.User authUsername string authPasswd string ) // check access if askAuth { baHead := ctx.Req.Header.Get("Authorization") if baHead == "" { authRequired(ctx) return } auths := strings.Fields(baHead) // currently check basic auth // TODO: support digit auth // FIXME: middlewares/context.go did basic auth check already, // maybe could use that one. if len(auths) != 2 || auths[0] != "Basic" { ctx.HandleText(401, "no basic auth and digit auth") return } authUsername, authPasswd, err = base.BasicAuthDecode(auths[1]) if err != nil { ctx.HandleText(401, "no basic auth and digit auth") return } authUser, err = models.UserSignIn(authUsername, authPasswd) if err != nil { if !models.IsErrUserNotExist(err) { ctx.Handle(500, "UserSignIn error: %v", err) return } // Assume username now is a token. token, err := models.GetAccessTokenBySHA(authUsername) if err != nil { if err == models.ErrAccessTokenNotExist { ctx.HandleText(401, "invalid token") } else { ctx.Handle(500, "GetAccessTokenBySha", err) } return } token.Updated = time.Now() if err = models.UpdateAccessToekn(token); err != nil { ctx.Handle(500, "UpdateAccessToekn", err) } authUser, err = models.GetUserByID(token.UID) if err != nil { ctx.Handle(500, "GetUserById", err) return } authUsername = authUser.Name } if !isPublicPull { var tp = models.ACCESS_MODE_WRITE if isPull { tp = models.ACCESS_MODE_READ } has, err := models.HasAccess(authUser, repo, tp) if err != nil { ctx.HandleText(401, "no basic auth and digit auth") return } else if !has { if tp == models.ACCESS_MODE_READ { has, err = models.HasAccess(authUser, repo, models.ACCESS_MODE_WRITE) if err != nil || !has { ctx.HandleText(401, "no basic auth and digit auth") return } } else { ctx.HandleText(401, "no basic auth and digit auth") return } } if !isPull && repo.IsMirror { ctx.HandleText(401, "can't push to mirror") return } } } callback := func(rpc string, input []byte) { if rpc == "receive-pack" { var lastLine int64 = 0 for { head := input[lastLine : lastLine+2] if head[0] == '0' && head[1] == '0' { size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32) if err != nil { log.Error(4, "%v", err) return } if size == 0 { //fmt.Println(string(input[lastLine:])) break } line := input[lastLine : lastLine+size] idx := bytes.IndexRune(line, '\000') if idx > -1 { line = line[:idx] } fields := strings.Fields(string(line)) if len(fields) >= 3 { oldCommitId := fields[0][4:] newCommitId := fields[1] refName := fields[2] // FIXME: handle error. if err = models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id); err == nil { models.HookQueue.AddRepoID(repo.ID) } } lastLine = lastLine + size } else { break } } } } HTTPBackend(&Config{ RepoRootPath: setting.RepoRootPath, GitBinPath: "git", UploadPack: true, ReceivePack: true, OnSucceed: callback, })(ctx.Resp, ctx.Req.Request) runtime.GC() }
func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { u, err := models.GetUserByName(ctx.Query("username")) if err != nil { if models.IsErrUserNotExist(err) { ctx.HandleAPI(422, err) } else { ctx.HandleAPI(500, err) } return } if !u.ValidatePassword(ctx.Query("password")) { ctx.HandleAPI(422, "Username or password is not correct.") return } ctxUser := u // Not equal means current user is an organization. if form.Uid != u.Id { org, err := models.GetUserByID(form.Uid) if err != nil { if models.IsErrUserNotExist(err) { ctx.HandleAPI(422, err) } else { ctx.HandleAPI(500, err) } return } ctxUser = org } if ctx.HasError() { ctx.HandleAPI(422, ctx.GetErrMsg()) return } if ctxUser.IsOrganization() { // Check ownership of organization. if !ctxUser.IsOwnedBy(u.Id) { ctx.HandleAPI(403, "Given user is not owner of organization.") return } } // Remote address can be HTTP/HTTPS/Git URL or local path. remoteAddr := form.CloneAddr if strings.HasPrefix(form.CloneAddr, "http://") || strings.HasPrefix(form.CloneAddr, "https://") || strings.HasPrefix(form.CloneAddr, "git://") { u, err := url.Parse(form.CloneAddr) if err != nil { ctx.HandleAPI(422, err) return } if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 { u.User = url.UserPassword(form.AuthUsername, form.AuthPassword) } remoteAddr = u.String() } else if !com.IsDir(remoteAddr) { ctx.HandleAPI(422, "Invalid local path, it does not exist or not a directory.") return } repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) if err != nil { if repo != nil { if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { log.Error(4, "DeleteRepository: %v", errDelete) } } ctx.HandleAPI(500, err) return } log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) ctx.WriteHeader(200) }
func Releases(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("repo.release.releases") ctx.Data["IsRepoToolbarReleases"] = true ctx.Data["IsRepoReleaseNew"] = false rawTags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "GetTags", err) return } rels, err := models.GetReleasesByRepoId(ctx.Repo.Repository.ID) if err != nil { ctx.Handle(500, "GetReleasesByRepoId", err) return } // Temproray cache commits count of used branches to speed up. countCache := make(map[string]int) tags := make([]*models.Release, len(rawTags)) for i, rawTag := range rawTags { for j, rel := range rels { if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner()) { continue } if rel.TagName == rawTag { rel.Publisher, err = models.GetUserByID(rel.PublisherId) if err != nil { ctx.Handle(500, "GetUserById", err) return } // FIXME: duplicated code. // Get corresponding target if it's not the current branch. if ctx.Repo.BranchName != rel.Target { // Get count if not exists. if _, ok := countCache[rel.Target]; !ok { commit, err := ctx.Repo.GitRepo.GetCommitOfBranch(ctx.Repo.BranchName) if err != nil { ctx.Handle(500, "GetCommitOfBranch", err) return } countCache[ctx.Repo.BranchName], err = commit.CommitsCount() if err != nil { ctx.Handle(500, "CommitsCount2", err) return } } rel.NumCommitsBehind = countCache[ctx.Repo.BranchName] - rel.NumCommits } else { rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits } rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink) tags[i] = rel rels[j] = nil // Mark as used. break } } if tags[i] == nil { commit, err := ctx.Repo.GitRepo.GetCommitOfTag(rawTag) if err != nil { ctx.Handle(500, "GetCommitOfTag2", err) return } tags[i] = &models.Release{ Title: rawTag, TagName: rawTag, Sha1: commit.Id.String(), } tags[i].NumCommits, err = ctx.Repo.GitRepo.CommitsCount(commit.Id.String()) if err != nil { ctx.Handle(500, "CommitsCount", err) return } tags[i].NumCommitsBehind = ctx.Repo.CommitsCount - tags[i].NumCommits } } for _, rel := range rels { if rel == nil { continue } rel.Publisher, err = models.GetUserByID(rel.PublisherId) if err != nil { ctx.Handle(500, "GetUserById", err) return } // FIXME: duplicated code. // Get corresponding target if it's not the current branch. if ctx.Repo.BranchName != rel.Target { // Get count if not exists. if _, ok := countCache[rel.Target]; !ok { commit, err := ctx.Repo.GitRepo.GetCommitOfBranch(ctx.Repo.BranchName) if err != nil { ctx.Handle(500, "GetCommitOfBranch", err) return } countCache[ctx.Repo.BranchName], err = commit.CommitsCount() if err != nil { ctx.Handle(500, "CommitsCount2", err) return } } rel.NumCommitsBehind = countCache[ctx.Repo.BranchName] - rel.NumCommits } else { rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits } rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink) tags = append(tags, rel) } models.SortReleases(tags) ctx.Data["Releases"] = tags ctx.HTML(200, RELEASES) }