admin: Embed static assets into binary

This commit is contained in:
nemunaire 2021-06-09 01:11:23 +02:00
commit 7fc860edec
37 changed files with 1569 additions and 1669 deletions

View file

@ -24,9 +24,3 @@ WORKDIR /srv
ENTRYPOINT ["/srv/admin", "-bind=:8081", "-baseurl=/admin/"]
COPY --from=gobuild /go/src/srs.epita.fr/fic-server/admin/admin /srv/admin
COPY admin/static/check_import.html /srv/htdocs-admin/
COPY admin/static/css/bootstrap.min.css frontend/static/css/glyphicon.css /srv/htdocs-admin/css/
COPY frontend/static/fonts /srv/htdocs-admin/fonts
COPY admin/static/img /srv/htdocs-admin/img
COPY admin/static/views /srv/htdocs-admin/views
COPY admin/static/js/app.js frontend/static/js/angular.min.js admin/static/js/angular-resource.min.js frontend/static/js/angular-route.min.js frontend/static/js/angular-sanitize.min.js frontend/static/js/bootstrap.min.js frontend/static/js/common.js frontend/static/js/d3.v3.min.js frontend/static/js/i18n frontend/static/js/jquery.min.js admin/static/js/popper.min.js /srv/htdocs-admin/js/

View file

@ -48,7 +48,7 @@ If your are trying to use the folder available with the Owncloud service, make t
Running this project requires a web server (configuration is given for nginx),
a database (currently supporting only MySQL/MariaDB), a Go compiler for the revision
1.9 at least and a `inotify`-aware system.
1.16 at least and a `inotify`-aware system.
1. First, you'll need to retrieve the dependencies:

View file

