Example #1
0
func LoadRepoConfig() {
	// Load .gitignore and license files and readme templates.
	types := []string{"gitignore", "license", "readme"}
	typeFiles := make([][]string, 3)
	for i, t := range types {
		files, err := bindata.AssetDir("conf/" + t)
		if err != nil {
			log.Fatal(4, "Fail to get %s files: %v", t, err)
		}
		customPath := path.Join(setting.CustomPath, "conf", t)
		if com.IsDir(customPath) {
			customFiles, err := com.StatDir(customPath)
			if err != nil {
				log.Fatal(4, "Fail to get custom %s files: %v", t, err)
			}

			for _, f := range customFiles {
				if !com.IsSliceContainsStr(files, f) {
					files = append(files, f)
				}
			}
		}
		typeFiles[i] = files
	}

	Gitignores = typeFiles[0]
	Licenses = typeFiles[1]
	Readmes = typeFiles[2]
	sort.Strings(Gitignores)
	sort.Strings(Licenses)
	sort.Strings(Readmes)
}
Example #2
0
File: repo.go Project: jcfrank/gogs
func LoadRepoConfig() {
	// Load .gitignore and license files.
	types := []string{"gitignore", "license"}
	typeFiles := make([][]string, 2)
	for i, t := range types {
		files := getAssetList(path.Join("conf", t))
		customPath := path.Join(setting.CustomPath, "conf", t)
		if com.IsDir(customPath) {
			customFiles, err := com.StatDir(customPath)
			if err != nil {
				log.Fatal("Fail to get custom %s files: %v", t, err)
			}

			for _, f := range customFiles {
				if !com.IsSliceContainsStr(files, f) {
					files = append(files, f)
				}
			}
		}
		typeFiles[i] = files
	}

	LanguageIgns = typeFiles[0]
	Licenses = typeFiles[1]
	sort.Strings(LanguageIgns)
	sort.Strings(Licenses)
}
Example #3
0
File: repo.go Project: j20/gogs
func LoadRepoConfig() {
	workDir, err := base.ExecDir()
	if err != nil {
		qlog.Fatalf("Fail to get work directory: %s\n", err)
	}

	// Load .gitignore and license files.
	types := []string{"gitignore", "license"}
	typeFiles := make([][]string, 2)
	for i, t := range types {
		cfgPath := filepath.Join(workDir, "conf", t)
		files, err := com.StatDir(cfgPath)
		if err != nil {
			qlog.Fatalf("Fail to get default %s files: %v\n", t, err)
		}
		cfgPath = filepath.Join(workDir, "custom/conf/gitignore")
		if com.IsDir(cfgPath) {
			customFiles, err := com.StatDir(cfgPath)
			if err != nil {
				qlog.Fatalf("Fail to get custom %s files: %v\n", t, err)
			}

			for _, f := range customFiles {
				if !com.IsSliceContainsStr(files, f) {
					files = append(files, f)
				}
			}
		}
		typeFiles[i] = files
	}

	LanguageIgns = typeFiles[0]
	Licenses = typeFiles[1]
}
Example #4
0
File: oauth.go Project: Gr1N/pacman
// HandleService validates that service name is valid and allowed.
func HandleService(serviceName string) error {
	if !com.IsSliceContainsStr(settings.S.OAuth2.EnabledServices, serviceName) {
		return errServiceNotSupported
	}

	return nil
}
Example #5
0
func checkHookType(ctx *middleware.Context) string {
	hookType := strings.ToLower(ctx.Params(":type"))
	if !com.IsSliceContainsStr(setting.Webhook.Types, hookType) {
		ctx.Handle(404, "checkHookType", nil)
		return ""
	}
	return hookType
}
Example #6
0
// Query if name/passwd can login against the LDAP directory pool
// Create a local user if success
// Return the same LoginUserPlain semantic
func LoginUserSMTPSource(u *User, name, passwd string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
	// Verify allowed domains.
	if len(cfg.AllowedDomains) > 0 {
		idx := strings.Index(name, "@")
		if idx == -1 {
			return nil, ErrUserNotExist{0, name}
		} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), name[idx+1:]) {
			return nil, ErrUserNotExist{0, name}
		}
	}

	var auth smtp.Auth
	if cfg.Auth == SMTP_PLAIN {
		auth = smtp.PlainAuth("", name, passwd, cfg.Host)
	} else if cfg.Auth == SMTP_LOGIN {
		auth = LoginAuth(name, passwd)
	} else {
		return nil, errors.New("Unsupported SMTP auth type")
	}

	if err := SMTPAuth(auth, cfg); err != nil {
		// Check standard error format first,
		// then fallback to worse case.
		tperr, ok := err.(*textproto.Error)
		if (ok && tperr.Code == 535) ||
			strings.Contains(err.Error(), "Username and Password not accepted") {
			return nil, ErrUserNotExist{0, name}
		}
		return nil, err
	}

	if !autoRegister {
		return u, nil
	}

	var loginName = name
	idx := strings.Index(name, "@")
	if idx > -1 {
		loginName = name[:idx]
	}
	// fake a local user creation
	u = &User{
		LowerName:   strings.ToLower(loginName),
		Name:        strings.ToLower(loginName),
		LoginType:   LOGIN_SMTP,
		LoginSource: sourceID,
		LoginName:   name,
		IsActive:    true,
		Passwd:      passwd,
		Email:       name,
	}
	err := CreateUser(u)
	return u, err
}
Example #7
0
func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
	ctx.Data["Title"] = "Create issue"
	ctx.Data["IsRepoToolbarIssues"] = true
	ctx.Data["IsRepoToolbarIssuesList"] = false

	if ctx.HasError() {
		ctx.HTML(200, "issue/create")
		return
	}

	issue, err := models.CreateIssue(ctx.User.Id, ctx.Repo.Repository.Id, form.MilestoneId, form.AssigneeId,
		ctx.Repo.Repository.NumIssues, form.IssueName, form.Labels, form.Content, false)
	if err != nil {
		ctx.Handle(500, "issue.CreateIssue(CreateIssue)", err)
		return
	}

	// Notify watchers.
	if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email,
		OpType: models.OP_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
		RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
		ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err)
		return
	}

	// Mail watchers and mentions.
	if base.Service.NotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			ctx.Handle(500, "issue.CreateIssue(SendIssueNotifyMail)", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		ms := base.MentionPattern.FindAllString(issue.Content, -1)
		newTos := make([]string, 0, len(ms))
		for _, m := range ms {
			if com.IsSliceContainsStr(tos, m[1:]) {
				continue
			}

			newTos = append(newTos, m[1:])
		}
		if err = mailer.SendIssueMentionMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository,
			issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "issue.CreateIssue(SendIssueMentionMail)", err)
			return
		}
	}
	log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)

	ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
}
Example #8
0
// LoginViaSMTP queries if login/password is valid against the SMTP,
// and create a local user if success when enabled.
func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {
	// Verify allowed domains.
	if len(cfg.AllowedDomains) > 0 {
		idx := strings.Index(login, "@")
		if idx == -1 {
			return nil, ErrUserNotExist{0, login}
		} else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), login[idx+1:]) {
			return nil, ErrUserNotExist{0, login}
		}
	}

	var auth smtp.Auth
	if cfg.Auth == SMTP_PLAIN {
		auth = smtp.PlainAuth("", login, password, cfg.Host)
	} else if cfg.Auth == SMTP_LOGIN {
		auth = &smtpLoginAuth{login, password}
	} else {
		return nil, errors.New("Unsupported SMTP auth type")
	}

	if err := SMTPAuth(auth, cfg); err != nil {
		// Check standard error format first,
		// then fallback to worse case.
		tperr, ok := err.(*textproto.Error)
		if (ok && tperr.Code == 535) ||
			strings.Contains(err.Error(), "Username and Password not accepted") {
			return nil, ErrUserNotExist{0, login}
		}
		return nil, err
	}

	if !autoRegister {
		return user, nil
	}

	username := login
	idx := strings.Index(login, "@")
	if idx > -1 {
		username = login[:idx]
	}

	user = &User{
		LowerName:   strings.ToLower(username),
		Name:        strings.ToLower(username),
		Email:       login,
		Passwd:      password,
		LoginType:   LOGIN_SMTP,
		LoginSource: sourceID,
		LoginName:   login,
		IsActive:    true,
	}
	return user, CreateUser(user)
}
Example #9
0
// PostProcessMarkdown treats different types of HTML differently,
// and only renders special links for plain text blocks.
func PostProcessMarkdown(rawHtml []byte, urlPrefix string) []byte {
	startTags := make([]string, 0, 5)
	var buf bytes.Buffer
	tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))

