admin: Add link to forge
This commit is contained in:
parent
80917ae436
commit
2c76b5c7a3
|
@ -85,6 +85,11 @@ func declareExercicesRoutes(router *gin.RouterGroup) {
|
|||
router.GET("/remote/themes/:thid/exercices/:exid/flags", sync.ApiGetRemoteExerciceFlags)
|
||||
}
|
||||
|
||||
type Exercice struct {
|
||||
*fic.Exercice
|
||||
ForgeLink string `json:"forge_link,omitempty"`
|
||||
}
|
||||
|
||||
func ExerciceHandler(c *gin.Context) {
|
||||
eid, err := strconv.ParseInt(string(c.Params.ByName("eid")), 10, 32)
|
||||
if err != nil {
|
||||
|
@ -359,7 +364,16 @@ func listExerciceQuiz(c *gin.Context) {
|
|||
}
|
||||
|
||||
func showExercice(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, c.MustGet("exercice").(*fic.Exercice))
|
||||
exercice := c.MustGet("exercice").(*fic.Exercice)
|
||||
|
||||
var forgelink string
|
||||
if fli, ok := sync.GlobalImporter.(sync.ForgeLinkedImporter); ok {
|
||||
if u, _ := fli.GetExerciceLink(exercice); u != nil {
|
||||
forgelink = u.String()
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Exercice{exercice, forgelink})
|
||||
}
|
||||
|
||||
func getExerciceHistory(c *gin.Context) {
|
||||
|
|
|
@ -51,6 +51,11 @@ func declareThemesRoutes(router *gin.RouterGroup) {
|
|||
router.GET("/remote/themes/:thid/exercices", sync.ApiListRemoteExercices)
|
||||
}
|
||||
|
||||
type Theme struct {
|
||||
*fic.Theme
|
||||
ForgeLink string `json:"forge_link,omitempty"`
|
||||
}
|
||||
|
||||
func ThemeHandler(c *gin.Context) {
|
||||
thid, err := strconv.ParseInt(string(c.Params.ByName("thid")), 10, 64)
|
||||
if err != nil {
|
||||
|
@ -142,7 +147,16 @@ func exportThemes(c *gin.Context) {
|
|||
}
|
||||
|
||||
func showTheme(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, c.MustGet("theme").(*fic.Theme))
|
||||
theme := c.MustGet("theme").(*fic.Theme)
|
||||
|
||||
var forgelink string
|
||||
if fli, ok := sync.GlobalImporter.(sync.ForgeLinkedImporter); ok {
|
||||
if u, _ := fli.GetThemeLink(theme); u != nil {
|
||||
forgelink = u.String()
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, Theme{theme, forgelink})
|
||||
}
|
||||
|
||||
func createTheme(c *gin.Context) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<a href="exercices/{{exercice.id}}/resolution" ng-disabled="!exercice.videoURI" class="float-right ml-2 btn btn-sm btn-info"><span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> Vidéo</a>
|
||||
<a href="exercices/{{exercice.id}}/flags" class="float-right ml-2 btn btn-sm btn-success"><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> Flags</a>
|
||||
<button type="button" ng-click="syncExo()" ng-class="{'disabled': inSync}" class="float-right ml-2 btn btn-sm btn-light"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Synchroniser</button>
|
||||
<a href="{{exercice.forge_link}}" target="_blank" class="float-right ml-2 btn btn-sm btn-dark" ng-if="exercice.forge_link"><span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span> Voir sur la forge</a>
|
||||
</h2>
|
||||
|
||||
<div class="row mb-5">
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<h2>{{theme.name}} <small>{{theme.authors | stripHTML}}</small></h2>
|
||||
<h2>
|
||||
{{theme.name}} <small>{{theme.authors | stripHTML}}</small>
|
||||
<a href="{{theme.forge_link}}" target="_blank" class="float-right ml-2 btn btn-sm btn-dark" ng-if="theme.forge_link"><span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span> Voir sur la forge</a>
|
||||
</h2>
|
||||
|
||||
<div class="row">
|
||||
<form ng-submit="saveTheme()" class="col-4">
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/base32"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
@ -46,6 +47,12 @@ type DirectAccessImporter interface {
|
|||
GetLocalPath(p ...string) string
|
||||
}
|
||||
|
||||
// ForgeLinkedImporter abstracts importer that are linked to a forge
|
||||
type ForgeLinkedImporter interface {
|
||||
GetThemeLink(th *fic.Theme) (*url.URL, error)
|
||||
GetExerciceLink(e *fic.Exercice) (*url.URL, error)
|
||||
}
|
||||
|
||||
// GlobalImporter stores the main importer instance to use for global imports.
|
||||
var GlobalImporter Importer
|
||||
|
||||
|
|
|
@ -2,9 +2,13 @@ package sync
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var gitRemoteRe = regexp.MustCompile(`^(?:(?:git@|https://)([\w.@]+)(?:/|:))((?:[\w-_]+)/(?:[\w-_/]+))(?:.git){0,1}(?:(?:/){0,1})$`)
|
||||
|
||||
func countFileInDir(dirname string) (int, error) {
|
||||
files, err := os.ReadDir(dirname)
|
||||
if err != nil {
|
||||
|
@ -45,3 +49,11 @@ func (i GitImporter) stat(filename string) (os.FileInfo, error) {
|
|||
func (i GitImporter) Kind() string {
|
||||
return "git originated from " + i.Remote + " on " + i.li.Kind()
|
||||
}
|
||||
|
||||
func getForgeBaseLink(remote string) (u *url.URL, err error) {
|
||||
res := gitRemoteRe.FindStringSubmatch(remote)
|
||||
u, err = url.Parse(res[2])
|
||||
u.Scheme = "https"
|
||||
u.Host = res[1]
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,10 +8,13 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
||||
// GitImporter implements an Importer, where files to imports are located
|
||||
|
@ -133,3 +136,75 @@ func (i GitImporter) Sync() error {
|
|||
log.Println("Local git repository synchronized successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i GitImporter) GetThemeLink(th *fic.Theme) (u *url.URL, err error) {
|
||||
prefix := ""
|
||||
|
||||
if _, err = os.Stat(path.Join(i.li.Base, ".gitmodules")); !errors.Is(err, os.ErrNotExist) {
|
||||
thdir := path.Join(i.li.Base, th.Path)
|
||||
cmdremote := exec.Command("git", "-C", thdir, "remote", "get-url", "origin")
|
||||
var stdout []byte
|
||||
stdout, err = cmdremote.CombinedOutput()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
u, err = getForgeBaseLink(string(bytes.TrimSpace(stdout)))
|
||||
|
||||
// Search .git directory
|
||||
for {
|
||||
if _, err = os.Stat(path.Join(thdir, ".git")); !errors.Is(err, os.ErrNotExist) {
|
||||
break
|
||||
}
|
||||
|
||||
thdir, _ = path.Split(thdir)
|
||||
}
|
||||
prefix = strings.TrimPrefix(thdir, i.li.Base)
|
||||
} else {
|
||||
u, err = getForgeBaseLink(i.Remote)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
u.Path = path.Join(u.Path, "-", "tree", "master", strings.TrimPrefix(th.Path, prefix))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (i GitImporter) GetExerciceLink(e *fic.Exercice) (u *url.URL, err error) {
|
||||
prefix := ""
|
||||
|
||||
if _, err = os.Stat(path.Join(i.li.Base, ".gitmodules")); !errors.Is(err, os.ErrNotExist) {
|
||||
exdir := path.Join(i.li.Base, e.Path)
|
||||
cmdremote := exec.Command("git", "-C", exdir, "remote", "get-url", "origin")
|
||||
var stdout []byte
|
||||
stdout, err = cmdremote.CombinedOutput()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
u, err = getForgeBaseLink(string(bytes.TrimSpace(stdout)))
|
||||
|
||||
// Search .git directory
|
||||
for {
|
||||
if _, err = os.Stat(path.Join(exdir, ".git")); !errors.Is(err, os.ErrNotExist) {
|
||||
break
|
||||
}
|
||||
|
||||
exdir, _ = path.Split(exdir)
|
||||
}
|
||||
prefix = strings.TrimPrefix(exdir, i.li.Base)
|
||||
} else {
|
||||
u, err = getForgeBaseLink(i.Remote)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
u.Path = path.Join(u.Path, "-", "tree", "master", strings.TrimPrefix(e.Path, prefix))
|
||||
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue