Able to sync and export standalone exercices
This commit is contained in:
parent
76f830b332
commit
adb0e36dd4
15 changed files with 159 additions and 31 deletions
|
@ -20,6 +20,13 @@ type ThemeError struct {
|
|||
}
|
||||
|
||||
func NewThemeError(theme *fic.Theme, err error) *ThemeError {
|
||||
if theme == nil {
|
||||
return &ThemeError{
|
||||
error: err,
|
||||
ThemePath: StandaloneExercicesDirectory,
|
||||
}
|
||||
}
|
||||
|
||||
return &ThemeError{
|
||||
error: err,
|
||||
ThemeId: theme.Id,
|
||||
|
|
|
@ -100,6 +100,10 @@ func ParseExceptionString(fexcept string, exceptions *CheckExceptions) *CheckExc
|
|||
}
|
||||
|
||||
func LoadThemeException(i Importer, th *fic.Theme) (exceptions *CheckExceptions) {
|
||||
if th == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if fexcept, err := GetFileContent(i, filepath.Join(th.Path, "repochecker-ack.txt")); err == nil {
|
||||
return ParseExceptionString(fexcept, nil)
|
||||
}
|
||||
|
|
|
@ -114,7 +114,9 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
exceptions = LoadExerciceException(i, theme, e, exceptions_in)
|
||||
//log.Printf("Kept repochecker exceptions for this exercice: %v", exceptions)
|
||||
|
||||
e.Language = theme.Language
|
||||
if theme != nil {
|
||||
e.Language = theme.Language
|
||||
}
|
||||
// Overwrite language if language.txt exists
|
||||
if language, err := GetFileContent(i, path.Join(epath, "language.txt")); err == nil {
|
||||
language = strings.TrimSpace(language)
|
||||
|
@ -251,7 +253,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
e.Image = path.Join(epath, "heading.jpg")
|
||||
} else if i.Exists(path.Join(epath, "heading.png")) {
|
||||
e.Image = path.Join(epath, "heading.png")
|
||||
} else if theme.Image == "" {
|
||||
} else if theme == nil || theme.Image == "" {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("heading.jpg: No such file")))
|
||||
}
|
||||
|
||||
|
@ -283,7 +285,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
|
||||
// Handle dependency
|
||||
if len(p.Dependencies) > 0 {
|
||||
if len(p.Dependencies[0].Theme) > 0 && p.Dependencies[0].Theme != theme.Name {
|
||||
if len(p.Dependencies[0].Theme) > 0 && (theme == nil || p.Dependencies[0].Theme != theme.Name) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to treat dependency to another theme (%q): not implemented.", p.Dependencies[0].Theme), theme))
|
||||
} else {
|
||||
if dmap == nil {
|
||||
|
@ -455,6 +457,17 @@ func SyncExercices(i Importer, theme *fic.Theme, exceptions *CheckExceptions) (e
|
|||
|
||||
// ApiListRemoteExercices is an accessor letting foreign packages to access remote exercices list.
|
||||
func ApiListRemoteExercices(c *gin.Context) {
|
||||
if c.Params.ByName("thid") == "_" {
|
||||
exercices, err := GetExercices(GlobalImporter, &fic.Theme{Path: StandaloneExercicesDirectory})
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, exercices)
|
||||
return
|
||||
}
|
||||
|
||||
theme, _, errs := BuildTheme(GlobalImporter, c.Params.ByName("thid"))
|
||||
if theme != nil {
|
||||
exercices, err := GetExercices(GlobalImporter, theme)
|
||||
|
@ -472,6 +485,17 @@ func ApiListRemoteExercices(c *gin.Context) {
|
|||
|
||||
// ApiListRemoteExercice is an accessor letting foreign packages to access remote exercice attributes.
|
||||
func ApiGetRemoteExercice(c *gin.Context) {
|
||||
if c.Params.ByName("thid") == "_" {
|
||||
exercice, _, _, _, _, errs := BuildExercice(GlobalImporter, nil, path.Join(StandaloneExercicesDirectory, c.Params.ByName("exid")), nil, nil)
|
||||
if exercice != nil {
|
||||
c.JSON(http.StatusOK, exercice)
|
||||
return
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Errorf("%q", errs)})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
theme, exceptions, errs := BuildTheme(GlobalImporter, c.Params.ByName("thid"))
|
||||
if theme != nil {
|
||||
exercice, _, _, _, _, errs := BuildExercice(GlobalImporter, theme, path.Join(theme.Path, c.Params.ByName("exid")), nil, exceptions)
|
||||
|
|
|
@ -32,6 +32,7 @@ type SyncReport struct {
|
|||
SyncId string `json:"_id,omitempty"`
|
||||
ThemesSync []string `json:"_themes,omitempty"`
|
||||
Themes map[string][]string `json:"themes"`
|
||||
Exercices []string `json:"exercices,omitempty"`
|
||||
}
|
||||
|
||||
// SpeedySyncDeep performs a recursive synchronisation without importing files.
|
||||
|
@ -57,6 +58,11 @@ func SpeedySyncDeep(i Importer) (errs SyncReport) {
|
|||
|
||||
if themes, err := fic.GetThemes(); err == nil {
|
||||
DeepSyncProgress = 2
|
||||
|
||||
if i.Exists(StandaloneExercicesDirectory) {
|
||||
themes = append([]*fic.Theme{}, &fic.Theme{Path: StandaloneExercicesDirectory})
|
||||
}
|
||||
|
||||
var themeStep uint8 = uint8(250) / uint8(len(themes))
|
||||
|
||||
for tid, theme := range themes {
|
||||
|
@ -113,14 +119,22 @@ func SyncDeep(i Importer) (errs SyncReport) {
|
|||
|
||||
startTime := time.Now()
|
||||
|
||||
// Import all themes
|
||||
errs.DateStart = startTime
|
||||
exceptions, sterrs := SyncThemes(i)
|
||||
for _, sterr := range multierr.Errors(sterrs) {
|
||||
errs.ThemesSync = append(errs.ThemesSync, sterr.Error())
|
||||
}
|
||||
|
||||
if themes, err := fic.GetThemes(); err == nil && len(themes) > 0 {
|
||||
// Synchronize themes
|
||||
if themes, err := fic.GetThemes(); err == nil {
|
||||
DeepSyncProgress = 2
|
||||
|
||||
// Also synchronize standalone exercices
|
||||
if i.Exists(StandaloneExercicesDirectory) {
|
||||
themes = append(themes, &fic.Theme{Path: StandaloneExercicesDirectory})
|
||||
}
|
||||
|
||||
var themeStep uint8 = uint8(250) / uint8(len(themes))
|
||||
|
||||
for tid, theme := range themes {
|
||||
|
|
|
@ -21,13 +21,15 @@ import (
|
|||
"srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
||||
const StandaloneExercicesDirectory = "exercices"
|
||||
|
||||
// GetThemes returns all theme directories in the base directory.
|
||||
func GetThemes(i Importer) (themes []string, err error) {
|
||||
if dirs, err := i.ListDir("/"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for _, dir := range dirs {
|
||||
if !strings.HasPrefix(dir, ".") && !strings.HasPrefix(dir, "_") {
|
||||
if !strings.HasPrefix(dir, ".") && !strings.HasPrefix(dir, "_") && dir != StandaloneExercicesDirectory {
|
||||
if _, err := i.ListDir(dir); err == nil {
|
||||
themes = append(themes, dir)
|
||||
}
|
||||
|
@ -310,6 +312,11 @@ func ApiListRemoteThemes(c *gin.Context) {
|
|||
|
||||
// ApiListRemoteTheme is an accessor letting foreign packages to access remote main theme attributes.
|
||||
func ApiGetRemoteTheme(c *gin.Context) {
|
||||
if c.Params.ByName("thid") == "_" {
|
||||
c.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
r, _, errs := BuildTheme(GlobalImporter, c.Params.ByName("thid"))
|
||||
if r == nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Errorf("%q", errs)})
|
||||
|
|
Reference in a new issue