Compare commits

...

7 Commits

Author SHA1 Message Date
nemunaire eb6427ec6c Add anchor on table lines 2021-09-24 09:55:14 +02:00
nemunaire bf556753b3 Rework ui to try to fit into screen 2021-09-24 09:54:55 +02:00
nemunaire e486ad0c1b Can pass multiple students files (concatenate them) 2021-09-24 09:54:25 +02:00
nemunaire e9cc2e1331 Add go.mod 2021-09-24 09:45:11 +02:00
nemunaire 364124db35 Add a page for each student 2019-11-03 00:35:27 +01:00
nemunaire b2d2cd860c Update to latest bootstrap 3 2019-11-02 16:31:13 +01:00
nemunaire 0a8e352622 go format 2019-11-02 16:30:41 +01:00
2 changed files with 82 additions and 20 deletions

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.nemunai.re/shemu
go 1.10

99
main.go
View File

@ -30,9 +30,10 @@ func Serve(w http.ResponseWriter, r *http.Request) {
<head>
<title>` + title + `</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<style>.table > tbody > tr > th, .table > tbody > tr > td { vertical-align: middle; }
td.danger { text-align: center; }
.hash { max-width: 150px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; display: inline-block; }
</style>
<script type="text/javascript">
function disp(rendus) {
@ -42,6 +43,7 @@ function disp(rendus) {
var row = document.createElement("tr");
var col = document.createElement("th");
col.id = login;
col.innerHTML = login;
row.appendChild(col);
@ -50,7 +52,7 @@ function disp(rendus) {
if (work) {
var col = document.createElement("td");
col.className = "success";
col.innerHTML = work["date"] + "<br>" + work["hash"];
col.innerHTML = (new Intl.DateTimeFormat('default', { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' }).format(new Date(work["date"]))) + '<br><span class="hash" title="' + work["hash"] + '">' + work["hash"] + '</span>';
row.appendChild(col);
} else {
var col = document.createElement("td");
@ -68,6 +70,35 @@ function disp(rendus) {
document.getElementById("head").appendChild(col);
});
}
function disp_std(rendus, login) {
Object.keys(rendus).map(function(label) {
var work = rendus[label];
var row = document.createElement("tr");
var col = document.createElement("th");
col.innerHTML = label;
row.appendChild(col);
if (work) {
var col = document.createElement("td");
col.className = "success";
col.innerHTML = (new Intl.DateTimeFormat('default', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' }).format(new Date(work["date"]))) + '<br>' + work["hash"];
row.appendChild(col);
} else {
var col = document.createElement("td");
col.className = "danger";
col.innerHTML = "<span class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></span>";
row.appendChild(col);
}
document.getElementById("students").appendChild(row);
});
var col = document.createElement("th");
col.innerHTML = login;
document.getElementById("head").appendChild(col);
}
</script>
</head>
<body class="container">
@ -80,13 +111,23 @@ function disp(rendus) {
</tbody>
</table>
<script type="text/javascript">
fetch('rendus.json') // You can also fetch login_x.json
.then(function(response) {
return response.json();
})
.then(function(submissions) {
disp(submissions);
});
if (window.location.pathname[window.location.pathname.length - 1] != "/")
fetch(window.location.pathname.replace(".html", "") + ".json")
.then(function(response) {
return response.json();
})
.then(function(submissions) {
var spl = window.location.pathname.split("/")
disp_std(submissions, spl[spl.length - 1]);
});
else
fetch('rendus.json') // You can also fetch login_x.json
.then(function(response) {
return response.json();
})
.then(function(submissions) {
disp(submissions);
});
</script>
</body>
</html>
@ -136,7 +177,7 @@ func genStudent(login string) map[string]*Submission {
ret[dir.Name()] = new(Submission)
ret[dir.Name()].Date = fi.ModTime()
if lnk, err := os.Readlink(p); err == nil {
ret[dir.Name()].Hash = strings.TrimPrefix(lnk, login + ".")
ret[dir.Name()].Hash = strings.TrimPrefix(lnk, login+".")
}
} else {
ret[dir.Name()] = nil
@ -166,11 +207,22 @@ func ServeJSONStudent(w http.ResponseWriter, r *http.Request) {
}
}
type arrayFlags []string
func (i *arrayFlags) String() string {
return fmt.Sprintf("%v", *i)
}
func (i *arrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
func main() {
var studentsFile string
var studentsFiles arrayFlags
var bind = flag.String("bind", "0.0.0.0:8081", "Bind port/socket")
flag.StringVar(&studentsFile, "students", "./students.csv", "Path to a CSV file containing in the third column the name of the directory to look for")
flag.Var(&studentsFiles, "students", "Path to a CSV file containing in the third column the name of the directory to look for (can be repeated multiple times)")
flag.StringVar(&rendusDir, "path", "./rendu/", "Path to the submissions directory (each subdirectory is a project)")
flag.StringVar(&title, "title", "Rendus VIRLI", "Title of the page")
flag.Parse()
@ -195,14 +247,21 @@ func main() {
// Read and parse students list
log.Println("Reading students files...")
if studentsFile, err = filepath.Abs(studentsFile); err != nil {
log.Fatal(err)
} else if fi, err := os.Open(studentsFile); err != nil {
log.Fatal(err)
} else {
r := csv.NewReader(bufio.NewReader(fi))
if students, err = r.ReadAll(); err != nil {
for _, studentsFile := range studentsFiles {
log.Println("Reading", studentsFile, "...")
if studentsFile, err = filepath.Abs(studentsFile); err != nil {
log.Fatal(err)
} else if fi, err := os.Open(studentsFile); err != nil {
log.Fatal(err)
} else {
var nstudents [][]string
r := csv.NewReader(bufio.NewReader(fi))
if nstudents, err = r.ReadAll(); err != nil {
log.Fatal(err)
}
students = append(students, nstudents...)
}
}
log.Println(len(students), "students loaded.")
@ -211,7 +270,7 @@ func main() {
http.HandleFunc("/", Serve)
http.HandleFunc("/rendus.json", ServeJSON)
for _, student := range students {
http.HandleFunc("/" + student[2] + ".json", ServeJSONStudent)
http.HandleFunc("/"+student[2]+".json", ServeJSONStudent)
}
log.Println(fmt.Sprintf("Ready, listening on %s", *bind))
if err := http.ListenAndServe(*bind, nil); err != nil {