Beispiel #1
0
// PasswordController updates the password
func PasswordController(c *gin.Context) {
	var err error
	var pf passwordForm

	err = c.Bind(&pf)
	if err != nil {
		c.Error(err).SetMeta("admin.PasswordController.Bind")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	err = u.CheckPassword(pf.Old)
	if err != nil {
		c.Error(err).SetMeta("admin.PasswordController.Check")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	if pf.New != pf.Check {
		c.Error(err).SetMeta("admin.PasswordController.Compare")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	var hash []byte

	hash, err = u.HashPassword(pf.Check)
	if err != nil {
		c.Error(err).SetMeta("admin.PasswordController.HashPassword")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	var user u.User

	err = u.Storm.Get("auth", "user", &user)
	if err != nil {
		c.Error(err).SetMeta("admin.PasswordController.HashPassword")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	// set user password
	user.Password = hash

	err = u.Storm.Set("auth", "user", &user)
	if err != nil {
		c.Error(err).SetMeta("admin.PasswordController.Set")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	// unset the jwt cookie
	http.SetCookie(c.Writer, u.DeleteCookie())

	c.Redirect(http.StatusFound, "/admin/panel")

	return

}
Beispiel #2
0
func (pc *NodeController) postDeleteNodeAction(c *gin.Context) {

	id := c.Param("id")

	node, err := models.NodeMapper.FetchOneById(id)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	if node == nil {
		c.HTML(http.StatusNotFound, "error_404.html", map[string]interface{}{
			"text": "Node not found",
		})
		return
	}

	if err := models.NodeMapper.Delete(node); err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	c.Redirect(http.StatusFound, "/nodes")
}
Beispiel #3
0
func GetAddonFiles(ctx *gin.Context) {
	user := ctx.Params.ByName("user")
	repository := ctx.Params.ByName("repository")
	filepath := ctx.Params.ByName("filepath")[1:] // strip the leading "/"
	log.Info("Request for: " + filepath)

	lastReleaseTag, lastReleaseBranch := getLastRelease(user, repository)

	switch filepath {
	case "addons.xml":
		GetAddonsXML(ctx)
		return
	case "addons.xml.md5":
		GetAddonsXMLChecksum(ctx)
		writeChangelog(user, repository)
		return
	case "fanart.jpg":
		fallthrough
	case "icon.png":
		ctx.Redirect(302, fmt.Sprintf(githubUserContentURL+"/"+filepath, user, repository, lastReleaseBranch))
		return
	}

	switch {
	case addonZipRE.MatchString(filepath):
		addonZip(ctx, user, repository, lastReleaseTag)
	case addonChangelogRE.MatchString(filepath):
		addonChangelog(ctx, user, repository)
	default:
		ctx.AbortWithError(404, errors.New(filepath))
	}
}
Beispiel #4
0
func LogoutHandler(c *gin.Context) {
	session := sessions.Default(c)
	a := auth.Default(c)
	auth.Logout(session, a.User)

	c.Redirect(http.StatusMovedPermanently, "/")
}
Beispiel #5
0
func (self *EnvController) New(c *gin.Context) {
	username := self.CurrentUser(c)

	if username == "" {
		c.Redirect(http.StatusFound, "/")

		return
	}

	appName := c.Param("appName")
	key := c.PostForm("key")
	value := c.PostForm("value")

	err := env.Create(self.etcd, username, appName, key, value)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%+v\n", err)

		c.HTML(http.StatusInternalServerError, "app.tmpl", gin.H{
			"alert":   true,
			"error":   true,
			"message": "Failed to add environment variable.",
		})

		return
	}

	c.Redirect(http.StatusSeeOther, "/apps/"+appName)
}
Beispiel #6
0
func UserLogout(c *gin.Context) {
	var cookie middleware.CookieManager
	cookie = c.MustGet("CM").(middleware.CookieManager)
	cookie.Delete("user_id")
	cookie.WriteCookies()
	c.Redirect(http.StatusMovedPermanently, "/")
}
Beispiel #7
0
func GetAddonFiles(ctx *gin.Context) {
	user := ctx.Params.ByName("user")
	repository := ctx.Params.ByName("repository")
	filepath := ctx.Params.ByName("filepath")[1:] // strip the leading "/"

	lastTagName, lastTagCommit := getLastTag(user, repository)

	switch filepath {
	case "addons.xml":
		GetAddonsXML(ctx)
		return
	case "addons.xml.md5":
		GetAddonsXMLChecksum(ctx)
		return
	case "fanart.jpg":
		fallthrough
	case "icon.png":
		ctx.Redirect(302, fmt.Sprintf(githubUserContentURL+"/"+filepath, user, repository, lastTagCommit))
		return
	}

	switch {
	case addonZipRE.MatchString(filepath):
		addonZip(ctx, user, repository, lastTagName, lastTagCommit)
	case addonChangelogRE.MatchString(filepath):
		addonChangelog(ctx, user, repository, lastTagName, lastTagCommit)
	}
}
Beispiel #8
0
func (ctl *AlertController) postEditAlertsGroupAction(c *gin.Context) {

	var form models.AlertGroupUpdateForm
	if err := c.Bind(&form); err != nil {
		c.AbortWithStatus(http.StatusBadRequest)
		return
	}

	ag, err := models.AlertGroupMapper.FetchOne(c.Param("id"))
	if err != nil {
		panic(err)
	}

	if ag == nil {
		c.Redirect(http.StatusFound, "/alerts-groups")
		return
	}

	if err := form.Validate(ag); err != nil {
		c.HTML(http.StatusOK, "alert_group_edit.html", map[string]interface{}{
			"errors": err.Errors,
			"form":   form,
			"ag":     ag,
		})
		return
	}

	ag.Update(&form)

	if err := models.AlertGroupMapper.Update(ag); err != nil {
		panic(err)
	}

	c.Redirect(http.StatusFound, "/alerts-groups")
}
Beispiel #9
0
//var sp int = config.PostsNum
func PageHandler(c *gin.Context) {
	num := c.Param("num")
	onpage, err := strconv.Atoi(num)
	if err != nil {
		c.Redirect(http.StatusBadRequest, "/")
		return
	}
	var posts []Post
	DB.Order("pid desc").Offset(sp).Limit(sp).Find(&posts)
	var countrows int
	DB.Model(&Post{}).Count(&countrows)
	var sumpage int
	if countrows%sp == 0 {
		sumpage = countrows / sp
	} else {
		sumpage = countrows/sp + 1
	}
	c.HTML(http.StatusOK, "home.tmpl", gin.H{
		"home":    "welcome home",
		"posts":   posts,
		"sumpage": sumpage,
		"onpage":  onpage,
	})

}
Beispiel #10
0
func IndexHandler(c *gin.Context) {

	var listTmpl = template.Must(template.ParseFiles("templates/base.html",
		"apps/message/templates/index.html"))

	User, _ := c.Get("User")
	Sid, _ := c.Get("Sid")
	sid := Sid.(string)
	//fmt.Println("User+++==>", Sid)

	bapi := auth.GetBackendApi2(c)
	data := gin.H{}
	if err := bapi.Get(&data, "http://127.0.0.1:8080/messages"); err != nil {
		fmt.Println("bapi failed:", err)
		return
	}

	if e, exist := data["error"]; exist {
		fmt.Println("get messages failed:", e.(string))
		if e.(string) == "session expired" {
			conn := utils.OpenDB()
			auth.Signout_del_session(conn, sid)
			c.Redirect(302, "/auth/signin")
			return
		}
		// TODO: else
	}

	data["User"] = User

	if err := listTmpl.Execute(c.Writer, data); err != nil {
		fmt.Println(err.Error())
	}

}
Beispiel #11
0
func (ctl *AlertController) postAddAlertsPolicyAction(c *gin.Context) {

	var form models.AlertPolicyForm
	if err := c.Bind(&form); err != nil {
		c.AbortWithStatus(http.StatusBadRequest)
		return
	}

	if err := form.Validate(); err != nil {
		c.HTML(http.StatusOK, "alert_policy_add.html", map[string]interface{}{
			"NagiosPlugins": models.NagiosPlugins,
			"errors":        err.Errors,
			"form":          form,
		})
		return
	}

	ap := models.AlertPolicyMapper.Create(&form)

	if err := models.AlertPolicyMapper.Save(ap); err != nil {
		panic(err)
	}

	c.Redirect(http.StatusFound, "/alerts-policies")
}
Beispiel #12
0
func ShowEpisodeLinks(ctx *gin.Context) {
	seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season"))
	episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode"))
	torrents, err := showEpisodeLinks(ctx.Params.ByName("showId"), seasonNumber, episodeNumber)
	if err != nil {
		ctx.Error(err)
		return
	}

	if len(torrents) == 0 {
		xbmc.Notify("Quasar", "LOCALIZE[30205]", config.AddonIcon())
		return
	}

	choices := make([]string, 0, len(torrents))
	for _, torrent := range torrents {
		label := fmt.Sprintf("S:%d P:%d - %s",
			torrent.Seeds,
			torrent.Peers,
			torrent.Name,
		)
		choices = append(choices, label)
	}

	choice := xbmc.ListDialog("LOCALIZE[30202]", choices...)
	if choice >= 0 {
		rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[choice].Magnet())
		ctx.Redirect(302, rUrl)
	}
}
Beispiel #13
0
// 原图本地获取或者跳转到img服务器
func rspImg(imgPath string, context *gin.Context) {
	imgUrl, err := url.Parse(imgPath)
	if err != nil || imgUrl == nil {
		context.Status(http.StatusNotFound)
		return
	}

	if len(imgUrl.Host) > 0 {
		context.Redirect(http.StatusFound, imgPath)
		return
	}

	// cache
	cacheBuff := util.FindInCache(imgUrl.String())
	if len(cacheBuff) > 0 {
		rspCacheControl(cacheBuff, context)
		return
	}

	buff := &bytes.Buffer{}
	thumbImg := getThumbnailImg(imgUrl)
	if thumbImg == nil {
		context.Status(http.StatusNotFound)
		return
	}

	jpeg.Encode(buff, thumbImg, nil)
	rspCacheControl(buff.Bytes(), context)
}
Beispiel #14
0
//PageShow handles /pages/:id route
func PageShow(c *gin.Context) {
	db := models.GetDB()
	session := sessions.Default(c)

	idslug := c.Param("idslug")
	id := helpers.Atouint(strings.Split(idslug, "-")[0])
	page := &models.Page{}
	db.First(page, id)
	if page.ID == 0 || !page.Published {
		c.HTML(404, "errors/404", nil)
		return
	}
	//redirect to canonical url
	if c.Request.URL.Path != page.URL() {
		c.Redirect(303, page.URL())
		return
	}
	c.HTML(200, "pages/show", gin.H{
		"Page":            page,
		"Title":           page.Name,
		"Active":          page.URL(),
		"MetaDescription": page.MetaDescription,
		"MetaKeywords":    page.MetaKeywords,
		"Authenticated":   (session.Get("user_id") != nil),
	})
}
Beispiel #15
0
// Login is a page with a login form and an alternative to the login API,
// this route handles both GET and POST requests.
func Login(c *gin.Context) {
	session := sessions.Default(c)
	defer session.Save()

	// returnURL can come from GET or POST or use default.
	returnURL := c.DefaultQuery("return_url", c.DefaultPostForm("return_url", "/"))

	if c.Request.Method == "POST" {
		var schema LoginSchema
		if c.Bind(&schema) == nil {
			// Fetch the user matching this username.
			user := GetUserByUsername(schema.Username)

			// If the user exists, the ID is > 0, check the password.
			if user.ID > 0 && user.CheckPassword(schema.Password) {
				session.Set("userID", user.ID)
				c.Redirect(http.StatusFound, returnURL)
				return
			}
			session.AddFlash("Invalid username or password")
		}
	}

	c.HTML(200, "login.html", pongo2.Context{
		"title":      "Login",
		"messages":   session.Flashes(),
		"csrf_token": nosurf.Token(c.Request),
		"return_url": returnURL,
	})
}
Beispiel #16
0
func Logout(c *gin.Context) {
	session := sessions.Default(c)
	session.Delete("internal")
	session.Delete(gin.AuthUserKey)
	SessionSave(c)
	c.Redirect(http.StatusTemporaryRedirect, "/")
}
Beispiel #17
0
func ShowEpisodePlay(ctx *gin.Context) {
	tmdbId := ctx.Params.ByName("showId")
	showId, _ := strconv.Atoi(tmdbId)
	seasonNumber, _ := strconv.Atoi(ctx.Params.ByName("season"))
	episodeNumber, _ := strconv.Atoi(ctx.Params.ByName("episode"))

	show := tmdb.GetShow(showId, "")
	episode := tmdb.GetEpisode(showId, seasonNumber, episodeNumber, "")

	runtime := 45
	if len(show.EpisodeRunTime) > 0 {
		runtime = show.EpisodeRunTime[len(show.EpisodeRunTime)-1]
	}

	torrents, err := showEpisodeLinks(showId, seasonNumber, episodeNumber)
	if err != nil {
		ctx.Error(err)
		return
	}

	if len(torrents) == 0 {
		xbmc.Notify("Quasar", "LOCALIZE[30205]", config.AddonIcon())
		return
	}

	AddToTorrentsMap(strconv.Itoa(episode.Id), torrents[0])

	rUrl := UrlQuery(UrlForXBMC("/play"), "uri", torrents[0].Magnet(),
		"tmdb", strconv.Itoa(episode.Id),
		"type", "episode",
		"runtime", strconv.Itoa(runtime))
	ctx.Redirect(302, rUrl)
}
Beispiel #18
0
// update an object from its change form
func changeUpdate(c *gin.Context) {
	log.Println("hitting changeUpdate")
	action := c.DefaultPostForm("action", "save")
	delete(c.Request.Form, "action") // don't keep this as part of the object
	modelAdmin, exists := modelAdmins[strings.ToLower(c.Param("model"))]
	if !exists {
		c.String(http.StatusNotFound, "Not found.")
		return
	}
	if !hasPermissions(c, modelAdmin.ModelName, "write", nil) { // TODO: add in the ID(s)
		return
	}
	switch action {
	case "save":
		saveFromForm(c)
		c.Request.Method = "GET"
		c.Redirect(http.StatusFound, fmt.Sprintf("../%v", strings.ToLower(c.Param("model"))))
	case "save-continue":
		saveFromForm(c)
		change(c)
	case "delete":
		modelAdmin.Accessor.DeletePK(c.Param("pk"))
		c.Request.Method = "GET"
		c.Redirect(http.StatusFound, fmt.Sprintf("../%v", strings.ToLower(c.Param("model"))))
	}
}
Beispiel #19
0
func UserLogin(c *gin.Context) {
	var cookie middleware.CookieManager
	cookie = c.MustGet("CM").(middleware.CookieManager)
	if c.Request.Method == "GET" {
		data := tool.GetTD(c)

		fmt.Println(data)
		c.HTML(http.StatusOK, "login.html", data)
	} else if c.Request.Method == "POST" {

		email := c.PostForm("email")
		password := c.PostForm("password")
		user := model.User{}
		model.T.DB.Debug().Where("email = ? and password = ?", email, password).First(&user)
		if user.Name != "" {
			cookie.Add("user_id", user.ID)
			cookie.WriteCookies()
			c.Redirect(http.StatusMovedPermanently, "/")
		} else {
			cookie.Flash("fail_msg", "login failed :(")
			c.Redirect(http.StatusMovedPermanently, "/user/login")
		}

	}
}
Beispiel #20
0
func ShowIndex(c *gin.Context) {
	user := session.User(c)
	if user == nil {
		c.Redirect(http.StatusSeeOther, "/login")
		return
	}

	// get the repository list from the cache
	repos, err := cache.GetRepos(c, user)
	if err != nil {
		c.String(400, err.Error())
		return
	}

	// filter to only show the currently active ones
	activeRepos, err := store.GetRepoListOf(c, repos)
	if err != nil {
		c.String(400, err.Error())
		return
	}

	c.HTML(200, "index.html", gin.H{
		"User":  user,
		"Repos": activeRepos,
	})
}
/**
 * 2 - Create a deployment
 */
func (ctl *DeploymentController) postDeploymentAction(c *gin.Context) {

	appId := c.Param("app_id")
	buildId := c.Param("build_id")

	resp, err := http.Post(fmt.Sprintf("http://localhost:8080/api/apps/%s/builds/%s/deploy", appId, buildId), "json/application", nil)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}
	var deployment models.Deployment
	if err := json.Unmarshal(body, &deployment); err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	c.Redirect(http.StatusFound, fmt.Sprintf("/application/deployment/%s/%s", appId, deployment.Id.Hex()))
}
Beispiel #22
0
func (self *AppController) New(c *gin.Context) {
	username := self.CurrentUser(c)

	if username == "" {
		c.Redirect(http.StatusFound, "/")

		return
	}

	appName := c.PostForm("appName")

	err := app.Create(self.etcd, username, appName)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%+v\n", err)

		c.HTML(http.StatusInternalServerError, "apps.tmpl", gin.H{
			"alert":   true,
			"error":   true,
			"message": "Failed to create app.",
		})

		return
	}

	c.Redirect(http.StatusSeeOther, "/apps/"+appName)
}
Beispiel #23
0
// DeleteController deletes links
func DeleteController(c *gin.Context) {
	var err error
	var df deleteForm

	err = c.Bind(&df)
	if err != nil {
		c.Error(err).SetMeta("link.DeleteController.Bind")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	var link m.LinkType

	// get the gallery from bolt
	err = u.Storm.One("ID", df.Link, &link)
	if err != nil {
		c.Error(err).SetMeta("link.DeleteController.One")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	// delete it
	err = u.Storm.Remove(&link)
	if err != nil {
		c.Error(err).SetMeta("link.DeleteController.Remove")
		c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
		return
	}

	c.Redirect(http.StatusFound, c.Request.Referer())

	return

}
func (h *FrontendHandlers) Logout(c *gin.Context) {
	session := sessions.Default(c)
	session.Clear()
	session.Save()

	c.Redirect(302, "/login")
}
Beispiel #25
0
func (pc *NodeController) postNodeAction(c *gin.Context) {

	id := c.Param("id")

	var form models.NodeUpdateForm
	if err := c.Bind(&form); err != nil {
		c.AbortWithStatus(http.StatusBadRequest)
		return
	}

	node, err := models.NodeMapper.FetchOneById(id)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	if node == nil {
		c.HTML(http.StatusNotFound, "error_404.html", map[string]interface{}{
			"text": "Node not found",
		})
		return
	}

	node.Tags = form.Tags
	node.Description = form.Description
	models.NodeMapper.Update(node)

	c.Redirect(http.StatusFound, "/nodes")
}
func (h *FrontendHandlers) PostLogin(c *gin.Context) {
	data := &LoginData{
		Username: c.PostForm("username"),
		Password: c.PostForm("password"),
	}

	if v := validateLogin(data); v.HasError() {
		data.Validate = v.Messages()
		h.render.HTML(c.Writer, 200, "login", data)
		return
	}

	info, err := h.loginService.Login(data.Username, data.Password)
	if err != nil {
		data.Error = err.Error()
		h.render.HTML(c.Writer, 200, "login", data)
		return
	}

	session := sessions.Default(c)
	session.Set("user_id", info.Id)
	session.Save()

	c.Redirect(302, "/")
}
Beispiel #27
0
func addonZip(ctx *gin.Context, user string, repository string, lastReleaseTag string) {
	release := getReleaseByTag(user, repository, lastReleaseTag)
	// if there a release with an asset that matches a addon zip, use it
	if release != nil {
		client := github.NewClient(nil)
		assets, _, _ := client.Repositories.ListReleaseAssets(user, repository, *release.ID, nil)
		platformStruct := xbmc.GetPlatform()
		platform := platformStruct.OS + "_" + platformStruct.Arch
		var assetAllPlatforms string
		for _, asset := range assets {
			if strings.HasSuffix(*asset.Name, platform+".zip") {
				assetPlatform := *asset.BrowserDownloadURL
				log.Info("Using release asset for " + platform + ": " + assetPlatform)
				ctx.Redirect(302, assetPlatform)
				return
			}
			if addonZipRE.MatchString(*asset.Name) {
				assetAllPlatforms = *asset.BrowserDownloadURL
				log.Info("Found all platforms release asset: " + assetAllPlatforms)
				continue
			}
		}
		if assetAllPlatforms != "" {
			log.Info("Using release asset for all platforms: " + assetAllPlatforms)
			ctx.Redirect(302, assetAllPlatforms)
			return
		}
	}
	ctx.AbortWithError(404, errors.New("Release asset not found."))
}
func (h *FrontendHandlers) PostRegister(c *gin.Context) {
	data := &RegisterData{
		Username:        c.PostForm("username"),
		Password:        c.PostForm("password"),
		ConfirmPassword: c.PostForm("confirmpassword"),
		Email:           c.PostForm("email"),
		Name:            c.PostForm("name"),
	}

	if v := ValidateRegister(data); v.HasError() {
		data.Validate = v.Messages()
		h.render.HTML(c.Writer, 200, "register", data)
		return
	}

	form := &register.RegisterForm{
		Username: data.Username,
		Password: data.Password,
		Email:    data.Email,
		Name:     data.Name,
	}

	if err := h.registerService.Register(form); err != nil {
		data.Error = err.Error()
		h.render.HTML(c.Writer, 200, "register", data)
		return
	}

	c.Redirect(302, "/login")
}
Beispiel #29
0
func HomeHandler(c *gin.Context) {
	// "SELECT * FROM posts ORDER BY id DESC LIMIT %s", sp
	// "SELECT count(*) FROM posts"
	var posts []Post
	DB.Order("pid desc").Limit(sp).Find(&posts)

	if len(posts) == 0 {
		c.Redirect(http.StatusFound, "/user/compose")
		return
	}
	var countrows int
	DB.Model(&Post{}).Count(&countrows)

	var sumpage int
	if countrows%sp == 0 {
		sumpage = countrows / sp
	} else {
		sumpage = countrows/sp + 1
	}
	//title and tag
	titles := component.GetTitle()
	tags := component.GetTag()
	c.HTML(http.StatusOK, "home.tmpl", gin.H{
		"home":    "welcome home",
		"posts":   posts,
		"sumpage": sumpage,
		"onpage":  1,
		"current": c.MustGet("current").(bool),
		"titles":  titles,
		"tags":    tags,
	})
}
Beispiel #30
0
func (self *ArgController) Delete(c *gin.Context) {
	username := self.CurrentUser(c)

	if username == "" {
		c.Redirect(http.StatusFound, "/")

		return
	}

	appName := c.Param("appName")
	key := c.PostForm("key")

	err := arg.Delete(self.etcd, username, appName, key)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%+v\n", err)

		c.HTML(http.StatusInternalServerError, "app.tmpl", gin.H{
			"alert":   true,
			"error":   true,
			"message": "Failed to delete build arg.",
		})

		return
	}

	c.Redirect(http.StatusSeeOther, "/apps/"+appName)
}