@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"io/fs"
"log"
"net/http"
"net/url"
@ -13,7 +14,6 @@ import (
"path/filepath"
"strings"
"syscall"
"text/template"
"srs.epita.fr/fic-server/admin/api"
"srs.epita.fr/fic-server/admin/pki"
@ -22,8 +22,6 @@ import (
"srs.epita.fr/fic-server/settings"
)
var StaticDir string
type ResponseWriterPrefix struct {
real http.ResponseWriter
prefix string
@ -94,7 +92,7 @@ func main() {
var baseURL = flag.String("baseurl", "/", "URL prepended to each URL")
flag.StringVar(&api.TimestampCheck, "timestampCheck", api.TimestampCheck, "Path regularly touched by frontend to check time synchronisation")
flag.StringVar(&pki.PKIDir, "pki", "./PKI", "Base directory where found PKI scripts")
flag.StringVar(&StaticDir, "static", "./htdocs-admin/", "Directory containing static files")
var staticDir = flag.String("static", "", "Directory containing static files (default if not provided: use embedded files)")
flag.StringVar(&api.TeamsDir, "teams", "./TEAMS", "Base directory where save teams JSON files")
flag.StringVar(&api.DashboardDir, "dashbord", "./DASHBOARD", "Base directory where save public JSON files")
flag.StringVar(&settings.SettingsDir, "settings", settings.SettingsDir, "Base directory where load and save settings")
@ -129,10 +127,20 @@ func main() {
// Sanitize options
var err error
log.Println("Checking paths...")
if StaticDir, err = filepath.Abs(StaticDir); err != nil {
log.Fatal(err)
if staticDir != nil && *staticDir != "" {
if sDir, err := filepath.Abs(*staticDir); err != nil {
log.Fatal(err)
} else {
staticFS = http.Dir(sDir)
sync.DeepReportPath = path.Join(sDir, sync.DeepReportPath)
}
} else {
sub, err := fs.Sub(assets, "static")
if err != nil {
log.Fatal("Unable to cd to static/ directory:", err)
}
staticFS = http.FS(sub)
}
sync.DeepReportPath = path.Join(StaticDir, sync.DeepReportPath)
if fic.FilesDir, err = filepath.Abs(fic.FilesDir); err != nil {
log.Fatal(err)
}
@ -194,13 +202,7 @@ func main() {
// Update base URL on main page
log.Println("Changing base URL to", *baseURL+"/", "...")
if file, err := os.OpenFile(path.Join(StaticDir, "index.html"), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)); err != nil {
log.Println("Unable to open index.html: ", err)
} else if indexTmpl, err := template.New("index").Parse(indextpl); err != nil {
log.Println("Cannot create template: ", err)
} else if err = indexTmpl.Execute(file, map[string]string{"urlbase": path.Clean(path.Join(*baseURL+"/", "nuke"))[:len(path.Clean(path.Join(*baseURL+"/", "nuke")))-4]}); err != nil {
log.Println("An error occurs during template execution: ", err)
}
genIndex(*baseURL)
// Prepare graceful shutdown
interrupt := make(chan os.Signal, 1)

View file

@ -1,9 +1,13 @@
package main
import (
"bytes"
"embed"
"log"
"net/http"
"path"
"strings"
"text/template"
"srs.epita.fr/fic-server/admin/api"
"srs.epita.fr/fic-server/admin/sync"
@ -12,52 +16,80 @@ import (
"github.com/julienschmidt/httprouter"
)
//go:embed static
var assets embed.FS
var indexPage []byte
func genIndex(baseURL string) {
b := bytes.NewBufferString("")
if indexTmpl, err := template.New("index").Parse(indextpl); err != nil {
log.Fatal("Cannot create template:", err)
} else if err = indexTmpl.Execute(b, map[string]string{"urlbase": path.Clean(path.Join(baseURL+"/", "nuke"))[:len(path.Clean(path.Join(baseURL+"/", "nuke")))-4]}); err != nil {
log.Fatal("An error occurs during template execution:", err)
} else {
indexPage = b.Bytes()
}
}
func serveIndex(w http.ResponseWriter, r *http.Request) {
w.Write(indexPage)
}
var staticFS http.FileSystem
func serveFile(w http.ResponseWriter, r *http.Request, url string) {
r.URL.Path = url
http.FileServer(staticFS).ServeHTTP(w, r)
}
func init() {
api.Router().GET("/", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/claims/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/exercices/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/files", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/public/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/pki/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/settings/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/teams/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/themes/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
serveIndex(w, r)
})
api.Router().GET("/css/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
serveFile(w, r, r.URL.Path)
})
api.Router().GET("/fonts/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
serveFile(w, r, r.URL.Path)
})
api.Router().GET("/img/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
serveFile(w, r, r.URL.Path)
})
api.Router().GET("/js/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
serveFile(w, r, r.URL.Path)
})
api.Router().GET("/views/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
serveFile(w, r, r.URL.Path)
})
api.Router().GET("/files/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
@ -75,9 +107,9 @@ func init() {
})
api.Router().GET("/check_import.html", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "check_import.html"))
serveFile(w, r, "check_import.html")
})
api.Router().GET("/full_import_report.json", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "full_import_report.json"))
http.ServeFile(w, r, sync.DeepReportPath)
})
}

View file

@ -1 +0,0 @@
../../../frontend/static/css/glyphicon.css

View file

