2017-12-09 00:21:58 +00:00
package sync
import (
2018-01-07 22:40:11 +00:00
"bufio"
2018-02-03 01:03:08 +00:00
"crypto"
2018-01-07 22:40:11 +00:00
"encoding/hex"
2017-12-09 00:21:58 +00:00
"fmt"
2018-01-07 22:40:11 +00:00
"io"
"os"
2017-12-09 00:21:58 +00:00
"path"
2018-01-07 22:40:11 +00:00
"strings"
2017-12-09 00:21:58 +00:00
"srs.epita.fr/fic-server/libfic"
2018-08-17 19:18:10 +00:00
"gopkg.in/russross/blackfriday.v2"
2018-02-03 01:03:08 +00:00
_ "golang.org/x/crypto/blake2b"
2018-01-07 22:40:11 +00:00
)
2017-12-09 00:21:58 +00:00
2018-03-09 18:07:08 +00:00
// SyncExerciceHints reads the content of hints/ directories and import it as EHint for the given challenge.
2018-01-07 22:40:11 +00:00
func SyncExerciceHints ( i Importer , exercice fic . Exercice ) ( errs [ ] string ) {
2018-01-10 03:42:50 +00:00
params , err := parseExerciceParams ( i , exercice . Path )
if err != nil {
2018-05-12 00:01:49 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: %s" , path . Base ( exercice . Path ) , err ) )
2018-01-10 03:42:50 +00:00
}
2017-12-09 00:21:58 +00:00
if _ , err := exercice . WipeHints ( ) ; err != nil {
errs = append ( errs , err . Error ( ) )
} else {
2018-08-17 19:13:13 +00:00
for n , hint := range params . Hints {
if hint . Title != "" {
hint . Title = fmt . Sprintf ( "Astuce #%d" , n + 1 )
}
if hint . Cost <= 0 {
hint . Cost = exercice . Gain / 4
2018-01-10 03:42:50 +00:00
}
2018-08-17 19:13:13 +00:00
if hint . Filename != "" {
if hint . Content != "" {
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: hint %s (%d): content and filename can't be filled at the same time" , path . Base ( exercice . Path ) , hint . Title , n + 1 ) )
2018-01-07 22:40:11 +00:00
continue
2018-08-17 19:13:13 +00:00
} else if ! i . exists ( path . Join ( exercice . Path , "hints" , hint . Filename ) ) {
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: hint %s (%d): %s: File not found" , path . Base ( exercice . Path ) , hint . Title , n + 1 , hint . Filename ) )
2018-01-07 22:40:11 +00:00
continue
} else {
2018-08-17 19:13:13 +00:00
// Handle files as downloadable content
if res , err := i . importFile ( path . Join ( exercice . Path , "hints" , hint . Filename ) , func ( filePath string , origin string ) ( interface { } , error ) {
// Calculate hash
hash512 := crypto . BLAKE2b_512 . New ( )
if fd , err := os . Open ( filePath ) ; err != nil {
return nil , err
} else {
defer fd . Close ( )
reader := bufio . NewReader ( fd )
if _ , err := io . Copy ( hash512 , reader ) ; err != nil {
return nil , err
}
}
result512 := hash512 . Sum ( nil )
// Special format for downloadable hints: $FILES + hexhash + path from FILES/
return "$FILES" + hex . EncodeToString ( result512 ) + strings . TrimPrefix ( filePath , fic . FilesDir ) , nil
} ) ; err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: unable to import hint file %q: %s" , path . Base ( exercice . Path ) , hint . Filename , err ) )
continue
} else if s , ok := res . ( string ) ; ! ok {
errs = append ( errs , fmt . Sprintf ( "%q: unable to import hint file %q: invalid string returned as filename" , path . Base ( exercice . Path ) , hint . Filename ) )
continue
} else {
hint . Content = s
}
2018-01-07 22:40:11 +00:00
}
2018-08-17 19:18:10 +00:00
} else if hint . Content == "" {
2018-08-17 19:13:13 +00:00
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: hint %s (%d): content and filename can't be empty at the same time" , path . Base ( exercice . Path ) , hint . Title , n + 1 ) )
2017-12-09 00:21:58 +00:00
continue
2018-08-17 19:18:10 +00:00
} else {
hint . Content = string ( blackfriday . Run ( [ ] byte ( hint . Content ) ) )
2018-01-07 22:40:11 +00:00
}
2018-01-10 03:42:50 +00:00
// Import hint
2018-08-17 19:13:13 +00:00
if _ , err := exercice . AddHint ( hint . Title , hint . Content , hint . Cost ) ; err != nil {
errs = append ( errs , fmt . Sprintf ( "%q: challenge.txt: hint %s (%d): %s" , path . Base ( exercice . Path ) , hint . Title , n + 1 , err ) )
2017-12-09 00:21:58 +00:00
}
}
}
2018-01-07 22:40:11 +00:00
return
2017-12-09 00:21:58 +00:00
}