add mark_posted

master
Joshua Herring 3 weeks ago
parent 20ff37ec43
commit 0fe34ddb61

@ -132,6 +132,8 @@ func HandleAPI(w http.ResponseWriter, r *http.Request) {
switch req.Method { switch req.Method {
case "report_activity": case "report_activity":
ReportActivity(w, conn, req, user) ReportActivity(w, conn, req, user)
case "mark_posted":
MarkPosted(w, conn, req, user)
default: default:
jsonRPCErr(w, -32601, "Method not found", req.ID) jsonRPCErr(w, -32601, "Method not found", req.ID)
} }

@ -0,0 +1,41 @@
package api
import (
"database/sql"
"encoding/json"
"net/http"
"faculty_media_report/dbi"
)
type markPostedParams struct {
UID string `json:"uid"`
}
func MarkPosted(w http.ResponseWriter, conn *sql.Conn, req jsonRPCRequest, user dbi.User) {
if user.Status != "admin" {
jsonRPCErr(w, -32000, "Forbidden", req.ID)
return
}
var params markPostedParams
if err := json.Unmarshal(req.Params, &params); err != nil {
jsonRPCErr(w, -32602, "Invalid params", req.ID)
return
}
if params.UID == "" {
jsonRPCErr(w, -32602, "Invalid params: uid is required", req.ID)
return
}
if err := dbi.MarkPosted(conn, params.UID); err != nil {
jsonRPCErr(w, -32603, "Internal error", req.ID)
return
}
writeJSONRPC(w, jsonRPCResponse{
Jsonrpc: "2.0",
Result: true,
ID: req.ID,
})
}

@ -61,12 +61,17 @@ func handleLoginPost(w http.ResponseWriter, r *http.Request) {
} }
if user.Status == "admin" { if user.Status == "admin" {
token, err := dbi.GenJWT(user)
if err != nil {
fail()
return
}
items, err := dbi.GetReportedItems(conn) items, err := dbi.GetReportedItems(conn)
if err != nil { if err != nil {
fail() fail()
return return
} }
html, err := pages.DashboardPage(items) html, err := pages.DashboardPage(token, items)
if err != nil { if err != nil {
fail() fail()
return return

@ -7,6 +7,11 @@ import (
"faculty_media_report/dbi" "faculty_media_report/dbi"
) )
type dashboardData struct {
JWT string
Items []dbi.DashboardItem
}
var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE html> var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -14,6 +19,7 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Maurer School of Law</title> <title>Dashboard Maurer School of Law</title>
<link rel="stylesheet" href="https://unpkg.com/rivet-core@2/css/rivet.min.css"> <link rel="stylesheet" href="https://unpkg.com/rivet-core@2/css/rivet.min.css">
<script>var JWT = "{{.JWT}}";</script>
</head> </head>
<body> <body>
<header class="rvt-header-wrapper"> <header class="rvt-header-wrapper">
@ -41,7 +47,7 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
<main id="main-content" class="rvt-container-xl rvt-p-top-xxl rvt-p-bottom-xxl"> <main id="main-content" class="rvt-container-xl rvt-p-top-xxl rvt-p-bottom-xxl">
<h1 class="rvt-ts-xxl rvt-m-bottom-xxl">Activity Report Dashboard</h1> <h1 class="rvt-ts-xxl rvt-m-bottom-xxl">Activity Report Dashboard</h1>
{{if .}} {{if .Items}}
<div class="rvt-m-bottom-lg"> <div class="rvt-m-bottom-lg">
<button class="rvt-button rvt-button--secondary" type="button" id="download-csv">Download CSV Report</button> <button class="rvt-button rvt-button--secondary" type="button" id="download-csv">Download CSV Report</button>
</div> </div>
@ -59,17 +65,19 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
<th scope="col">Description</th> <th scope="col">Description</th>
<th scope="col">Hyperlink</th> <th scope="col">Hyperlink</th>
<th scope="col" data-col="5" style="cursor:pointer;white-space:nowrap;">Type <span class="sort-ind">&#8597;</span></th> <th scope="col" data-col="5" style="cursor:pointer;white-space:nowrap;">Type <span class="sort-ind">&#8597;</span></th>
<th scope="col"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{range .}} {{range .Items}}
<tr> <tr data-uid="{{.UID}}">
<td>{{.Created}}</td> <td>{{.Created}}</td>
<td>{{.LastName}}, {{.FirstName}}</td> <td>{{.LastName}}, {{.FirstName}}</td>
<td>{{.Title}}</td> <td>{{.Title}}</td>
<td>{{.Description}}</td> <td>{{.Description}}</td>
<td>{{if .Hyperlink}}<a href="{{.Hyperlink}}" target="_blank" rel="noopener">Link</a>{{end}}</td> <td>{{if .Hyperlink}}<a href="{{.Hyperlink}}" target="_blank" rel="noopener">Link</a>{{end}}</td>
<td>{{.ItemType}}</td> <td>{{.ItemType}}</td>
<td><button type="button" class="mark-posted-btn" aria-label="Mark as posted" style="background:none;border:none;cursor:pointer;color:#006633;padding:0;"><rvt-icon name="check"></rvt-icon></button></td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>
@ -79,6 +87,7 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
<p class="rvt-ts-lg">No reported items.</p> <p class="rvt-ts-lg">No reported items.</p>
{{end}} {{end}}
</main> </main>
<script type="module" src="https://unpkg.com/rivet-icons@3/dist/rivet-icons.js"></script>
<script> <script>
(function() { (function() {
var table = document.getElementById('report-table'); var table = document.getElementById('report-table');
@ -124,6 +133,31 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
apply(); apply();
}); });
}); });
table.addEventListener('click', function(e) {
var btn = e.target.closest('.mark-posted-btn');
if (!btn) return;
var row = btn.closest('tr');
var uid = row ? row.getAttribute('data-uid') : null;
if (!uid) return;
btn.disabled = true;
fetch('/faculty/activity/api', {
method: 'POST',
headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + JWT},
body: JSON.stringify({jsonrpc: '2.0', method: 'mark_posted', params: {uid: uid}, id: 1})
})
.then(function(resp) { return resp.json(); })
.then(function(data) {
if (data.error) {
btn.disabled = false;
return;
}
allRows = allRows.filter(function(r) { return r !== row; });
row.remove();
})
.catch(function() { btn.disabled = false; });
});
} }
var dlBtn = document.getElementById('download-csv'); var dlBtn = document.getElementById('download-csv');
@ -150,7 +184,7 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
if (i === 4) { if (i === 4) {
var a = cell.querySelector('a'); var a = cell.querySelector('a');
fields.push(esc(a ? a.href : '')); fields.push(esc(a ? a.href : ''));
} else { } else if (i < 6) {
fields.push(esc(cell.textContent.trim())); fields.push(esc(cell.textContent.trim()));
} }
}); });
@ -174,9 +208,9 @@ var dashboardTmpl = template.Must(template.New("dashboard").Parse(`<!DOCTYPE htm
</body> </body>
</html>`)) </html>`))
func DashboardPage(items []dbi.DashboardItem) (string, error) { func DashboardPage(jwtToken string, items []dbi.DashboardItem) (string, error) {
var buf bytes.Buffer var buf bytes.Buffer
if err := dashboardTmpl.Execute(&buf, items); err != nil { if err := dashboardTmpl.Execute(&buf, dashboardData{JWT: jwtToken, Items: items}); err != nil {
return "", err return "", err
} }
return buf.String(), nil return buf.String(), nil

Loading…
Cancel
Save