diff --git a/admin/api/repositories.go b/admin/api/repositories.go index 70986aba..9afaea5d 100644 --- a/admin/api/repositories.go +++ b/admin/api/repositories.go @@ -41,5 +41,27 @@ func declareRepositoriesRoutes(router *gin.RouterGroup) { } c.JSON(http.StatusOK, mod) }) + + router.DELETE("/repositories/*repopath", func(c *gin.Context) { + di, ok := sync.GlobalImporter.(sync.DeletableImporter) + if !ok { + c.AbortWithStatusJSON(http.StatusNotImplemented, gin.H{"errmsg": "Not implemented"}) + return + } + + if strings.Contains(c.Param("repopath"), "..") { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Repopath contains invalid characters"}) + return + } + + repopath := strings.TrimPrefix(c.Param("repopath"), "/") + + err := di.DeleteDir(repopath) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) + return + } + c.JSON(http.StatusOK, true) + }) } } diff --git a/admin/api/settings.go b/admin/api/settings.go index 60065c3c..0ea7f0ea 100644 --- a/admin/api/settings.go +++ b/admin/api/settings.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "path" - "reflect" "strconv" "time" @@ -26,7 +25,6 @@ func declareSettingsRoutes(router *gin.RouterGroup) { router.GET("/challenge.json", getChallengeInfo) router.PUT("/challenge.json", saveChallengeInfo) - router.GET("/settings-ro.json", getROSettings) router.GET("/settings.json", getSettings) router.PUT("/settings.json", saveSettings) router.DELETE("/settings.json", func(c *gin.Context) { @@ -98,24 +96,6 @@ func fullGeneration(c *gin.Context) { }) } -func getROSettings(c *gin.Context) { - syncMtd := "Disabled" - if sync.GlobalImporter != nil { - syncMtd = sync.GlobalImporter.Kind() - } - - var syncId *string - if sync.GlobalImporter != nil { - syncId = sync.GlobalImporter.Id() - } - - c.JSON(http.StatusOK, gin.H{ - "sync-type": reflect.TypeOf(sync.GlobalImporter).Name(), - "sync-id": syncId, - "sync": syncMtd, - }) -} - func GetChallengeInfo() (*settings.ChallengeInfo, error) { var challengeinfo string var err error diff --git a/admin/api/sync.go b/admin/api/sync.go index 113524c8..47bfaaad 100644 --- a/admin/api/sync.go +++ b/admin/api/sync.go @@ -7,6 +7,7 @@ import ( "net/url" "os" "path" + "reflect" "strings" "srs.epita.fr/fic-server/admin/generation" @@ -17,6 +18,8 @@ import ( "go.uber.org/multierr" ) +var lastSyncError = "" + func flatifySyncErrors(errs error) (ret []string) { for _, err := range multierr.Errors(errs) { ret = append(ret, err.Error()) @@ -27,12 +30,37 @@ func flatifySyncErrors(errs error) (ret []string) { func declareSyncRoutes(router *gin.RouterGroup) { apiSyncRoutes := router.Group("/sync") + // Return the global sync status + apiSyncRoutes.GET("/status", func(c *gin.Context) { + syncMtd := "Disabled" + if sync.GlobalImporter != nil { + syncMtd = sync.GlobalImporter.Kind() + } + + var syncId *string + if sync.GlobalImporter != nil { + syncId = sync.GlobalImporter.Id() + } + + c.JSON(http.StatusOK, gin.H{ + "sync-type": reflect.TypeOf(sync.GlobalImporter).Name(), + "sync-id": syncId, + "sync": syncMtd, + "pullMutex": !sync.OneGitPullStatus(), + "syncMutex": !sync.OneDeepSyncStatus() && !sync.OneThemeDeepSyncStatus(), + "progress": sync.DeepSyncProgress, + "lastError": lastSyncError, + }) + }) + // Base sync checks if the local directory is in sync with remote one. apiSyncRoutes.POST("/base", func(c *gin.Context) { err := sync.GlobalImporter.Sync() if err != nil { + lastSyncError = err.Error() c.JSON(http.StatusExpectationFailed, gin.H{"errmsg": err.Error()}) } else { + lastSyncError = "" c.JSON(http.StatusOK, true) } }) @@ -45,15 +73,10 @@ func declareSyncRoutes(router *gin.RouterGroup) { }) // Deep sync: a fully recursive synchronization (can be limited by theme). - apiSyncRoutes.GET("/deep", func(c *gin.Context) { - if sync.DeepSyncProgress == 0 { - c.AbortWithStatusJSON(http.StatusTooEarly, gin.H{"errmsg": "Pas de synchronisation en cours"}) - return - } - c.JSON(http.StatusOK, gin.H{"progress": sync.DeepSyncProgress}) - }) apiSyncRoutes.POST("/deep", func(c *gin.Context) { - c.JSON(http.StatusOK, sync.SyncDeep(sync.GlobalImporter)) + r := sync.SyncDeep(sync.GlobalImporter) + lastSyncError = "" + c.JSON(http.StatusOK, r) }) apiSyncDeepRoutes := apiSyncRoutes.Group("/deep/:thid") @@ -66,6 +89,7 @@ func declareSyncRoutes(router *gin.RouterGroup) { } sync.EditDeepReport(&sync.SyncReport{Exercices: st}, false) sync.DeepSyncProgress = 255 + lastSyncError = "" c.JSON(http.StatusOK, st) }) apiSyncDeepRoutes.POST("", func(c *gin.Context) { @@ -79,6 +103,7 @@ func declareSyncRoutes(router *gin.RouterGroup) { } sync.EditDeepReport(&sync.SyncReport{Themes: map[string][]string{theme.Name: st}}, false) sync.DeepSyncProgress = 255 + lastSyncError = "" c.JSON(http.StatusOK, st) }) @@ -90,6 +115,7 @@ func declareSyncRoutes(router *gin.RouterGroup) { apiSyncRoutes.POST("/themes", func(c *gin.Context) { _, errs := sync.SyncThemes(sync.GlobalImporter) + lastSyncError = "" c.JSON(http.StatusOK, flatifySyncErrors(errs)) }) diff --git a/admin/static/js/app.js b/admin/static/js/app.js index 0039770e..77b9c2cd 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -230,9 +230,6 @@ angular.module("FICApp") .factory("File", function ($resource) { return $resource("api/files/:fileId", { fileId: '@id' }) }) - .factory("ROSettings", function ($resource) { - return $resource("api/settings-ro.json") - }) .factory("Settings", function ($resource) { return $resource("api/settings.json", null, { 'update': { method: 'PUT' }, @@ -755,6 +752,12 @@ angular.module("FICApp") $http.get("api/repositories").then(function (response) { $scope.repositories = response.data.repositories; }); + + $scope.deleteRepository = function(repo) { + $http.delete("api/repositories/" + repo.path).then(function (response) { + $scope.repositories[$scope.repositories.indexOf(repo)].hash = "- DELETED -"; + }); + }; }) .component('repositoryUptodate', { bindings: { @@ -781,9 +784,8 @@ angular.module("FICApp") template: `{{ $ctrl.status.hash }} {{ $ctrl.status.text }}` }) - .controller("SyncController", function ($scope, $rootScope, ROSettings, $location, $http, $interval) { + .controller("SyncController", function ($scope, $rootScope, $location, $http, $interval) { $scope.displayDangerousActions = false; - $scope.configro = ROSettings.get(); var needRefreshSyncReportWhenReady = false; var refreshSyncReport = function () { @@ -794,30 +796,28 @@ angular.module("FICApp") }; refreshSyncReport() + $scope.deepSyncInProgress = false; + var progressInterval = $interval(function () { - $http.get("api/sync/deep").then(function (response) { + $http.get("api/sync/status").then(function (response) { if (response.data.progress && response.data.progress != 255) needRefreshSyncReportWhenReady = true; else if (needRefreshSyncReportWhenReady) refreshSyncReport(); if (response.data && response.data.progress) { $scope.syncPercent = Math.floor(response.data.progress * 100 / 255); - $scope.syncProgress = Math.floor(response.data.progress * 100 / 255) + " %"; + $scope.deepSyncInProgress = response.data.pullMutex && response.data.syncMutex; } else { - $scope.syncProgress = response.data; $scope.syncPercent = 0; } + $scope.syncStatus = response.data; }, function (response) { $scope.syncPercent = 0; - if (response.data && response.data.errmsg) - $scope.syncProgress = response.data.errmsg; - else - $scope.syncProgress = response.data; + $scope.syncStatus = response.data; }) }, 1500); $scope.$on('$destroy', function () { $interval.cancel(progressInterval); }); - $scope.deepSyncInProgress = false; $scope.deepSync = function (theme) { if (theme) { question = 'Faire une synchronisation intégrale du thème ' + theme.name + ' ?' diff --git a/admin/static/views/repositories.html b/admin/static/views/repositories.html index 3946b181..daca48fa 100644 --- a/admin/static/views/repositories.html +++ b/admin/static/views/repositories.html @@ -9,16 +9,20 @@ Chemin Branche - Commit - Plus récent + Commit Plus récent {{ repository.path }} {{ repository.branch }} - {{ repository.hash }} - + + {{ repository.hash }}
+ + + + + diff --git a/admin/static/views/sync.html b/admin/static/views/sync.html index 847c9969..3643d4d5 100644 --- a/admin/static/views/sync.html +++ b/admin/static/views/sync.html @@ -32,17 +32,25 @@
Type
-
+
Synchronisation
-
-
ID
-
{{ configro['sync-id'] }}
-
Statut
-
{{ syncProgress }}
+
+
ID
+
+ {{ syncStatus['sync-id'] }} + +
+
Statut
+
+ {{ syncPercent }} % + Pull + Synchronisation +
-
- +
{{ syncStatus.lastError }}
+ +
diff --git a/qa/ui/vite.config.js b/qa/ui/vite.config.js index 87470505..f7d505e3 100644 --- a/qa/ui/vite.config.js +++ b/qa/ui/vite.config.js @@ -2,6 +2,12 @@ import { sveltekit } from '@sveltejs/kit/vite'; /** @type {import('vite').UserConfig} */ const config = { + server: { + hmr: { + port: 10001 + } + }, + plugins: [sveltekit()] };