mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
refactor: settings routes and actions
This commit is contained in:
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/muety/wakapi/utils"
|
"github.com/muety/wakapi/utils"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -16,6 +17,8 @@ func Init() {
|
|||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type action func(w http.ResponseWriter, r *http.Request) (int, string, string)
|
||||||
|
|
||||||
var templates map[string]*template.Template
|
var templates map[string]*template.Template
|
||||||
|
|
||||||
func loadTemplates() {
|
func loadTemplates() {
|
||||||
|
@ -42,16 +42,7 @@ func NewSettingsHandler(userService services.IUserService, summaryService servic
|
|||||||
|
|
||||||
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
|
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
|
||||||
router.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
router.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||||
router.Path("/credentials").Methods(http.MethodPost).HandlerFunc(h.PostCredentials)
|
router.Methods(http.MethodPost).HandlerFunc(h.PostIndex)
|
||||||
router.Path("/aliases").Methods(http.MethodPost).HandlerFunc(h.PostAlias)
|
|
||||||
router.Path("/aliases/delete").Methods(http.MethodPost).HandlerFunc(h.DeleteAlias)
|
|
||||||
router.Path("/language_mappings").Methods(http.MethodPost).HandlerFunc(h.PostLanguageMapping)
|
|
||||||
router.Path("/language_mappings/delete").Methods(http.MethodPost).HandlerFunc(h.DeleteLanguageMapping)
|
|
||||||
router.Path("/reset").Methods(http.MethodPost).HandlerFunc(h.PostResetApiKey)
|
|
||||||
router.Path("/badges").Methods(http.MethodPost).HandlerFunc(h.PostToggleBadges)
|
|
||||||
router.Path("/user/delete").Methods(http.MethodPost).HandlerFunc(h.DeleteUser)
|
|
||||||
router.Path("/wakatime_integration").Methods(http.MethodPost).HandlerFunc(h.PostSetWakatimeApiKey)
|
|
||||||
router.Path("/regenerate").Methods(http.MethodPost).HandlerFunc(h.PostRegenerateSummaries)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) RegisterAPIRoutes(router *mux.Router) {}
|
func (h *SettingsHandler) RegisterAPIRoutes(router *mux.Router) {}
|
||||||
@ -64,7 +55,73 @@ func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
|||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) PostIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if h.config.IsDev() {
|
||||||
|
loadTemplates()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing form values"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action := r.PostForm.Get("action")
|
||||||
|
r.PostForm.Del("action")
|
||||||
|
|
||||||
|
actionFunc := h.dispatchAction(action)
|
||||||
|
if actionFunc == nil {
|
||||||
|
logbuch.Warn("failed to dispatch action '%s'", action)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("unknown action requests"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status, successMsg, errorMsg := actionFunc(w, r)
|
||||||
|
|
||||||
|
// action responded itself
|
||||||
|
if status == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if errorMsg != "" {
|
||||||
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError(errorMsg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if successMsg != "" {
|
||||||
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess(successMsg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) dispatchAction(action string) action {
|
||||||
|
switch action {
|
||||||
|
case "change_password":
|
||||||
|
return h.actionChangePassword
|
||||||
|
case "reset_apikey":
|
||||||
|
return h.actionResetApiKey
|
||||||
|
case "delete_alias":
|
||||||
|
return h.actionDeleteAlias
|
||||||
|
case "add_alias":
|
||||||
|
return h.actionAddAlias
|
||||||
|
case "delete_mapping":
|
||||||
|
return h.actionDeleteLanguageMapping
|
||||||
|
case "add_mapping":
|
||||||
|
return h.actionAddLanguageMapping
|
||||||
|
case "toggle_badges":
|
||||||
|
return h.actionToggleBadges
|
||||||
|
case "toggle_wakatime":
|
||||||
|
return h.actionSetWakatimeApiKey
|
||||||
|
case "regenerate_summaries":
|
||||||
|
return h.actionRegenerateSummaries
|
||||||
|
case "delete_account":
|
||||||
|
return h.actionDeleteUser
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) actionChangePassword(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
@ -73,41 +130,29 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
|
|||||||
|
|
||||||
var credentials models.CredentialsReset
|
var credentials models.CredentialsReset
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
return http.StatusBadRequest, "", "missing parameters"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if err := credentialsDecoder.Decode(&credentials, r.PostForm); err != nil {
|
if err := credentialsDecoder.Decode(&credentials, r.PostForm); err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
return http.StatusBadRequest, "", "missing parameters"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utils.CompareBcrypt(user.Password, credentials.PasswordOld, h.config.Security.PasswordSalt) {
|
if !utils.CompareBcrypt(user.Password, credentials.PasswordOld, h.config.Security.PasswordSalt) {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
return http.StatusUnauthorized, "", "invalid credentials"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid credentials"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !credentials.IsValid() {
|
if !credentials.IsValid() {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
return http.StatusBadRequest, "", "invalid parameters"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid parameters"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Password = credentials.PasswordNew
|
user.Password = credentials.PasswordNew
|
||||||
if hash, err := utils.HashBcrypt(user.Password, h.config.Security.PasswordSalt); err != nil {
|
if hash, err := utils.HashBcrypt(user.Password, h.config.Security.PasswordSalt); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
user.Password = hash
|
user.Password = hash
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := h.userSrvc.Update(user); err != nil {
|
if _, err := h.userSrvc.Update(user); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
login := &models.Login{
|
login := &models.Login{
|
||||||
@ -116,75 +161,28 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
|
|||||||
}
|
}
|
||||||
encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login.Username)
|
encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, h.config.CreateCookie(models.AuthCookieKey, encoded, "/"))
|
http.SetCookie(w, h.config.CreateCookie(models.AuthCookieKey, encoded, "/"))
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("password was updated successfully"))
|
return http.StatusOK, "password was updated successfully", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) DeleteLanguageMapping(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionResetApiKey(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
|
|
||||||
user := r.Context().Value(models.UserKey).(*models.User)
|
user := r.Context().Value(models.UserKey).(*models.User)
|
||||||
id, err := strconv.Atoi(r.PostFormValue("mapping_id"))
|
if _, err := h.userSrvc.ResetApiKey(user); err != nil {
|
||||||
if err != nil {
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mapping, err := h.languageMappingSrvc.GetById(uint(id)); err != nil || mapping == nil {
|
msg := fmt.Sprintf("your new api key is: %s", user.ApiKey)
|
||||||
w.WriteHeader(http.StatusNotFound)
|
return http.StatusOK, msg, ""
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("mapping not found"))
|
|
||||||
return
|
|
||||||
} else if mapping.UserID != user.ID {
|
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("not allowed to delete mapping"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.languageMappingSrvc.Delete(&models.LanguageMapping{ID: uint(id)}); err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping deleted successfully"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostLanguageMapping(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionDeleteAlias(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
|
||||||
loadTemplates()
|
|
||||||
}
|
|
||||||
user := r.Context().Value(models.UserKey).(*models.User)
|
|
||||||
extension := r.PostFormValue("extension")
|
|
||||||
language := r.PostFormValue("language")
|
|
||||||
|
|
||||||
if extension[0] == '.' {
|
|
||||||
extension = extension[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping := &models.LanguageMapping{
|
|
||||||
UserID: user.ID,
|
|
||||||
Extension: extension,
|
|
||||||
Language: language,
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := h.languageMappingSrvc.Create(mapping); err != nil {
|
|
||||||
w.WriteHeader(http.StatusConflict)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("mapping already exists"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping added successfully"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *SettingsHandler) DeleteAlias(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
@ -197,19 +195,15 @@ func (h *SettingsHandler) DeleteAlias(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if aliases, err := h.aliasSrvc.GetByUserAndKeyAndType(user.ID, aliasKey, uint8(aliasType)); err != nil {
|
if aliases, err := h.aliasSrvc.GetByUserAndKeyAndType(user.ID, aliasKey, uint8(aliasType)); err != nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
return http.StatusNotFound, "", "aliases not found"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("aliases not found"))
|
|
||||||
return
|
|
||||||
} else if err := h.aliasSrvc.DeleteMulti(aliases); err != nil {
|
} else if err := h.aliasSrvc.DeleteMulti(aliases); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return http.StatusInternalServerError, "", "could not delete aliases"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete aliases"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("aliases deleted successfully"))
|
return http.StatusOK, "aliases deleted successfully", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostAlias(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionAddAlias(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
@ -229,32 +223,76 @@ func (h *SettingsHandler) PostAlias(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, err := h.aliasSrvc.Create(alias); err != nil {
|
if _, err := h.aliasSrvc.Create(alias); err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
// TODO: distinguish between bad request, conflict and server error
|
// TODO: distinguish between bad request, conflict and server error
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid input"))
|
return http.StatusBadRequest, "", "invalid input"
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("alias added successfully"))
|
return http.StatusOK, "alias added successfully", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionDeleteLanguageMapping(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
|
|
||||||
user := r.Context().Value(models.UserKey).(*models.User)
|
user := r.Context().Value(models.UserKey).(*models.User)
|
||||||
if _, err := h.userSrvc.ResetApiKey(user); err != nil {
|
id, err := strconv.Atoi(r.PostFormValue("mapping_id"))
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
if err != nil {
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
return http.StatusInternalServerError, "", "could not delete mapping"
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := fmt.Sprintf("your new api key is: %s", user.ApiKey)
|
if mapping, err := h.languageMappingSrvc.GetById(uint(id)); err != nil || mapping == nil {
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess(msg))
|
return http.StatusNotFound, "", "mapping not found"
|
||||||
|
} else if mapping.UserID != user.ID {
|
||||||
|
return http.StatusForbidden, "", "not allowed to delete mapping"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.languageMappingSrvc.Delete(&models.LanguageMapping{ID: uint(id)}); err != nil {
|
||||||
|
return http.StatusInternalServerError, "", "could not delete mapping"
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusOK, "mapping deleted successfully", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostSetWakatimeApiKey(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionAddLanguageMapping(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
|
if h.config.IsDev() {
|
||||||
|
loadTemplates()
|
||||||
|
}
|
||||||
|
user := r.Context().Value(models.UserKey).(*models.User)
|
||||||
|
extension := r.PostFormValue("extension")
|
||||||
|
language := r.PostFormValue("language")
|
||||||
|
|
||||||
|
if extension[0] == '.' {
|
||||||
|
extension = extension[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping := &models.LanguageMapping{
|
||||||
|
UserID: user.ID,
|
||||||
|
Extension: extension,
|
||||||
|
Language: language,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := h.languageMappingSrvc.Create(mapping); err != nil {
|
||||||
|
return http.StatusConflict, "", "mapping already exists"
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusOK, "mapping added successfully", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) actionToggleBadges(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
|
if h.config.IsDev() {
|
||||||
|
loadTemplates()
|
||||||
|
}
|
||||||
|
|
||||||
|
user := r.Context().Value(models.UserKey).(*models.User)
|
||||||
|
if _, err := h.userSrvc.ToggleBadges(user); err != nil {
|
||||||
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusOK, "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) actionSetWakatimeApiKey(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
@ -264,35 +302,39 @@ func (h *SettingsHandler) PostSetWakatimeApiKey(w http.ResponseWriter, r *http.R
|
|||||||
|
|
||||||
// Healthcheck, if a new API key is set, i.e. the feature is activated
|
// Healthcheck, if a new API key is set, i.e. the feature is activated
|
||||||
if (user.WakatimeApiKey == "" && apiKey != "") && !h.validateWakatimeKey(apiKey) {
|
if (user.WakatimeApiKey == "" && apiKey != "") && !h.validateWakatimeKey(apiKey) {
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to connect to WakaTime, API key invalid?"))
|
return http.StatusBadRequest, "", "failed to connect to WakaTime, API key invalid?"
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := h.userSrvc.SetWakatimeApiKey(user, apiKey); err != nil {
|
if _, err := h.userSrvc.SetWakatimeApiKey(user, apiKey); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
return http.StatusInternalServerError, "", "internal server error"
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("Wakatime API Key updated successfully"))
|
return http.StatusOK, "Wakatime API Key updated successfully", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) PostToggleBadges(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionRegenerateSummaries(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
|
|
||||||
user := r.Context().Value(models.UserKey).(*models.User)
|
user := r.Context().Value(models.UserKey).(*models.User)
|
||||||
if _, err := h.userSrvc.ToggleBadges(user); err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
logbuch.Info("clearing summaries for user '%s'", user.ID)
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
if err := h.summarySrvc.DeleteByUser(user.ID); err != nil {
|
||||||
return
|
logbuch.Error("failed to clear summaries: %v", err)
|
||||||
|
return http.StatusInternalServerError, "", "failed to delete old summaries"
|
||||||
}
|
}
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
if err := h.aggregationSrvc.Run(map[string]bool{user.ID: true}); err != nil {
|
||||||
|
logbuch.Error("failed to regenerate summaries: %v", err)
|
||||||
|
return http.StatusInternalServerError, "", "failed to generate aggregations"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusOK, "summaries are being regenerated – this may take a few seconds", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) actionDeleteUser(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
}
|
}
|
||||||
@ -310,31 +352,7 @@ func (h *SettingsHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
http.SetCookie(w, h.config.GetClearCookie(models.AuthCookieKey, "/"))
|
http.SetCookie(w, h.config.GetClearCookie(models.AuthCookieKey, "/"))
|
||||||
http.Redirect(w, r, fmt.Sprintf("%s/?success=%s", h.config.Server.BasePath, "Your account will be deleted in a few minutes. Sorry to you go."), http.StatusFound)
|
http.Redirect(w, r, fmt.Sprintf("%s/?success=%s", h.config.Server.BasePath, "Your account will be deleted in a few minutes. Sorry to you go."), http.StatusFound)
|
||||||
}
|
return -1, "", ""
|
||||||
|
|
||||||
func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if h.config.IsDev() {
|
|
||||||
loadTemplates()
|
|
||||||
}
|
|
||||||
|
|
||||||
user := r.Context().Value(models.UserKey).(*models.User)
|
|
||||||
|
|
||||||
logbuch.Info("clearing summaries for user '%s'", user.ID)
|
|
||||||
if err := h.summarySrvc.DeleteByUser(user.ID); err != nil {
|
|
||||||
logbuch.Error("failed to clear summaries: %v", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to delete old summaries"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.aggregationSrvc.Run(map[string]bool{user.ID: true}); err != nil {
|
|
||||||
logbuch.Error("failed to regenerate summaries: %v", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to generate aggregations"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("summaries are being regenerated – this may take a few seconds"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) validateWakatimeKey(apiKey string) bool {
|
func (h *SettingsHandler) validateWakatimeKey(apiKey string) bool {
|
||||||
|
@ -64,7 +64,8 @@
|
|||||||
Change Password
|
Change Password
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form class="mt-10" action="settings/credentials" method="post">
|
<form class="mt-10" action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="change_password">
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<label class="inline-block text-sm mb-1 text-gray-500" for="password_old">Current Password</label>
|
<label class="inline-block text-sm mb-1 text-gray-500" for="password_old">Current Password</label>
|
||||||
<input class="shadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded w-full py-1 px-3"
|
<input class="shadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded w-full py-1 px-3"
|
||||||
@ -96,7 +97,8 @@
|
|||||||
Reset API Key
|
Reset API Key
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form class="mt-6" action="settings/reset" method="post">
|
<form class="mt-6" action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="reset_apikey">
|
||||||
<div class="text-gray-300 text-sm mb-4">
|
<div class="text-gray-300 text-sm mb-4">
|
||||||
<strong>⚠️ Caution:</strong> Resetting your API key requires you to update your <span
|
<strong>⚠️ Caution:</strong> Resetting your API key requires you to update your <span
|
||||||
class="font-mono">.wakatime.cfg</span> files on all of your computers to make the WakaTime
|
class="font-mono">.wakatime.cfg</span> files on all of your computers to make the WakaTime
|
||||||
@ -141,7 +143,8 @@
|
|||||||
are mapped to <span class="underline">{{ $alias.Type | typeName }}</span> <span
|
are mapped to <span class="underline">{{ $alias.Type | typeName }}</span> <span
|
||||||
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono">{{ $alias.Key }}</span>.
|
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono">{{ $alias.Key }}</span>.
|
||||||
</div>
|
</div>
|
||||||
<form class="float-right" action="settings/aliases/delete" method="post">
|
<form class="float-right" action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="delete_alias">
|
||||||
<input type="hidden" id="delete_alias_key" name="key" required value="{{ $alias.Key }}">
|
<input type="hidden" id="delete_alias_key" name="key" required value="{{ $alias.Key }}">
|
||||||
<input type="hidden" id="delete_alias_type" name="type" required value="{{ $alias.Type }}">
|
<input type="hidden" id="delete_alias_type" name="type" required value="{{ $alias.Type }}">
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
@ -155,7 +158,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white mb-2">Add Rule</h3>
|
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white mb-2">Add Rule</h3>
|
||||||
<form action="settings/aliases" method="post">
|
<form action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="add_alias">
|
||||||
<div class="flex items-center mt-2 w-full text-gray-500 text-sm">
|
<div class="flex items-center mt-2 w-full text-gray-500 text-sm">
|
||||||
<span class="mr-2">Map</span>
|
<span class="mr-2">Map</span>
|
||||||
<select name="type" id="select-type"
|
<select name="type" id="select-type"
|
||||||
@ -203,7 +207,8 @@
|
|||||||
then change the <span class="underline">language</span> to <span
|
then change the <span class="underline">language</span> to <span
|
||||||
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono mr-1">{{ $mapping.Language }}</span>
|
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono mr-1">{{ $mapping.Language }}</span>
|
||||||
</div>
|
</div>
|
||||||
<form class="float-right" action="settings/language_mappings/delete" method="post">
|
<form class="float-right" action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="delete_mapping">
|
||||||
<input type="hidden" id="mapping_id" name="mapping_id" required value="{{ $mapping.ID }}">
|
<input type="hidden" id="mapping_id" name="mapping_id" required value="{{ $mapping.ID }}">
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="py-1 px-3 rounded border border-red-500 hover:border-red-600 text-gray-400 text-sm">
|
class="py-1 px-3 rounded border border-red-500 hover:border-red-600 text-gray-400 text-sm">
|
||||||
@ -216,7 +221,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white">Add Rule</h3>
|
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white">Add Rule</h3>
|
||||||
<form action="settings/language_mappings" method="post">
|
<form action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="add_mapping">
|
||||||
<div class="flex items-center w-full text-gray-500 text-sm">
|
<div class="flex items-center w-full text-gray-500 text-sm">
|
||||||
<span class="mr-2">When filename ends in</span>
|
<span class="mr-2">When filename ends in</span>
|
||||||
<input class="shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3"
|
<input class="shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3"
|
||||||
@ -241,7 +247,8 @@
|
|||||||
Badges
|
Badges
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="mt-6" action="settings/badges" method="post">
|
<form class="mt-6" action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="toggle_badges">
|
||||||
<div class="text-gray-300 text-sm mb-4">
|
<div class="text-gray-300 text-sm mb-4">
|
||||||
{{ if .User.BadgesEnabled }}
|
{{ if .User.BadgesEnabled }}
|
||||||
<p>Badges are currently enabled. You can disable the feature by deactivating the respective API
|
<p>Badges are currently enabled. You can disable the feature by deactivating the respective API
|
||||||
@ -328,7 +335,8 @@
|
|||||||
target="_blank">get your API key</a> and paste it here.</p>
|
target="_blank">get your API key</a> and paste it here.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form action="settings/wakatime_integration" method="post">
|
<form action="" method="post">
|
||||||
|
<input type="hidden" name="action" value="toggle_wakatime">
|
||||||
|
|
||||||
{{ $placeholderText := "Paste your WakaTime API key here ..." }}
|
{{ $placeholderText := "Paste your WakaTime API key here ..." }}
|
||||||
{{ if .User.WakatimeApiKey }}
|
{{ if .User.WakatimeApiKey }}
|
||||||
@ -390,7 +398,8 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 flex justify-center">
|
<div class="mt-6 flex justify-center">
|
||||||
<form action="settings/regenerate" method="post" id="form-regenerate-summaries">
|
<form action="" method="post" id="form-regenerate-summaries">
|
||||||
|
<input type="hidden" name="action" value="regenerate_summaries">
|
||||||
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
||||||
id="btn-regenerate-summaries">
|
id="btn-regenerate-summaries">
|
||||||
Clear & Regenerate
|
Clear & Regenerate
|
||||||
@ -408,8 +417,9 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 flex justify-center">
|
<div class="mt-6 flex justify-center">
|
||||||
<form action="settings/user/delete" method="post" id="form-delete-user">
|
<form action="" method="post" id="form-delete-user">
|
||||||
<button type="button" onclick="console.log('boom')" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
<input type="hidden" name="action" value="delete_account">
|
||||||
|
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
||||||
id="btn-confirm-delete-user">
|
id="btn-confirm-delete-user">
|
||||||
Delete my Account
|
Delete my Account
|
||||||
</button>
|
</button>
|
||||||
|
Reference in New Issue
Block a user