OUTER_LOOP:
	for html.ErrorToken != tokenizer.Next() {
		token := tokenizer.Token()
		switch token.Type {
		case html.TextToken:
			buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix))

		case html.StartTagToken:
			buf.WriteString(token.String())
			tagName := token.Data
			// If this is an excluded tag, we skip processing all output until a close tag is encountered.
			if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
				for html.ErrorToken != tokenizer.Next() {
					token = tokenizer.Token()

					// Copy the token to the output verbatim
					buf.WriteString(token.String())
					// If this is the close tag, we are done
					if token.Type == html.EndTagToken && strings.EqualFold(tagName, token.Data) {
						break
					}
				}
				continue OUTER_LOOP
			}

			if !com.IsSliceContainsStr(noEndTags, token.Data) {
				startTags = append(startTags, token.Data)
			}

		case html.EndTagToken:
			buf.Write(leftAngleBracket)
			buf.WriteString(startTags[len(startTags)-1])
			buf.Write(rightAngleBracket)
			startTags = startTags[:len(startTags)-1]
		default:
			buf.WriteString(token.String())
		}
	}

	if io.EOF == tokenizer.Err() {
		return buf.Bytes()
	}

	// If we are not at the end of the input, then some other parsing error has occurred,
	// so return the input verbatim.
	return rawHtml
}
Example #10
0
// mailIssueCommentToParticipants can be used for both new issue creation and comment.
func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error {
	if !setting.Service.EnableNotifyMail {
		return nil
	}

	// Mail wahtcers.
	watchers, err := GetWatchers(issue.RepoID)
	if err != nil {
		return fmt.Errorf("GetWatchers [%d]: %v", issue.RepoID, err)
	}

	tos := make([]string, 0, len(watchers)) // List of email addresses.
	names := make([]string, 0, len(watchers))
	for i := range watchers {
		if watchers[i].UserID == doer.ID {
			continue
		}

		to, err := GetUserByID(watchers[i].UserID)
		if err != nil {
			return fmt.Errorf("GetUserByID [%d]: %v", watchers[i].UserID, err)
		}
		if to.IsOrganization() {
			continue
		}

		tos = append(tos, to.Email)
		names = append(names, to.Name)
	}
	SendIssueCommentMail(issue, doer, tos)

	// Mail mentioned people and exclude watchers.
	names = append(names, doer.Name)
	tos = make([]string, 0, len(mentions)) // list of user names.
	for i := range mentions {
		if com.IsSliceContainsStr(names, mentions[i]) {
			continue
		}

		tos = append(tos, mentions[i])
	}
	SendIssueMentionMail(issue, doer, GetUserEmailsByNames(tos))

	return nil
}
Example #11
0
func notifyWatchersAndMentions(ctx *middleware.Context, issue *models.Issue) {
	// Update mentions
	mentions := base.MentionPattern.FindAllString(issue.Content, -1)
	if len(mentions) > 0 {
		for i := range mentions {
			mentions[i] = strings.TrimSpace(mentions[i])[1:]
		}

		if err := models.UpdateMentions(mentions, issue.ID); err != nil {
			ctx.Handle(500, "UpdateMentions", err)
			return
		}
	}

	repo := ctx.Repo.Repository

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, repo, issue)
		if err != nil {
			ctx.Handle(500, "SendIssueNotifyMail", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(mentions))
		for _, m := range mentions {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			repo, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "SendIssueMentionMail", err)
			return
		}
	}
}
Example #12
0
func Issues(ctx *middleware.Context) {
	ctx.Data["Title"] = "Your Issues"

	viewType := ctx.Query("type")
	types := []string{"assigned", "created_by"}
	if !com.IsSliceContainsStr(types, viewType) {
		viewType = "all"
	}

	isShowClosed := ctx.Query("state") == "closed"

	var filterMode int
	switch viewType {
	case "assigned":
		filterMode = models.FM_ASSIGN
	case "created_by":
		filterMode = models.FM_CREATE
	}

	repoId, _ := com.StrTo(ctx.Query("repoid")).Int64()
	issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode)

	// Get all repositories.
	repos, err := models.GetRepositories(ctx.User.Id, true)
	if err != nil {
		ctx.Handle(500, "user.Issues(GetRepositories)", err)
		return
	}

	repoIds := make([]int64, 0, len(repos))
	showRepos := make([]*models.Repository, 0, len(repos))
	for _, repo := range repos {
		if repo.NumIssues == 0 {
			continue
		}

		repoIds = append(repoIds, repo.Id)
		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
		issueStats.AllCount += int64(repo.NumOpenIssues)

		if isShowClosed {
			if repo.NumClosedIssues > 0 {
				if filterMode == models.FM_CREATE {
					repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
				}
				showRepos = append(showRepos, repo)
			}
		} else {
			if repo.NumOpenIssues > 0 {
				if filterMode == models.FM_CREATE {
					repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
				}
				showRepos = append(showRepos, repo)
			}
		}
	}

	if repoId > 0 {
		repoIds = []int64{repoId}
	}

	page, _ := com.StrTo(ctx.Query("page")).Int()

	// Get all issues.
	var ius []*models.IssueUser
	switch viewType {
	case "assigned":
		fallthrough
	case "created_by":
		ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode)
	default:
		ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page)
	}
	if err != nil {
		ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err)
		return
	}

	issues := make([]*models.Issue, len(ius))
	for i := range ius {
		issues[i], err = models.GetIssueById(ius[i].IssueId)
		if err != nil {
			if err == models.ErrIssueNotExist {
				log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueId)
				continue
			} else {
				ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueId), err)
				return
			}
		}

		issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId)
		if err != nil {
			if err == models.ErrRepoNotExist {
				log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId)
				continue
			} else {
				ctx.Handle(500, fmt.Sprintf("user.Issues(GetRepositoryById #%d)", issues[i].RepoId), err)
				return
			}
		}

		if err = issues[i].Repo.GetOwner(); err != nil {
			ctx.Handle(500, "user.Issues(GetOwner)", err)
			return
		}

		if err = issues[i].GetPoster(); err != nil {
			ctx.Handle(500, "user.Issues(GetUserById)", err)
			return
		}
	}

	ctx.Data["RepoId"] = repoId
	ctx.Data["Repos"] = showRepos
	ctx.Data["Issues"] = issues
	ctx.Data["ViewType"] = viewType
	ctx.Data["IssueStats"] = issueStats
	ctx.Data["IsShowClosed"] = isShowClosed
	if isShowClosed {
		ctx.Data["State"] = "closed"
		ctx.Data["ShowCount"] = issueStats.ClosedCount
	} else {
		ctx.Data["ShowCount"] = issueStats.OpenCount
	}
	ctx.HTML(200, ISSUES)
}
Example #13
0
func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
	ctx.Data["Title"] = ctx.Tr("repo.issues.new")
	ctx.Data["PageIsIssueList"] = true
	ctx.Data["RequireDropzone"] = true
	ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
	ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
	ctx.Data["AttachmentMaxFiles"] = setting.AttachmentMaxFiles

	var (
		repo        = ctx.Repo.Repository
		labelIDs    []int64
		milestoneID int64
		assigneeID  int64
		attachments []string
	)
	if ctx.User.IsAdmin {
		// Check labels.
		labelIDs = base.StringsToInt64s(strings.Split(form.LabelIDs, ","))
		labelIDMark := base.Int64sToMap(labelIDs)
		labels, err := models.GetLabelsByRepoID(repo.ID)
		if err != nil {
			ctx.Handle(500, "GetLabelsByRepoID: %v", err)
			return
		}
		hasSelected := false
		for i := range labels {
			if labelIDMark[labels[i].ID] {
				labels[i].IsChecked = true
				hasSelected = true
			}
		}
		ctx.Data["HasSelectedLabel"] = hasSelected
		ctx.Data["label_ids"] = form.LabelIDs
		ctx.Data["Labels"] = labels

		// Check milestone.
		milestoneID = form.MilestoneID
		if milestoneID > 0 {
			ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
			if err != nil {
				ctx.Handle(500, "GetMilestones: %v", err)
				return
			}
			ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
			if err != nil {
				ctx.Handle(500, "GetMilestones: %v", err)
				return
			}
			ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID)
			if err != nil {
				ctx.Handle(500, "GetMilestoneByID: %v", err)
				return
			}
			ctx.Data["milestone_id"] = milestoneID
		}

		// Check assignee.
		assigneeID = form.AssigneeID
		if assigneeID > 0 {
			ctx.Data["Assignees"], err = repo.GetAssignees()
			if err != nil {
				ctx.Handle(500, "GetAssignees: %v", err)
				return
			}
			ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID)
			if err != nil {
				ctx.Handle(500, "GetAssigneeByID: %v", err)
				return
			}
			ctx.Data["assignee_id"] = assigneeID
		}
	}

	if setting.AttachmentEnabled {
		attachments = ctx.QueryStrings("attachments")
	}

	if ctx.HasError() {
		ctx.HTML(200, ISSUE_NEW)
		return
	}

	issue := &models.Issue{
		RepoID:      ctx.Repo.Repository.ID,
		Index:       int64(repo.NumIssues) + 1,
		Name:        form.Title,
		PosterID:    ctx.User.Id,
		Poster:      ctx.User,
		MilestoneID: milestoneID,
		AssigneeID:  assigneeID,
		Content:     form.Content,
	}
	if err := models.NewIssue(repo, issue, labelIDs, attachments); err != nil {
		ctx.Handle(500, "NewIssue", err)
		return
	}

	// Update mentions.
	mentions := base.MentionPattern.FindAllString(issue.Content, -1)
	if len(mentions) > 0 {
		for i := range mentions {
			mentions[i] = mentions[i][1:]
		}

		if err := models.UpdateMentions(mentions, issue.ID); err != nil {
			ctx.Handle(500, "UpdateMentions", err)
			return
		}
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			ctx.Handle(500, "SendIssueNotifyMail", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(mentions))
		for _, m := range mentions {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "SendIssueMentionMail", err)
			return
		}
	}

	log.Trace("Issue created: %d/%d", ctx.Repo.Repository.ID, issue.ID)
	ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
}
Example #14
0
// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook
func EditHook(ctx *context.APIContext, form api.EditHookOption) {
	w, err := models.GetWebhookByID(ctx.ParamsInt64(":id"))
	if err != nil {
		if models.IsErrWebhookNotExist(err) {
			ctx.Status(404)
		} else {
			ctx.Error(500, "GetWebhookByID", err)
		}
		return
	}

	if form.Config != nil {
		if url, ok := form.Config["url"]; ok {
			w.URL = url
		}
		if ct, ok := form.Config["content_type"]; ok {
			if !models.IsValidHookContentType(ct) {
				ctx.Error(422, "", "Invalid content type")
				return
			}
			w.ContentType = models.ToHookContentType(ct)
		}

		if w.HookTaskType == models.SLACK {
			if channel, ok := form.Config["channel"]; ok {
				meta, err := json.Marshal(&models.SlackMeta{
					Channel:  channel,
					Username: form.Config["username"],
					IconURL:  form.Config["icon_url"],
					Color:    form.Config["color"],
				})
				if err != nil {
					ctx.Error(500, "slack: JSON marshal failed", err)
					return
				}
				w.Meta = string(meta)
			}
		}
	}

	// Update events
	if len(form.Events) == 0 {
		form.Events = []string{"push"}
	}
	w.PushOnly = false
	w.SendEverything = false
	w.ChooseEvents = true
	w.Create = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE))
	w.Push = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH))
	if err = w.UpdateEvent(); err != nil {
		ctx.Error(500, "UpdateEvent", err)
		return
	}

	if form.Active != nil {
		w.IsActive = *form.Active
	}

	if err := models.UpdateWebhook(w); err != nil {
		ctx.Error(500, "UpdateWebhook", err)
		return
	}

	ctx.JSON(200, convert.ToHook(ctx.Repo.RepoLink, w))
}
Example #15
0
func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) {
	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
	if err != nil {
		if models.IsErrIssueNotExist(err) {
			ctx.Handle(404, "GetIssueByIndex", err)
		} else {
			ctx.Handle(500, "GetIssueByIndex", err)
		}
		return
	}

	var attachments []string
	if setting.AttachmentEnabled {
		attachments = form.Attachments
	}

	if ctx.HasError() {
		ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
		ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
		return
	}

	// Fix #321: Allow empty comments, as long as we have attachments.
	if len(form.Content) == 0 && len(attachments) == 0 {
		ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
		return
	}

	comment, err := models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments)
	if err != nil {
		ctx.Handle(500, "CreateIssueComment", err)
		return
	}

	// Update mentions.
	mentions := base.MentionPattern.FindAllString(comment.Content, -1)
	if len(mentions) > 0 {
		for i := range mentions {
			mentions[i] = mentions[i][1:]
		}

		if err := models.UpdateMentions(mentions, issue.ID); err != nil {
			ctx.Handle(500, "UpdateMentions", err)
			return
		}
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		issue.Content = form.Content
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			ctx.Handle(500, "SendIssueNotifyMail", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(mentions))
		for _, m := range mentions {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "SendIssueMentionMail", err)
			return
		}
	}
	log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID)

	// Check if issue owner/poster changes the status of issue.
	if (ctx.Repo.IsOwner() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) &&
		(form.Status == "reopen" || form.Status == "close") &&
		!(issue.IsPull && issue.HasMerged) {
		issue.Repo = ctx.Repo.Repository
		if err = issue.ChangeStatus(ctx.User, form.Status == "close"); err != nil {
			ctx.Handle(500, "ChangeStatus", err)
			return
		}
		log.Trace("Issue[%d] status changed: %v", issue.ID, !issue.IsClosed)
	}

	ctx.Redirect(fmt.Sprintf("%s/issues/%d#%s", ctx.Repo.RepoLink, issue.Index, comment.HashTag()))
}
Example #16
0
func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
	ctx.Data["Title"] = ctx.Tr("repo.issues.new")
	ctx.Data["PageIsIssueList"] = true
	renderAttachmentSettings(ctx)

	var (
		repo        = ctx.Repo.Repository
		attachments []string
	)

	labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
	if ctx.Written() {
		return
	}

	if setting.AttachmentEnabled {
		attachments = form.Attachments
	}

	if ctx.HasError() {
		ctx.HTML(200, ISSUE_NEW)
		return
	}

	issue := &models.Issue{
		RepoID:      ctx.Repo.Repository.ID,
		Index:       repo.NextIssueIndex(),
		Name:        form.Title,
		PosterID:    ctx.User.Id,
		Poster:      ctx.User,
		MilestoneID: milestoneID,
		AssigneeID:  assigneeID,
		Content:     form.Content,
	}
	if err := models.NewIssue(repo, issue, labelIDs, attachments); err != nil {
		ctx.Handle(500, "NewIssue", err)
		return
	}

	// Update mentions.
	mentions := base.MentionPattern.FindAllString(issue.Content, -1)
	if len(mentions) > 0 {
		for i := range mentions {
			mentions[i] = mentions[i][1:]
		}

		if err := models.UpdateMentions(mentions, issue.ID); err != nil {
			ctx.Handle(500, "UpdateMentions", err)
			return
		}
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, repo, issue)
		if err != nil {
			ctx.Handle(500, "SendIssueNotifyMail", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(mentions))
		for _, m := range mentions {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			repo, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "SendIssueMentionMail", err)
			return
		}
	}

	log.Trace("Issue created: %d/%d", repo.ID, issue.ID)
	ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
}
Example #17
0
func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
	ctx.Data["Title"] = "Create issue"
	ctx.Data["IsRepoToolbarIssues"] = true
	ctx.Data["IsRepoToolbarIssuesList"] = false

	var err error
	// Get all milestones.
	ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false)
	if err != nil {
		ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
		return
	}
	ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true)
	if err != nil {
		ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
		return
	}

	us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
	if err != nil {
		ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
		return
	}
	ctx.Data["Collaborators"] = us

	if ctx.HasError() {
		ctx.HTML(200, ISSUE_CREATE)
		return
	}

	// Only collaborators can assign.
	if !ctx.Repo.IsOwner {
		form.AssigneeId = 0
	}
	issue := &models.Issue{
		RepoId:      ctx.Repo.Repository.Id,
		Index:       int64(ctx.Repo.Repository.NumIssues) + 1,
		Name:        form.IssueName,
		PosterId:    ctx.User.Id,
		MilestoneId: form.MilestoneId,
		AssigneeId:  form.AssigneeId,
		LabelIds:    form.Labels,
		Content:     form.Content,
	}
	if err := models.NewIssue(issue); err != nil {
		ctx.Handle(500, "issue.CreateIssue(NewIssue)", err)
		return
	} else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id, ctx.Repo.Owner.Id,
		ctx.User.Id, form.AssigneeId, ctx.Repo.Repository.Name); err != nil {
		ctx.Handle(500, "issue.CreateIssue(NewIssueUserPairs)", err)
		return
	}

	// Update mentions.
	ms := base.MentionPattern.FindAllString(issue.Content, -1)
	if len(ms) > 0 {
		for i := range ms {
			ms[i] = ms[i][1:]
		}

		ids := models.GetUserIdsByNames(ms)
		if err := models.UpdateIssueUserPairsByMentions(ids, issue.Id); err != nil {
			ctx.Handle(500, "issue.CreateIssue(UpdateIssueUserPairsByMentions)", err)
			return
		}
	}

	act := &models.Action{
		ActUserId:    ctx.User.Id,
		ActUserName:  ctx.User.Name,
		ActEmail:     ctx.User.Email,
		OpType:       models.OP_CREATE_ISSUE,
		Content:      fmt.Sprintf("%d|%s", issue.Index, issue.Name),
		RepoId:       ctx.Repo.Repository.Id,
		RepoUserName: ctx.Repo.Owner.Name,
		RepoName:     ctx.Repo.Repository.Name,
		RefName:      ctx.Repo.BranchName,
		IsPrivate:    ctx.Repo.Repository.IsPrivate,
	}
	// Notify watchers.
	if err := models.NotifyWatchers(act); err != nil {
		ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err)
		return
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			ctx.Handle(500, "issue.CreateIssue(SendIssueNotifyMail)", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(ms))
		for _, m := range ms {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "issue.CreateIssue(SendIssueMentionMail)", err)
			return
		}
	}
	log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)

	ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
}
Example #18
0
func Issues(ctx *middleware.Context) {
	isPullList := ctx.Params(":type") == "pulls"
	if isPullList {
		ctx.Data["Title"] = ctx.Tr("repo.pulls")
		ctx.Data["PageIsPullList"] = true
		ctx.Data["HasForkedRepo"] = ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)

	} else {
		MustEnableIssues(ctx)
		if ctx.Written() {
			return
		}
		ctx.Data["Title"] = ctx.Tr("repo.issues")
		ctx.Data["PageIsIssueList"] = true
	}

	viewType := ctx.Query("type")
	sortType := ctx.Query("sort")
	types := []string{"assigned", "created_by", "mentioned"}
	if !com.IsSliceContainsStr(types, viewType) {
		viewType = "all"
	}

	// Must sign in to see issues about you.
	if viewType != "all" && !ctx.IsSigned {
		ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
		ctx.Redirect(setting.AppSubUrl + "/user/login")
		return
	}

	var (
		assigneeID = ctx.QueryInt64("assignee")
		posterID   int64
	)
	filterMode := models.FM_ALL
	switch viewType {
	case "assigned":
		filterMode = models.FM_ASSIGN
		assigneeID = ctx.User.Id
	case "created_by":
		filterMode = models.FM_CREATE
		posterID = ctx.User.Id
	case "mentioned":
		filterMode = models.FM_MENTION
	}

	var uid int64 = -1
	if ctx.IsSigned {
		uid = ctx.User.Id
	}

	repo := ctx.Repo.Repository
	selectLabels := ctx.Query("labels")
	milestoneID := ctx.QueryInt64("milestone")
	isShowClosed := ctx.Query("state") == "closed"
	issueStats := models.GetIssueStats(&models.IssueStatsOptions{
		RepoID:      repo.ID,
		UserID:      uid,
		LabelID:     com.StrTo(selectLabels).MustInt64(),
		MilestoneID: milestoneID,
		AssigneeID:  assigneeID,
		FilterMode:  filterMode,
		IsPull:      isPullList,
	})

	page := ctx.QueryInt("page")
	if page <= 1 {
		page = 1
	}

	var total int
	if !isShowClosed {
		total = int(issueStats.OpenCount)
	} else {
		total = int(issueStats.ClosedCount)
	}
	pager := paginater.New(total, setting.IssuePagingNum, page, 5)
	ctx.Data["Page"] = pager

	// Get issues.
	issues, err := models.Issues(&models.IssuesOptions{
		UserID:      uid,
		AssigneeID:  assigneeID,
		RepoID:      repo.ID,
		PosterID:    posterID,
		MilestoneID: milestoneID,
		Page:        pager.Current(),
		IsClosed:    isShowClosed,
		IsMention:   filterMode == models.FM_MENTION,
		IsPull:      isPullList,
		Labels:      selectLabels,
		SortType:    sortType,
	})
	if err != nil {
		ctx.Handle(500, "Issues: %v", err)
		return
	}

	// Get issue-user relations.
	pairs, err := models.GetIssueUsers(repo.ID, posterID, isShowClosed)
	if err != nil {
		ctx.Handle(500, "GetIssueUsers: %v", err)
		return
	}

	// Get posters.
	for i := range issues {
		if err = issues[i].GetPoster(); err != nil {
			ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if err = issues[i].GetLabels(); err != nil {
			ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if !ctx.IsSigned {
			issues[i].IsRead = true
			continue
		}

		// Check read status.
		idx := models.PairsContains(pairs, issues[i].ID, ctx.User.Id)
		if idx > -1 {
			issues[i].IsRead = pairs[idx].IsRead
		} else {
			issues[i].IsRead = true
		}
	}
	ctx.Data["Issues"] = issues

	// Get milestones.
	ctx.Data["Milestones"], err = models.GetAllRepoMilestones(repo.ID)
	if err != nil {
		ctx.Handle(500, "GetAllRepoMilestones: %v", err)
		return
	}

	// Get assignees.
	ctx.Data["Assignees"], err = repo.GetAssignees()
	if err != nil {
		ctx.Handle(500, "GetAssignees: %v", err)
		return
	}

	ctx.Data["IssueStats"] = issueStats
	ctx.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64()
	ctx.Data["ViewType"] = viewType
	ctx.Data["SortType"] = sortType
	ctx.Data["MilestoneID"] = milestoneID
	ctx.Data["AssigneeID"] = assigneeID
	ctx.Data["IsShowClosed"] = isShowClosed
	if isShowClosed {
		ctx.Data["State"] = "closed"
	} else {
		ctx.Data["State"] = "open"
	}

	ctx.HTML(200, ISSUES)
}
Example #19
0
// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook
func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) {
	w, err := models.GetWebhookByID(ctx.ParamsInt64(":id"))
	if err != nil {
		ctx.JSON(500, &base.ApiJsonErr{"GetWebhookById: " + err.Error(), base.DOC_URL})
		return
	}

	if form.Config != nil {
		if url, ok := form.Config["url"]; ok {
			w.URL = url
		}
		if ct, ok := form.Config["content_type"]; ok {
			if !models.IsValidHookContentType(ct) {
				ctx.JSON(422, &base.ApiJsonErr{"invalid content type", base.DOC_URL})
				return
			}
			w.ContentType = models.ToHookContentType(ct)
		}

		if w.HookTaskType == models.SLACK {
			if channel, ok := form.Config["channel"]; ok {
				meta, err := json.Marshal(&models.SlackMeta{
					Channel:  channel,
					Username: form.Config["username"],
					IconURL:  form.Config["icon_url"],
					Color:    form.Config["color"],
				})
				if err != nil {
					ctx.JSON(500, &base.ApiJsonErr{"slack: JSON marshal failed: " + err.Error(), base.DOC_URL})
					return
				}
				w.Meta = string(meta)
			}
		}
	}

	// Update events
	if len(form.Events) == 0 {
		form.Events = []string{"push"}
	}
	w.PushOnly = false
	w.SendEverything = false
	w.ChooseEvents = true
	w.Create = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE))
	w.Push = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH))
	if err = w.UpdateEvent(); err != nil {
		ctx.JSON(500, &base.ApiJsonErr{"UpdateEvent: " + err.Error(), base.DOC_URL})
		return
	}

	if form.Active != nil {
		w.IsActive = *form.Active
	}

	if err := models.UpdateWebhook(w); err != nil {
		ctx.JSON(500, &base.ApiJsonErr{"UpdateWebhook: " + err.Error(), base.DOC_URL})
		return
	}

	ctx.JSON(200, ToApiHook(ctx.Repo.RepoLink, w))
}
Example #20
0
func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params Params) {
	if leaf.regexps == nil {
		if len(wildcardValues) == 0 && len(leaf.wildcards) > 0 {
			if com.IsSliceContainsStr(leaf.wildcards, ":") {
				params = make(map[string]string)
				j := 0
				for _, v := range leaf.wildcards {
					if v == ":" {
						continue
					}
					params[v] = ""
					j += 1
				}
				return true, params
			}
			return false, nil
		} else if len(wildcardValues) == 0 {
			return true, nil // Static path.
		}

		// Match *
		if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" {
			params = make(map[string]string)
			params[":splat"] = path.Join(wildcardValues...)
			return true, params
		}

		// Match *.*
		if len(leaf.wildcards) == 3 && leaf.wildcards[0] == "." {
			params = make(map[string]string)
			lastone := wildcardValues[len(wildcardValues)-1]
			strs := strings.SplitN(lastone, ".", 2)
			if len(strs) == 2 {
				params[":ext"] = strs[1]
			} else {
				params[":ext"] = ""
			}
			params[":path"] = path.Join(wildcardValues[:len(wildcardValues)-1]...) + "/" + strs[0]
			return true, params
		}

		// Match :id
		params = make(map[string]string)
		j := 0
		for _, v := range leaf.wildcards {
			if v == ":" {
				continue
			}
			if v == "." {
				lastone := wildcardValues[len(wildcardValues)-1]
				strs := strings.SplitN(lastone, ".", 2)
				if len(strs) == 2 {
					params[":ext"] = strs[1]
				} else {
					params[":ext"] = ""
				}
				if len(wildcardValues[j:]) == 1 {
					params[":path"] = strs[0]
				} else {
					params[":path"] = path.Join(wildcardValues[j:]...) + "/" + strs[0]
				}
				return true, params
			}
			if len(wildcardValues) <= j {
				return false, nil
			}
			params[v] = wildcardValues[j]
			j++
		}
		if len(params) != len(wildcardValues) {
			return false, nil
		}
		return true, params
	}

	if !leaf.regexps.MatchString(path.Join(wildcardValues...)) {
		return false, nil
	}
	params = make(map[string]string)
	matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
	for i, match := range matches[1:] {
		params[leaf.wildcards[i]] = match
	}
	return true, params
}
Example #21
0
func Comment(ctx *middleware.Context) {
	send := func(status int, data interface{}, err error) {
		if err != nil {
			log.Error(4, "issue.Comment(?): %s", err)

			ctx.JSON(status, map[string]interface{}{
				"ok":     false,
				"status": status,
				"error":  err.Error(),
			})
		} else {
			ctx.JSON(status, map[string]interface{}{
				"ok":     true,
				"status": status,
				"data":   data,
			})
		}
	}

	index := com.StrTo(ctx.Query("issueIndex")).MustInt64()
	if index == 0 {
		ctx.Error(404)
		return
	}

	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
	if err != nil {
		if err == models.ErrIssueNotExist {
			send(404, nil, err)
		} else {
			send(200, nil, err)
		}

		return
	}

	// Check if issue owner changes the status of issue.
	var newStatus string
	if ctx.Repo.IsOwner() || issue.PosterId == ctx.User.Id {
		newStatus = ctx.Query("change_status")
	}
	if len(newStatus) > 0 {
		if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
			(strings.Contains(newStatus, "Close") && !issue.IsClosed) {
			issue.IsClosed = !issue.IsClosed
			if err = models.UpdateIssue(issue); err != nil {
				send(500, nil, err)
				return
			} else if err = models.UpdateIssueUserPairsByStatus(issue.ID, issue.IsClosed); err != nil {
				send(500, nil, err)
				return
			}

			if err = issue.GetLabels(); err != nil {
				send(500, nil, err)
				return
			}

			for _, label := range issue.Labels {
				if issue.IsClosed {
					label.NumClosedIssues++
				} else {
					label.NumClosedIssues--
				}

				if err = models.UpdateLabel(label); err != nil {
					send(500, nil, err)
					return
				}
			}

			// Change open/closed issue counter for the associated milestone
			if issue.MilestoneId > 0 {
				if err = models.ChangeMilestoneIssueStats(issue); err != nil {
					send(500, nil, err)
				}
			}

			cmtType := models.COMMENT_TYPE_CLOSE
			if !issue.IsClosed {
				cmtType = models.COMMENT_TYPE_REOPEN
			}

			if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, cmtType, "", nil); err != nil {
				send(200, nil, err)
				return
			}
			log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.ID, !issue.IsClosed)
		}
	}

	var comment *models.Comment

	var ms []string
	content := ctx.Query("content")
	// Fix #321. Allow empty comments, as long as we have attachments.
	if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 {
		switch ctx.Params(":action") {
		case "new":
			if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil {
				send(500, nil, err)
				return
			}

			// Update mentions.
			ms = base.MentionPattern.FindAllString(issue.Content, -1)
			if len(ms) > 0 {
				for i := range ms {
					ms[i] = ms[i][1:]
				}

				if err := models.UpdateMentions(ms, issue.ID); err != nil {
					send(500, nil, err)
					return
				}
			}

			log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.ID)
		default:
			ctx.Handle(404, "issue.Comment", err)
			return
		}
	}

	if comment != nil {
		uploadFiles(ctx, issue.ID, comment.Id)
	}

	// Notify watchers.
	act := &models.Action{
		ActUserID:    ctx.User.Id,
		ActUserName:  ctx.User.LowerName,
		ActEmail:     ctx.User.Email,
		OpType:       models.COMMENT_ISSUE,
		Content:      fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
		RepoID:       ctx.Repo.Repository.Id,
		RepoUserName: ctx.Repo.Owner.LowerName,
		RepoName:     ctx.Repo.Repository.LowerName,
		IsPrivate:    ctx.Repo.Repository.IsPrivate,
	}
	if err = models.NotifyWatchers(act); err != nil {
		send(500, nil, err)
		return
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		issue.Content = content
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			send(500, nil, err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(ms))
		for _, m := range ms {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			send(500, nil, err)
			return
		}
	}

	send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil)
}
Example #22
0
// InitRepository initializes README and .gitignore if needed.
func initRepository(e Engine, repoPath string, u *User, repo *Repository, initReadme bool, repoLang, license string) error {
	// Somehow the directory could exist.
	if com.IsExist(repoPath) {
		return fmt.Errorf("initRepository: path already exists: %s", repoPath)
	}

	// Init bare new repository.
	os.MkdirAll(repoPath, os.ModePerm)
	_, stderr, err := process.ExecDir(-1, repoPath,
		fmt.Sprintf("initRepository(git init --bare): %s", repoPath),
		"git", "init", "--bare")
	if err != nil {
		return fmt.Errorf("git init --bare: %s", err)
	}

	if err := createUpdateHook(repoPath); err != nil {
		return err
	}

	// Initialize repository according to user's choice.
	fileName := map[string]string{}
	if initReadme {
		fileName["readme"] = "README.md"
	}
	if repoLang != "" {
		fileName["gitign"] = ".gitignore"
	}
	if license != "" {
		fileName["license"] = "LICENSE"
	}

	// Clone to temprory path and do the init commit.
	tmpDir := filepath.Join(os.TempDir(), com.ToStr(time.Now().Nanosecond()))
	os.MkdirAll(tmpDir, os.ModePerm)
	defer os.RemoveAll(tmpDir)

	_, stderr, err = process.Exec(
		fmt.Sprintf("initRepository(git clone): %s", repoPath),
		"git", "clone", repoPath, tmpDir)
	if err != nil {
		return errors.New("git clone: " + stderr)
	}

	// README
	if initReadme {
		defaultReadme := repo.Name + "\n" + strings.Repeat("=",
			utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description
		if err := ioutil.WriteFile(filepath.Join(tmpDir, fileName["readme"]),
			[]byte(defaultReadme), 0644); err != nil {
			return err
		}
	}

	// FIXME: following two can be merged.

	// .gitignore
	// Copy custom file when available.
	customPath := path.Join(setting.CustomPath, "conf/gitignore", repoLang)
	targetPath := path.Join(tmpDir, fileName["gitign"])
	if com.IsFile(customPath) {
		if err := com.Copy(customPath, targetPath); err != nil {
			return fmt.Errorf("copy gitignore: %v", err)
		}
	} else if com.IsSliceContainsStr(Gitignores, repoLang) {
		if err = ioutil.WriteFile(targetPath,
			bindata.MustAsset(path.Join("conf/gitignore", repoLang)), 0644); err != nil {
			return fmt.Errorf("generate gitignore: %v", err)
		}
	} else {
		delete(fileName, "gitign")
	}

	// LICENSE
	customPath = path.Join(setting.CustomPath, "conf/license", license)
	targetPath = path.Join(tmpDir, fileName["license"])
	if com.IsFile(customPath) {
		if err = com.Copy(customPath, targetPath); err != nil {
			return fmt.Errorf("copy license: %v", err)
		}
	} else if com.IsSliceContainsStr(Licenses, license) {
		if err = ioutil.WriteFile(targetPath,
			bindata.MustAsset(path.Join("conf/license", license)), 0644); err != nil {
			return fmt.Errorf("generate license: %v", err)
		}
	} else {
		delete(fileName, "license")
	}

	if len(fileName) == 0 {
		// Re-fetch the repository from database before updating it (else it would
		// override changes that were done earlier with sql)
		if repo, err = getRepositoryById(e, repo.Id); err != nil {
			return err
		}
		repo.IsBare = true
		repo.DefaultBranch = "master"
		return updateRepository(e, repo, false)
	}

	// Apply changes and commit.
	return initRepoCommit(tmpDir, u.NewGitSig())
}
Example #23
0
func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
	send := func(status int, data interface{}, err error) {
		if err != nil {
			log.Error(4, "issue.CreateIssuePost(?): %s", err)

			ctx.JSON(status, map[string]interface{}{
				"ok":     false,
				"status": status,
				"error":  err.Error(),
			})
		} else {
			ctx.JSON(status, map[string]interface{}{
				"ok":     true,
				"status": status,
				"data":   data,
			})
		}
	}

	var err error
	// Get all milestones.
	_, err = models.GetMilestones(ctx.Repo.Repository.Id, false)
	if err != nil {
		send(500, nil, err)
		return
	}
	_, err = models.GetMilestones(ctx.Repo.Repository.Id, true)
	if err != nil {
		send(500, nil, err)
		return
	}

	_, err = ctx.Repo.Repository.GetCollaborators()
	if err != nil {
		send(500, nil, err)
		return
	}

	if ctx.HasError() {
		send(400, nil, errors.New(ctx.Flash.ErrorMsg))
		return
	}

	// Only collaborators can assign.
	if !ctx.Repo.IsOwner() {
		form.AssigneeId = 0
	}
	issue := &models.Issue{
		RepoId:      ctx.Repo.Repository.Id,
		Index:       int64(ctx.Repo.Repository.NumIssues) + 1,
		Name:        form.IssueName,
		PosterId:    ctx.User.Id,
		MilestoneId: form.MilestoneId,
		AssigneeId:  form.AssigneeId,
		LabelIds:    form.Labels,
		Content:     form.Content,
	}
	if err := models.NewIssue(issue); err != nil {
		send(500, nil, err)
		return
	} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.ID, ctx.Repo.Owner.Id,
		ctx.User.Id, form.AssigneeId); err != nil {
		send(500, nil, err)
		return
	}

	if setting.AttachmentEnabled {
		uploadFiles(ctx, issue.ID, 0)
	}

	// Update mentions.
	ms := base.MentionPattern.FindAllString(issue.Content, -1)
	if len(ms) > 0 {
		for i := range ms {
			ms[i] = ms[i][1:]
		}

		if err := models.UpdateMentions(ms, issue.ID); err != nil {
			send(500, nil, err)
			return
		}
	}

	act := &models.Action{
		ActUserID:    ctx.User.Id,
		ActUserName:  ctx.User.Name,
		ActEmail:     ctx.User.Email,
		OpType:       models.CREATE_ISSUE,
		Content:      fmt.Sprintf("%d|%s", issue.Index, issue.Name),
		RepoID:       ctx.Repo.Repository.Id,
		RepoUserName: ctx.Repo.Owner.Name,
		RepoName:     ctx.Repo.Repository.Name,
		RefName:      ctx.Repo.BranchName,
		IsPrivate:    ctx.Repo.Repository.IsPrivate,
	}
	// Notify watchers.
	if err := models.NotifyWatchers(act); err != nil {
		send(500, nil, err)
		return
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			send(500, nil, err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(ms))
		for _, m := range ms {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			send(500, nil, err)
			return
		}
	}
	log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.ID)

	send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil)
}
Example #24
0
func Comment(ctx *middleware.Context, params martini.Params) {
	index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
	if err != nil {
		ctx.Handle(404, "issue.Comment(get index)", err)
		return
	}

	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
	if err != nil {
		if err == models.ErrIssueNotExist {
			ctx.Handle(404, "issue.Comment", err)
		} else {
			ctx.Handle(200, "issue.Comment(get issue)", err)
		}
		return
	}

	// Check if issue owner changes the status of issue.
	var newStatus string
	if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
		newStatus = ctx.Query("change_status")
	}
	if len(newStatus) > 0 {
		if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
			(strings.Contains(newStatus, "Close") && !issue.IsClosed) {
			issue.IsClosed = !issue.IsClosed
			if err = models.UpdateIssue(issue); err != nil {
				ctx.Handle(500, "issue.Comment(UpdateIssue)", err)
				return
			} else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
				ctx.Handle(500, "issue.Comment(UpdateIssueUserPairsByStatus)", err)
				return
			}

			cmtType := models.IT_CLOSE
			if !issue.IsClosed {
				cmtType = models.IT_REOPEN
			}

			if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil {
				ctx.Handle(200, "issue.Comment(create status change comment)", err)
				return
			}
			log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
		}
	}

	var ms []string
	content := ctx.Query("content")
	if len(content) > 0 {
		switch params["action"] {
		case "new":
			if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil {
				ctx.Handle(500, "issue.Comment(create comment)", err)
				return
			}

			// Update mentions.
			ms = base.MentionPattern.FindAllString(issue.Content, -1)
			if len(ms) > 0 {
				for i := range ms {
					ms[i] = ms[i][1:]
				}

				ids := models.GetUserIdsByNames(ms)
				if err := models.UpdateIssueUserPairsByMentions(ids, issue.Id); err != nil {
					ctx.Handle(500, "issue.CreateIssue(UpdateIssueUserPairsByMentions)", err)
					return
				}
			}

			log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
		default:
			ctx.Handle(404, "issue.Comment", err)
			return
		}
	}

	// Notify watchers.
	act := &models.Action{
		ActUserId:    ctx.User.Id,
		ActUserName:  ctx.User.LowerName,
		ActEmail:     ctx.User.Email,
		OpType:       models.OP_COMMENT_ISSUE,
		Content:      fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
		RepoId:       ctx.Repo.Repository.Id,
		RepoUserName: ctx.Repo.Owner.LowerName,
		RepoName:     ctx.Repo.Repository.LowerName,
	}
	if err = models.NotifyWatchers(act); err != nil {
		ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err)
		return
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		issue.Content = content
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
		if err != nil {
			ctx.Handle(500, "issue.Comment(SendIssueNotifyMail)", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(ms))
		for _, m := range ms {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "issue.Comment(SendIssueMentionMail)", err)
			return
		}
	}

	ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index))
}
Example #25
0
func Issues(ctx *middleware.Context) {
	ctx.Data["Title"] = "Issues"
	ctx.Data["IsRepoToolbarIssues"] = true
	ctx.Data["IsRepoToolbarIssuesList"] = true

	viewType := ctx.Query("type")
	types := []string{"assigned", "created_by", "mentioned"}
	if !com.IsSliceContainsStr(types, viewType) {
		viewType = "all"
	}

	isShowClosed := ctx.Query("state") == "closed"

	if viewType != "all" && !ctx.IsSigned {
		ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
		ctx.Redirect("/user/login")
		return
	}

	var assigneeId, posterId int64
	var filterMode int
	switch viewType {
	case "assigned":
		assigneeId = ctx.User.Id
		filterMode = models.FM_ASSIGN
	case "created_by":
		posterId = ctx.User.Id
		filterMode = models.FM_CREATE
	case "mentioned":
		filterMode = models.FM_MENTION
	}

	var mid int64
	midx, _ := base.StrTo(ctx.Query("milestone")).Int64()
	if midx > 0 {
		mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, midx)
		if err != nil {
			ctx.Handle(500, "issue.Issues(GetMilestoneByIndex): %v", err)
			return
		}
		mid = mile.Id
	}

	selectLabels := ctx.Query("labels")
	labels, err := models.GetLabels(ctx.Repo.Repository.Id)
	if err != nil {
		ctx.Handle(500, "issue.Issues(GetLabels): %v", err)
		return
	}
	for _, l := range labels {
		l.CalOpenIssues()
	}
	ctx.Data["Labels"] = labels

	page, _ := base.StrTo(ctx.Query("page")).Int()

	// Get issues.
	issues, err := models.GetIssues(assigneeId, ctx.Repo.Repository.Id, posterId, mid, page,
		isShowClosed, selectLabels, ctx.Query("sortType"))
	if err != nil {
		ctx.Handle(500, "issue.Issues(GetIssues): %v", err)
		return
	}

	// Get issue-user pairs.
	pairs, err := models.GetIssueUserPairs(ctx.Repo.Repository.Id, posterId, isShowClosed)
	if err != nil {
		ctx.Handle(500, "issue.Issues(GetIssueUserPairs): %v", err)
		return
	}

	// Get posters.
	for i := range issues {
		if err = issues[i].GetLabels(); err != nil {
			ctx.Handle(500, "issue.Issues(GetLabels)", fmt.Errorf("[#%d]%v", issues[i].Id, err))
			return
		}

		idx := models.PairsContains(pairs, issues[i].Id)

		if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) {
			continue
		}

		if idx > -1 {
			issues[i].IsRead = pairs[idx].IsRead
		} else {
			issues[i].IsRead = true
		}

		if err = issues[i].GetPoster(); err != nil {
			ctx.Handle(500, "issue.Issues(GetPoster)", fmt.Errorf("[#%d]%v", issues[i].Id, err))
			return
		}
	}

	var uid int64 = -1
	if ctx.User != nil {
		uid = ctx.User.Id
	}
	issueStats := models.GetIssueStats(ctx.Repo.Repository.Id, uid, isShowClosed, filterMode)
	ctx.Data["IssueStats"] = issueStats
	ctx.Data["SelectLabels"], _ = base.StrTo(selectLabels).Int64()
	ctx.Data["ViewType"] = viewType
	ctx.Data["Issues"] = issues
	ctx.Data["IsShowClosed"] = isShowClosed
	if isShowClosed {
		ctx.Data["State"] = "closed"
		ctx.Data["ShowCount"] = issueStats.ClosedCount
	} else {
		ctx.Data["ShowCount"] = issueStats.OpenCount
	}
	ctx.HTML(200, ISSUES)
}
Example #26
0
File: home.go Project: Janfred/gogs
func Issues(ctx *middleware.Context) {
	isPullList := ctx.Params(":type") == "pulls"
	if isPullList {
		ctx.Data["Title"] = ctx.Tr("pull_requests")
		ctx.Data["PageIsPulls"] = true
	} else {
		ctx.Data["Title"] = ctx.Tr("issues")
		ctx.Data["PageIsIssues"] = true
	}

	ctxUser := getDashboardContextUser(ctx)
	if ctx.Written() {
		return
	}

	// Organization does not have view type and filter mode.
	var (
		viewType   string
		sortType   = ctx.Query("sort")
		filterMode = models.FM_ALL
		assigneeID int64
		posterID   int64
	)
	if ctxUser.IsOrganization() {
		viewType = "all"
	} else {
		viewType = ctx.Query("type")
		types := []string{"assigned", "created_by"}
		if !com.IsSliceContainsStr(types, viewType) {
			viewType = "all"
		}

		switch viewType {
		case "assigned":
			filterMode = models.FM_ASSIGN
			assigneeID = ctxUser.Id
		case "created_by":
			filterMode = models.FM_CREATE
			posterID = ctxUser.Id
		}
	}

	repoID := ctx.QueryInt64("repo")
	isShowClosed := ctx.Query("state") == "closed"

	// Get repositories.
	repos, err := models.GetRepositories(ctxUser.Id, true)
	if err != nil {
		ctx.Handle(500, "GetRepositories", err)
		return
	}

	allCount := 0
	repoIDs := make([]int64, 0, len(repos))
	showRepos := make([]*models.Repository, 0, len(repos))
	for _, repo := range repos {
		if (isPullList && repo.NumPulls == 0) ||
			(!isPullList && repo.NumIssues == 0) {
			continue
		}

		repoIDs = append(repoIDs, repo.ID)

		if isPullList {
			allCount += repo.NumOpenPulls
			repo.NumOpenIssues = repo.NumOpenPulls
			repo.NumClosedIssues = repo.NumClosedPulls
		} else {
			allCount += repo.NumOpenIssues
		}

		if filterMode != models.FM_ALL {
			// Calculate repository issue count with filter mode.
			numOpen, numClosed := repo.IssueStats(ctxUser.Id, filterMode, isPullList)
			repo.NumOpenIssues, repo.NumClosedIssues = int(numOpen), int(numClosed)
		}

		if repo.ID == repoID ||
			(isShowClosed && repo.NumClosedIssues > 0) ||
			(!isShowClosed && repo.NumOpenIssues > 0) {
			showRepos = append(showRepos, repo)
		}
	}
	ctx.Data["Repos"] = showRepos

	issueStats := models.GetUserIssueStats(repoID, ctxUser.Id, repoIDs, filterMode, isPullList)
	issueStats.AllCount = int64(allCount)

	page := ctx.QueryInt("page")
	if page <= 1 {
		page = 1
	}

	var total int
	if !isShowClosed {
		total = int(issueStats.OpenCount)
	} else {
		total = int(issueStats.ClosedCount)
	}
	ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5)

	// Get issues.
	issues, err := models.Issues(&models.IssuesOptions{
		UserID:     ctxUser.Id,
		AssigneeID: assigneeID,
		RepoID:     repoID,
		PosterID:   posterID,
		RepoIDs:    repoIDs,
		Page:       page,
		IsClosed:   isShowClosed,
		IsPull:     isPullList,
		SortType:   sortType,
	})
	if err != nil {
		ctx.Handle(500, "Issues: %v", err)
		return
	}

	// Get posters and repository.
	for i := range issues {
		issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID)
		if err != nil {
			ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if err = issues[i].Repo.GetOwner(); err != nil {
			ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if err = issues[i].GetPoster(); err != nil {
			ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}
	}
	ctx.Data["Issues"] = issues

	ctx.Data["IssueStats"] = issueStats
	ctx.Data["ViewType"] = viewType
	ctx.Data["SortType"] = sortType
	ctx.Data["RepoID"] = repoID
	ctx.Data["IsShowClosed"] = isShowClosed
	if isShowClosed {
		ctx.Data["State"] = "closed"
	} else {
		ctx.Data["State"] = "open"
	}

	ctx.HTML(200, ISSUES)
}
Example #27
0
// https://github.com/gogits/go-gogs-client/wiki/Repositories#create-a-hook
func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) {
	if !models.IsValidHookTaskType(form.Type) {
		ctx.JSON(422, &base.ApiJsonErr{"invalid hook type", base.DOC_URL})
		return
	}
	for _, name := range []string{"url", "content_type"} {
		if _, ok := form.Config[name]; !ok {
			ctx.JSON(422, &base.ApiJsonErr{"missing config option: " + name, base.DOC_URL})
			return
		}
	}
	if !models.IsValidHookContentType(form.Config["content_type"]) {
		ctx.JSON(422, &base.ApiJsonErr{"invalid content type", base.DOC_URL})
		return
	}

	if len(form.Events) == 0 {
		form.Events = []string{"push"}
	}
	w := &models.Webhook{
		RepoID:      ctx.Repo.Repository.ID,
		URL:         form.Config["url"],
		ContentType: models.ToHookContentType(form.Config["content_type"]),
		Secret:      form.Config["secret"],
		HookEvent: &models.HookEvent{
			ChooseEvents: true,
			HookEvents: models.HookEvents{
				Create: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE)),
				Push:   com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH)),
			},
		},
		IsActive:     form.Active,
		HookTaskType: models.ToHookTaskType(form.Type),
	}
	if w.HookTaskType == models.SLACK {
		channel, ok := form.Config["channel"]
		if !ok {
			ctx.JSON(422, &base.ApiJsonErr{"missing config option: channel", base.DOC_URL})
			return
		}
		meta, err := json.Marshal(&models.SlackMeta{
			Channel:  channel,
			Username: form.Config["username"],
			IconURL:  form.Config["icon_url"],
			Color:    form.Config["color"],
		})
		if err != nil {
			ctx.JSON(500, &base.ApiJsonErr{"slack: JSON marshal failed: " + err.Error(), base.DOC_URL})
			return
		}
		w.Meta = string(meta)
	}

	if err := w.UpdateEvent(); err != nil {
		ctx.JSON(500, &base.ApiJsonErr{"UpdateEvent: " + err.Error(), base.DOC_URL})
		return
	} else if err := models.CreateWebhook(w); err != nil {
		ctx.JSON(500, &base.ApiJsonErr{"CreateWebhook: " + err.Error(), base.DOC_URL})
		return
	}

	ctx.JSON(201, ToApiHook(ctx.Repo.RepoLink, w))
}
Example #28
0
// addSegments add segments to the router tree.
func (t *Tree) addSegments(segments []string, handle Handle, wildcards []string, reg string) {
	// Fixed root route.
	if len(segments) == 0 {
		if reg != "" {
			filterCards := make([]string, 0, len(wildcards))
			for _, v := range wildcards {
				if v == ":" || v == "." {
					continue
				}
				filterCards = append(filterCards, v)
			}
			t.leaves = append(t.leaves, &leafInfo{
				handle:    handle,
				wildcards: filterCards,
				regexps:   regexp.MustCompile("^" + reg + "$"),
			})
		} else {
			t.leaves = append(t.leaves, &leafInfo{
				handle:    handle,
				wildcards: wildcards,
			})
		}
		return
	}

	seg := segments[0]
	iswild, params, regexpStr := splitSegment(seg)
	//for the router  /login/*/access match /login/2009/11/access
	if !iswild && com.IsSliceContainsStr(wildcards, ":splat") {
		iswild = true
		regexpStr = seg
	}
	if seg == "*" && len(wildcards) > 0 && reg == "" {
		iswild = true
		regexpStr = "(.+)"
	}
	if iswild {
		if t.wildcard == nil {
			t.wildcard = NewTree()
		}
		if regexpStr != "" {
			if reg == "" {
				rr := ""
				for _, w := range wildcards {
					if w == "." || w == ":" {
						continue
					}
					if w == ":splat" {
						rr = rr + "(.+)/"
					} else {
						rr = rr + "([^/]+)/"
					}
				}
				regexpStr = rr + regexpStr
			} else {
				regexpStr = "/" + regexpStr
			}
		} else if reg != "" {
			if seg == "*.*" {
				regexpStr = "/([^.]+).(.+)"
			} else {
				for _, w := range params {
					if w == "." || w == ":" {
						continue
					}
					regexpStr = "/([^/]+)" + regexpStr
				}
			}
		}
		t.wildcard.addSegments(segments[1:], handle, append(wildcards, params...), reg+regexpStr)
	} else {
		subTree, ok := t.fixroutes[seg]
		if !ok {
			subTree = NewTree()
			t.fixroutes[seg] = subTree
		}
		subTree.addSegments(segments[1:], handle, wildcards, reg)
	}
}
Example #29
0
func Issues(ctx *middleware.Context) {
	ctx.Data["Title"] = ctx.Tr("repo.issues")
	ctx.Data["PageIsIssueList"] = true

	viewType := ctx.Query("type")
	types := []string{"assigned", "created_by", "mentioned"}
	if !com.IsSliceContainsStr(types, viewType) {
		viewType = "all"
	}

	isShowClosed := ctx.Query("state") == "closed"

	// Must sign in to see issues about you.
	if viewType != "all" && !ctx.IsSigned {
		ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
		ctx.Redirect(setting.AppSubUrl + "/user/login")
		return
	}

	var assigneeID, posterID int64
	filterMode := models.FM_ALL
	switch viewType {
	case "assigned":
		assigneeID = ctx.User.Id
		filterMode = models.FM_ASSIGN
	case "created_by":
		posterID = ctx.User.Id
		filterMode = models.FM_CREATE
	case "mentioned":
		filterMode = models.FM_MENTION
	}

	var uid int64 = -1
	if ctx.IsSigned {
		uid = ctx.User.Id
	}

	repo := ctx.Repo.Repository
	selectLabels := ctx.Query("labels")
	milestoneID := ctx.QueryInt64("milestone")
	issueStats := models.GetIssueStats(repo.Id, uid, com.StrTo(selectLabels).MustInt64(), isShowClosed, filterMode)

	page := ctx.QueryInt("page")
	if page <= 1 {
		page = 1
	} else {
		ctx.Data["PreviousPage"] = page - 1
	}
	if (!isShowClosed && int(issueStats.OpenCount) > setting.IssuePagingNum*page) ||
		(isShowClosed && int(issueStats.ClosedCount) > setting.IssuePagingNum*page) {
		ctx.Data["NextPage"] = page + 1
	}

	// Get issues.
	issues, err := models.GetIssues(uid, assigneeID, repo.Id, posterID, milestoneID,
		page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, ctx.Query("sortType"))
	if err != nil {
		ctx.Handle(500, "GetIssues: %v", err)
		return
	}

	// Get issue-user pairs.
	pairs, err := models.GetIssueUserPairs(repo.Id, posterID, isShowClosed)
	if err != nil {
		ctx.Handle(500, "GetIssueUserPairs: %v", err)
		return
	}

	// Get posters.
	for i := range issues {
		if err = issues[i].GetPoster(); err != nil {
			ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if err = issues[i].GetLabels(); err != nil {
			ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].ID, err))
			return
		}

		if !ctx.IsSigned {
			issues[i].IsRead = true
			continue
		}

		// Check read status.
		idx := models.PairsContains(pairs, issues[i].ID, ctx.User.Id)
		if idx > -1 {
			issues[i].IsRead = pairs[idx].IsRead
		} else {
			issues[i].IsRead = true
		}
	}

	ctx.Data["IssueStats"] = issueStats
	ctx.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64()
	ctx.Data["ViewType"] = viewType
	ctx.Data["Issues"] = issues
	ctx.Data["IsShowClosed"] = isShowClosed
	if isShowClosed {
		ctx.Data["State"] = "closed"
		ctx.Data["ShowCount"] = issueStats.ClosedCount
	} else {
		ctx.Data["State"] = "open"
		ctx.Data["ShowCount"] = issueStats.OpenCount
	}

	ctx.HTML(200, ISSUES)
}
Example #30
0
func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) {
	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
	if err != nil {
		if models.IsErrIssueNotExist(err) {
			ctx.Handle(404, "GetIssueByIndex", err)
		} else {
			ctx.Handle(500, "GetIssueByIndex", err)
		}
		return
	}
	if issue.IsPull {
		if err = issue.GetPullRequest(); err != nil {
			ctx.Handle(500, "GetPullRequest", err)
			return
		}
	}

	var attachments []string
	if setting.AttachmentEnabled {
		attachments = form.Attachments
	}

	if ctx.HasError() {
		ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
		ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
		return
	}

	var comment *models.Comment
	defer func() {
		// Check if issue owner/poster changes the status of issue.
		if (ctx.Repo.IsOwner() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) &&
			(form.Status == "reopen" || form.Status == "close") &&
			!(issue.IsPull && issue.HasMerged) {

			// Duplication and conflict check should apply to reopen pull request.
			var pr *models.PullRequest

			if form.Status == "reopen" && issue.IsPull {
				pull := issue.PullRequest
				pr, err = models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch)
				if err != nil {
					if !models.IsErrPullRequestNotExist(err) {
						ctx.Handle(500, "GetUnmergedPullRequest", err)
						return
					}
				}

				// Regenerate patch and test conflict.
				if pr == nil {
					if err = issue.UpdatePatch(); err != nil {
						ctx.Handle(500, "UpdatePatch", err)
						return
					}

					issue.AddToTaskQueue()
				}
			}

			if pr != nil {
				ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
			} else {
				issue.Repo = ctx.Repo.Repository
				if err = issue.ChangeStatus(ctx.User, form.Status == "close"); err != nil {
					log.Error(4, "ChangeStatus: %v", err)
				} else {
					log.Trace("Issue[%d] status changed to closed: %v", issue.ID, issue.IsClosed)
				}
			}
		}

		// Redirect to comment hashtag if there is any actual content.
		typeName := "issues"
		if issue.IsPull {
			typeName = "pulls"
		}
		if comment != nil {
			ctx.Redirect(fmt.Sprintf("%s/%s/%d#%s", ctx.Repo.RepoLink, typeName, issue.Index, comment.HashTag()))
		} else {
			ctx.Redirect(fmt.Sprintf("%s/%s/%d", ctx.Repo.RepoLink, typeName, issue.Index))
		}
	}()

	// Fix #321: Allow empty comments, as long as we have attachments.
	if len(form.Content) == 0 && len(attachments) == 0 {
		return
	}

	comment, err = models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments)
	if err != nil {
		ctx.Handle(500, "CreateIssueComment", err)
		return
	}

	// Update mentions.
	mentions := base.MentionPattern.FindAllString(comment.Content, -1)
	if len(mentions) > 0 {
		for i := range mentions {
			mentions[i] = mentions[i][1:]
		}

		if err := models.UpdateMentions(mentions, issue.ID); err != nil {
			ctx.Handle(500, "UpdateMentions", err)
			return
		}
	}

	// Mail watchers and mentions.
	if setting.Service.EnableNotifyMail {
		tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, &models.Issue{
			Index:   issue.Index,
			Name:    issue.Name,
			Content: form.Content,
		})
		if err != nil {
			ctx.Handle(500, "SendIssueNotifyMail", err)
			return
		}

		tos = append(tos, ctx.User.LowerName)
		newTos := make([]string, 0, len(mentions))
		for _, m := range mentions {
			if com.IsSliceContainsStr(tos, m) {
				continue
			}

			newTos = append(newTos, m)
		}
		if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
			ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
			ctx.Handle(500, "SendIssueMentionMail", err)
			return
		}
	}
	log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID)
}