2017-12-09 00:21:58 +00:00
package sync
import (
"fmt"
"path"
"strings"
"strconv"
"srs.epita.fr/fic-server/libfic"
2018-08-17 19:18:10 +00:00
"gopkg.in/russross/blackfriday.v2"
2017-12-09 00:21:58 +00:00
)
2018-05-11 23:08:37 +00:00
// getExercices returns all exercice directories existing in a given theme, considering the given Importer.
2017-12-09 00:21:58 +00:00
func getExercices ( i Importer , theme fic . Theme ) ( [ ] string , error ) {
var exercices [ ] string
2018-07-13 05:25:21 +00:00
if len ( theme . Path ) == 0 {
return [ ] string { } , nil
} else if dirs , err := i . listDir ( theme . Path ) ; err != nil {
2017-12-09 00:21:58 +00:00
return [ ] string { } , err
} else {
for _ , dir := range dirs {
2018-07-13 05:25:21 +00:00
if _ , err := i . listDir ( path . Join ( theme . Path , dir ) ) ; err == nil {
2017-12-09 00:21:58 +00:00
exercices = append ( exercices , dir )
}
}
}
return exercices , nil
}
2018-05-11 23:08:37 +00:00
// SyncExercices imports new or updates existing exercices, in a given theme.
2017-12-09 00:21:58 +00:00
func SyncExercices ( i Importer , theme fic . Theme ) [ ] string {
var errs [ ] string
if exercices , err := getExercices ( i , theme ) ; err != nil {
errs = append ( errs , err . Error ( ) )
} else {
2018-09-09 20:50:06 +00:00
dmap := map [ int64 ] fic . Exercice { }
2017-12-09 00:21:58 +00:00
emap := map [ string ] int { }
for _ , edir := range exercices {
edir_splt := strings . SplitN ( edir , "-" , 2 )
if len ( edir_splt ) != 2 {
errs = append ( errs , fmt . Sprintf ( "%q is not a valid exercice directory: missing id prefix" , edir ) )
continue
}
eid , err := strconv . Atoi ( edir_splt [ 0 ] )
if err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: invalid exercice identifier: %s" , edir , err ) )
continue
}
ename := edir_splt [ 1 ]
emap [ ename ] = eid
2017-12-17 13:30:48 +00:00
// Overview and scenario
2018-07-13 05:25:21 +00:00
overview , err := getFileContent ( i , path . Join ( theme . Path , edir , "overview.txt" ) )
2017-12-17 13:30:48 +00:00
if err != nil {
2018-05-12 00:01:49 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: overview.txt: %s" , edir , err ) )
2017-12-17 13:30:48 +00:00
}
2018-07-13 05:25:21 +00:00
statement , err := getFileContent ( i , path . Join ( theme . Path , edir , "statement.txt" ) )
2017-12-09 00:21:58 +00:00
if err != nil {
2018-05-12 00:01:49 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: statement.txt: %s" , edir , err ) )
2017-12-09 00:21:58 +00:00
continue
}
2018-01-10 02:45:56 +00:00
// Handle score gain
var gain int64
2018-09-09 20:50:06 +00:00
var depend * fic . Exercice
2018-11-18 21:44:23 +00:00
var tags [ ] string
2018-07-13 05:25:21 +00:00
if p , err := parseExerciceParams ( i , path . Join ( theme . Path , edir ) ) ; err != nil {
2018-05-12 00:01:49 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: %s" , edir , err ) )
2018-01-10 02:45:56 +00:00
continue
} else if p . Gain == 0 {
2018-05-12 00:01:49 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: Undefined gain for challenge" , edir ) )
2018-01-10 02:45:56 +00:00
} else {
gain = p . Gain
2018-11-18 21:44:23 +00:00
tags = p . Tags
2018-09-09 20:50:06 +00:00
// Handle dependency
if len ( p . Dependencies ) > 0 {
if len ( p . Dependencies [ 0 ] . Theme ) > 0 && p . Dependencies [ 0 ] . Theme != theme . Name {
errs = append ( errs , fmt . Sprintf ( "%q: unable to treat dependency to another theme: not implemented." , edir ) )
} else {
for ed , e := range dmap {
if ed == p . Dependencies [ 0 ] . Id {
depend = & e
break
}
}
if depend == nil {
dmap_keys := [ ] string { }
for k , _ := range dmap {
dmap_keys = append ( dmap_keys , fmt . Sprintf ( "%d" , k ) )
}
errs = append ( errs , fmt . Sprintf ( "%q: Unable to find required dependancy %q (available at time of processing: %s)" , edir , p . Dependencies [ 0 ] . Id , strings . Join ( dmap_keys , "," ) ) )
}
}
}
2018-01-10 02:45:56 +00:00
}
2017-12-09 00:21:58 +00:00
2018-01-06 15:41:33 +00:00
// Handle video
2018-07-13 05:25:21 +00:00
videoURI := path . Join ( theme . Path , edir , "resolution.mp4" )
2018-05-12 00:01:49 +00:00
if ! i . exists ( videoURI ) {
errs = append ( errs , fmt . Sprintf ( "%q: resolution.mp4: no video file found at %s" , edir , videoURI ) )
videoURI = ""
2018-01-06 15:41:33 +00:00
}
2017-12-09 00:21:58 +00:00
2018-08-17 19:18:10 +00:00
// Markdown pre-formating
statement = string ( blackfriday . Run ( [ ] byte ( statement ) ) )
overview = string ( blackfriday . Run ( [ ] byte ( overview ) ) )
2018-11-18 21:44:23 +00:00
e , err := theme . GetExerciceByTitle ( ename )
if err != nil {
if e , err = theme . AddExercice ( ename , fic . ToURLid ( ename ) , path . Join ( theme . Path , edir ) , statement , overview , depend , gain , videoURI ) ; err != nil {
2017-12-09 00:21:58 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: error on exercice add: %s" , edir , err ) )
continue
}
2018-06-23 13:20:45 +00:00
} else if e . Title != ename || e . URLId == "" || e . Statement != statement || e . Overview != overview || e . Gain != gain || e . VideoURI != videoURI {
2017-12-09 00:21:58 +00:00
e . Title = ename
2018-06-23 13:20:45 +00:00
e . URLId = fic . ToURLid ( ename )
2017-12-09 00:21:58 +00:00
e . Statement = statement
2017-12-17 13:30:48 +00:00
e . Overview = overview
2017-12-09 00:21:58 +00:00
e . Gain = gain
e . VideoURI = videoURI
if _ , err := e . Update ( ) ; err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: error on exercice update: %s" , edir , err ) )
continue
}
2018-11-18 21:44:23 +00:00
}
dmap [ int64 ( eid ) ] = e
if _ , err := e . WipeTags ( ) ; err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: Unable to wipe tags: %s" , edir , err ) )
}
for _ , tag := range tags {
if _ , err := e . AddTag ( tag ) ; err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: Unable to add tag: %s" , edir , err ) )
continue
}
2017-12-09 00:21:58 +00:00
}
}
2017-12-12 15:54:32 +00:00
// Remove old exercices
if exercices , err := theme . GetExercices ( ) ; err == nil {
for _ , ex := range exercices {
if _ , ok := emap [ ex . Title ] ; ! ok {
ex . Delete ( )
2017-12-17 15:00:32 +00:00
}
}
}
2017-12-09 00:21:58 +00:00
}
return errs
}
2018-05-11 23:08:37 +00:00
// ApiListRemoteExercices is an accessor letting foreign packages to access remote exercices list.
2017-12-09 00:21:58 +00:00
func ApiListRemoteExercices ( theme fic . Theme , _ [ ] byte ) ( interface { } , error ) {
return getExercices ( GlobalImporter , theme )
}