mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat: ability to clear all user data (resolve #339)
This commit is contained in:
parent
8e558d8dee
commit
e7e5254673
@ -69,3 +69,8 @@ func (m *HeartbeatServiceMock) DeleteBefore(time time.Time) error {
|
|||||||
args := m.Called(time)
|
args := m.Called(time)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *HeartbeatServiceMock) DeleteByUser(u *models.User) error {
|
||||||
|
args := m.Called(u)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
@ -176,3 +176,12 @@ func (r *HeartbeatRepository) DeleteBefore(t time.Time) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *HeartbeatRepository) DeleteByUser(user *models.User) error {
|
||||||
|
if err := r.db.
|
||||||
|
Where("user_id = ?", user.ID).
|
||||||
|
Delete(models.Heartbeat{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -30,6 +30,7 @@ type IHeartbeatRepository interface {
|
|||||||
CountByUsers([]*models.User) ([]*models.CountByUser, error)
|
CountByUsers([]*models.User) ([]*models.CountByUser, error)
|
||||||
GetEntitySetByUser(uint8, *models.User) ([]string, error)
|
GetEntitySetByUser(uint8, *models.User) ([]string, error)
|
||||||
DeleteBefore(time.Time) error
|
DeleteBefore(time.Time) error
|
||||||
|
DeleteByUser(*models.User) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type IDiagnosticsRepository interface {
|
type IDiagnosticsRepository interface {
|
||||||
|
@ -151,6 +151,8 @@ func (h *SettingsHandler) dispatchAction(action string) action {
|
|||||||
return h.actionImportWakatime
|
return h.actionImportWakatime
|
||||||
case "regenerate_summaries":
|
case "regenerate_summaries":
|
||||||
return h.actionRegenerateSummaries
|
return h.actionRegenerateSummaries
|
||||||
|
case "clear_data":
|
||||||
|
return h.actionClearData
|
||||||
case "delete_account":
|
case "delete_account":
|
||||||
return h.actionDeleteUser
|
return h.actionDeleteUser
|
||||||
}
|
}
|
||||||
@ -553,6 +555,29 @@ func (h *SettingsHandler) actionRegenerateSummaries(w http.ResponseWriter, r *ht
|
|||||||
return http.StatusAccepted, "summaries are being regenerated - this may take a up to a couple of minutes, please come back later", ""
|
return http.StatusAccepted, "summaries are being regenerated - this may take a up to a couple of minutes, please come back later", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) actionClearData(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
|
if h.config.IsDev() {
|
||||||
|
loadTemplates()
|
||||||
|
}
|
||||||
|
|
||||||
|
user := middlewares.GetPrincipal(r)
|
||||||
|
logbuch.Info("user '%s' requested to delete all data", user.ID)
|
||||||
|
|
||||||
|
go func(user *models.User) {
|
||||||
|
logbuch.Info("deleting summaries for user '%s'", user.ID)
|
||||||
|
if err := h.summarySrvc.DeleteByUser(user.ID); err != nil {
|
||||||
|
logbuch.Error("failed to clear summaries: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logbuch.Info("deleting heartbeats for user '%s'", user.ID)
|
||||||
|
if err := h.heartbeatSrvc.DeleteByUser(user); err != nil {
|
||||||
|
logbuch.Error("failed to clear heartbeats: %v", err)
|
||||||
|
}
|
||||||
|
}(user)
|
||||||
|
|
||||||
|
return http.StatusAccepted, "deletion in progress, this may take a couple of seconds", ""
|
||||||
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) actionDeleteUser(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
func (h *SettingsHandler) actionDeleteUser(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||||
if h.config.IsDev() {
|
if h.config.IsDev() {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
|
@ -179,9 +179,15 @@ func (srv *HeartbeatService) GetEntitySetByUser(entityType uint8, user *models.U
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (srv *HeartbeatService) DeleteBefore(t time.Time) error {
|
func (srv *HeartbeatService) DeleteBefore(t time.Time) error {
|
||||||
|
go srv.cache.Flush()
|
||||||
return srv.repository.DeleteBefore(t)
|
return srv.repository.DeleteBefore(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srv *HeartbeatService) DeleteByUser(user *models.User) error {
|
||||||
|
go srv.cache.Flush()
|
||||||
|
return srv.repository.DeleteByUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
func (srv *HeartbeatService) augmented(heartbeats []*models.Heartbeat, userId string) ([]*models.Heartbeat, error) {
|
func (srv *HeartbeatService) augmented(heartbeats []*models.Heartbeat, userId string) ([]*models.Heartbeat, error) {
|
||||||
languageMapping, err := srv.languageMappingSrvc.ResolveByUser(userId)
|
languageMapping, err := srv.languageMappingSrvc.ResolveByUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -39,6 +39,7 @@ type IHeartbeatService interface {
|
|||||||
GetLatestByOriginAndUser(string, *models.User) (*models.Heartbeat, error)
|
GetLatestByOriginAndUser(string, *models.User) (*models.Heartbeat, error)
|
||||||
GetEntitySetByUser(uint8, *models.User) ([]string, error)
|
GetEntitySetByUser(uint8, *models.User) ([]string, error)
|
||||||
DeleteBefore(time.Time) error
|
DeleteBefore(time.Time) error
|
||||||
|
DeleteByUser(*models.User) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type IDiagnosticsService interface {
|
type IDiagnosticsService interface {
|
||||||
|
@ -21,6 +21,11 @@ PetiteVue.createApp({
|
|||||||
document.querySelector('#form-import-wakatime').submit()
|
document.querySelector('#form-import-wakatime').submit()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
confirmClearData() {
|
||||||
|
if (confirm('Are you sure? This can not be undone!')) {
|
||||||
|
document.querySelector('#form-clear-data').submit()
|
||||||
|
}
|
||||||
|
},
|
||||||
confirmDeleteAccount() {
|
confirmDeleteAccount() {
|
||||||
if (confirm('Are you sure? This can not be undone!')) {
|
if (confirm('Are you sure? This can not be undone!')) {
|
||||||
document.querySelector('#form-delete-user').submit()
|
document.querySelector('#form-delete-user').submit()
|
||||||
|
@ -1 +1 @@
|
|||||||
2.2.7
|
2.3.0
|
@ -609,7 +609,7 @@
|
|||||||
Regenerate all pre-computed summaries from raw heartbeat data. This may be useful if, for some reason, summaries are faulty or preconditions have change (e.g. you modified language mappings retrospectively). This may take some time. Be careful and only run this action if you know, what your are doing, as data loss might occur.
|
Regenerate all pre-computed summaries from raw heartbeat data. This may be useful if, for some reason, summaries are faulty or preconditions have change (e.g. you modified language mappings retrospectively). This may take some time. Be careful and only run this action if you know, what your are doing, as data loss might occur.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 ml-4">
|
<div class="w-1/2 ml-4 flex items-center">
|
||||||
<button type="button" class="btn-danger ml-1" @click.stop="confirmRegenerate">Clear and regenerate</button>
|
<button type="button" class="btn-danger ml-1" @click.stop="confirmRegenerate">Clear and regenerate</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -623,11 +623,25 @@
|
|||||||
Please note that resetting your API key requires you to update your .wakatime.cfg files on all of your computers to make the WakaTime client send heartbeats again.
|
Please note that resetting your API key requires you to update your .wakatime.cfg files on all of your computers to make the WakaTime client send heartbeats again.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 ml-4">
|
<div class="w-1/2 ml-4 flex items-center">
|
||||||
<button type="submit" class="btn-danger ml-1">Reset API key</button>
|
<button type="submit" class="btn-danger ml-1">Reset API key</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form action="" method="post" class="flex mb-8" id="form-clear-data">
|
||||||
|
<input type="hidden" name="action" value="clear_data">
|
||||||
|
|
||||||
|
<div class="w-1/2 mr-4 inline-block">
|
||||||
|
<span class="font-semibold text-gray-300">Clear Data</span>
|
||||||
|
<span class="block text-sm text-gray-600">
|
||||||
|
Clear all your time tracking data from Wakapi. This cannot be undone. Be careful!
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2 ml-4 flex items-center">
|
||||||
|
<button type="button" class="btn-danger ml-1" @click.stop="confirmClearData">Clear data</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
<form action="" method="post" class="flex mb-8" id="form-delete-user">
|
<form action="" method="post" class="flex mb-8" id="form-delete-user">
|
||||||
<input type="hidden" name="action" value="delete_account">
|
<input type="hidden" name="action" value="delete_account">
|
||||||
|
|
||||||
@ -637,7 +651,7 @@
|
|||||||
Deleting your account will cause all data, including all your heartbeats, to be erased from the server immediately. This action is irreversible. Be careful!
|
Deleting your account will cause all data, including all your heartbeats, to be erased from the server immediately. This action is irreversible. Be careful!
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 ml-4">
|
<div class="w-1/2 ml-4 flex items-center">
|
||||||
<button type="button" class="btn-danger ml-1" @click.stop="confirmDeleteAccount">Delete account</button>
|
<button type="button" class="btn-danger ml-1" @click.stop="confirmDeleteAccount">Delete account</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
Reference in New Issue
Block a user