@ -0,0 +1,805 @@
@font-face {
font-family: 'Glyphicons Halflings';
src: url('../fonts/glyphicons-halflings-regular.eot');
src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
.glyphicon {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.glyphicon-asterisk:before {
content: "\002a";
}
.glyphicon-plus:before {
content: "\002b";
}
.glyphicon-euro:before,
.glyphicon-eur:before {
content: "\20ac";
}
.glyphicon-minus:before {
content: "\2212";
}
.glyphicon-cloud:before {
content: "\2601";
}
.glyphicon-envelope:before {
content: "\2709";
}
.glyphicon-pencil:before {
content: "\270f";
}
.glyphicon-glass:before {
content: "\e001";
}
.glyphicon-music:before {
content: "\e002";
}
.glyphicon-search:before {
content: "\e003";
}
.glyphicon-heart:before {
content: "\e005";
}
.glyphicon-star:before {
content: "\e006";
}
.glyphicon-star-empty:before {
content: "\e007";
}
.glyphicon-user:before {
content: "\e008";
}
.glyphicon-film:before {
content: "\e009";
}
.glyphicon-th-large:before {
content: "\e010";
}
.glyphicon-th:before {
content: "\e011";
}
.glyphicon-th-list:before {
content: "\e012";
}
.glyphicon-ok:before {
content: "\e013";
}
.glyphicon-remove:before {
content: "\e014";
}
.glyphicon-zoom-in:before {
content: "\e015";
}
.glyphicon-zoom-out:before {
content: "\e016";
}
.glyphicon-off:before {
content: "\e017";
}
.glyphicon-signal:before {
content: "\e018";
}
.glyphicon-cog:before {
content: "\e019";
}
.glyphicon-trash:before {
content: "\e020";
}
.glyphicon-home:before {
content: "\e021";
}
.glyphicon-file:before {
content: "\e022";
}
.glyphicon-time:before {
content: "\e023";
}
.glyphicon-road:before {
content: "\e024";
}
.glyphicon-download-alt:before {
content: "\e025";
}
.glyphicon-download:before {
content: "\e026";
}
.glyphicon-upload:before {
content: "\e027";
}
.glyphicon-inbox:before {
content: "\e028";
}
.glyphicon-play-circle:before {
content: "\e029";
}
.glyphicon-repeat:before {
content: "\e030";
}
.glyphicon-refresh:before {
content: "\e031";
}
.glyphicon-list-alt:before {
content: "\e032";
}
.glyphicon-lock:before {
content: "\e033";
}
.glyphicon-flag:before {
content: "\e034";
}
.glyphicon-headphones:before {
content: "\e035";
}
.glyphicon-volume-off:before {
content: "\e036";
}
.glyphicon-volume-down:before {
content: "\e037";
}
.glyphicon-volume-up:before {
content: "\e038";
}
.glyphicon-qrcode:before {
content: "\e039";
}
.glyphicon-barcode:before {
content: "\e040";
}
.glyphicon-tag:before {
content: "\e041";
}
.glyphicon-tags:before {
content: "\e042";
}
.glyphicon-book:before {
content: "\e043";
}
.glyphicon-bookmark:before {
content: "\e044";
}
.glyphicon-print:before {
content: "\e045";
}
.glyphicon-camera:before {
content: "\e046";
}
.glyphicon-font:before {
content: "\e047";
}
.glyphicon-bold:before {
content: "\e048";
}
.glyphicon-italic:before {
content: "\e049";
}
.glyphicon-text-height:before {
content: "\e050";
}
.glyphicon-text-width:before {
content: "\e051";
}
.glyphicon-align-left:before {
content: "\e052";
}
.glyphicon-align-center:before {
content: "\e053";
}
.glyphicon-align-right:before {
content: "\e054";
}
.glyphicon-align-justify:before {
content: "\e055";
}
.glyphicon-list:before {
content: "\e056";
}
.glyphicon-indent-left:before {
content: "\e057";
}
.glyphicon-indent-right:before {
content: "\e058";
}
.glyphicon-facetime-video:before {
content: "\e059";
}
.glyphicon-picture:before {
content: "\e060";
}
.glyphicon-map-marker:before {
content: "\e062";
}
.glyphicon-adjust:before {
content: "\e063";
}
.glyphicon-tint:before {
content: "\e064";
}
.glyphicon-edit:before {
content: "\e065";
}
.glyphicon-share:before {
content: "\e066";
}
.glyphicon-check:before {
content: "\e067";
}
.glyphicon-move:before {
content: "\e068";
}
.glyphicon-step-backward:before {
content: "\e069";
}
.glyphicon-fast-backward:before {
content: "\e070";
}
.glyphicon-backward:before {
content: "\e071";
}
.glyphicon-play:before {
content: "\e072";
}
.glyphicon-pause:before {
content: "\e073";
}
.glyphicon-stop:before {
content: "\e074";
}
.glyphicon-forward:before {
content: "\e075";
}
.glyphicon-fast-forward:before {
content: "\e076";
}
.glyphicon-step-forward:before {
content: "\e077";
}
.glyphicon-eject:before {
content: "\e078";
}
.glyphicon-chevron-left:before {
content: "\e079";
}
.glyphicon-chevron-right:before {
content: "\e080";
}
.glyphicon-plus-sign:before {
content: "\e081";
}
.glyphicon-minus-sign:before {
content: "\e082";
}
.glyphicon-remove-sign:before {
content: "\e083";
}
.glyphicon-ok-sign:before {
content: "\e084";
}
.glyphicon-question-sign:before {
content: "\e085";
}
.glyphicon-info-sign:before {
content: "\e086";
}
.glyphicon-screenshot:before {
content: "\e087";
}
.glyphicon-remove-circle:before {
content: "\e088";
}
.glyphicon-ok-circle:before {
content: "\e089";
}
.glyphicon-ban-circle:before {
content: "\e090";
}
.glyphicon-arrow-left:before {
content: "\e091";
}
.glyphicon-arrow-right:before {
content: "\e092";
}
.glyphicon-arrow-up:before {
content: "\e093";
}
.glyphicon-arrow-down:before {
content: "\e094";
}
.glyphicon-share-alt:before {
content: "\e095";
}
.glyphicon-resize-full:before {
content: "\e096";
}
.glyphicon-resize-small:before {
content: "\e097";
}
.glyphicon-exclamation-sign:before {
content: "\e101";
}
.glyphicon-gift:before {
content: "\e102";
}
.glyphicon-leaf:before {
content: "\e103";
}
.glyphicon-fire:before {
content: "\e104";
}
.glyphicon-eye-open:before {
content: "\e105";
}
.glyphicon-eye-close:before {
content: "\e106";
}
.glyphicon-warning-sign:before {
content: "\e107";
}
.glyphicon-plane:before {
content: "\e108";
}
.glyphicon-calendar:before {
content: "\e109";
}
.glyphicon-random:before {
content: "\e110";
}
.glyphicon-comment:before {
content: "\e111";
}
.glyphicon-magnet:before {
content: "\e112";
}
.glyphicon-chevron-up:before {
content: "\e113";
}
.glyphicon-chevron-down:before {
content: "\e114";
}
.glyphicon-retweet:before {
content: "\e115";
}
.glyphicon-shopping-cart:before {
content: "\e116";
}
.glyphicon-folder-close:before {
content: "\e117";
}
.glyphicon-folder-open:before {
content: "\e118";
}
.glyphicon-resize-vertical:before {
content: "\e119";
}
.glyphicon-resize-horizontal:before {
content: "\e120";
}
.glyphicon-hdd:before {
content: "\e121";
}
.glyphicon-bullhorn:before {
content: "\e122";
}
.glyphicon-bell:before {
content: "\e123";
}
.glyphicon-certificate:before {
content: "\e124";
}
.glyphicon-thumbs-up:before {
content: "\e125";
}
.glyphicon-thumbs-down:before {
content: "\e126";
}
.glyphicon-hand-right:before {
content: "\e127";
}
.glyphicon-hand-left:before {
content: "\e128";
}
.glyphicon-hand-up:before {
content: "\e129";
}
.glyphicon-hand-down:before {
content: "\e130";
}
.glyphicon-circle-arrow-right:before {
content: "\e131";
}
.glyphicon-circle-arrow-left:before {
content: "\e132";
}
.glyphicon-circle-arrow-up:before {
content: "\e133";
}
.glyphicon-circle-arrow-down:before {
content: "\e134";
}
.glyphicon-globe:before {
content: "\e135";
}
.glyphicon-wrench:before {
content: "\e136";
}
.glyphicon-tasks:before {
content: "\e137";
}
.glyphicon-filter:before {
content: "\e138";
}
.glyphicon-briefcase:before {
content: "\e139";
}
.glyphicon-fullscreen:before {
content: "\e140";
}
.glyphicon-dashboard:before {
content: "\e141";
}
.glyphicon-paperclip:before {
content: "\e142";
}
.glyphicon-heart-empty:before {
content: "\e143";
}
.glyphicon-link:before {
content: "\e144";
}
.glyphicon-phone:before {
content: "\e145";
}
.glyphicon-pushpin:before {
content: "\e146";
}
.glyphicon-usd:before {
content: "\e148";
}
.glyphicon-gbp:before {
content: "\e149";
}
.glyphicon-sort:before {
content: "\e150";
}
.glyphicon-sort-by-alphabet:before {
content: "\e151";
}
.glyphicon-sort-by-alphabet-alt:before {
content: "\e152";
}
.glyphicon-sort-by-order:before {
content: "\e153";
}
.glyphicon-sort-by-order-alt:before {
content: "\e154";
}
.glyphicon-sort-by-attributes:before {
content: "\e155";
}
.glyphicon-sort-by-attributes-alt:before {
content: "\e156";
}
.glyphicon-unchecked:before {
content: "\e157";
}
.glyphicon-expand:before {
content: "\e158";