Added the /api/me/ API endpoint.
Moved a script block into an API endpoint. Split the gigantic switch in ServeHTTP into it's own function. Scripts should load more efficiently now.
This commit is contained in:
parent
18c5223143
commit
a9a1d667c0
|
@ -138,6 +138,9 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//h := w.Header()
|
||||||
|
//h.Set("Content-Security-Policy", "default-src 'self'")
|
||||||
|
|
||||||
// TODO: GDPR. Add a global control panel notice warning the admins of staff members who don't have 2FA enabled
|
// TODO: GDPR. Add a global control panel notice warning the admins of staff members who don't have 2FA enabled
|
||||||
stats.Users = Users.GlobalCount()
|
stats.Users = Users.GlobalCount()
|
||||||
stats.Groups = Groups.GlobalCount()
|
stats.Groups = Groups.GlobalCount()
|
||||||
|
|
|
@ -78,6 +78,39 @@ type WsJSONUser struct {
|
||||||
Liked int
|
Liked int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) Me() *MeUser {
|
||||||
|
var groupID = user.Group
|
||||||
|
if user.TempGroup != 0 {
|
||||||
|
groupID = user.TempGroup
|
||||||
|
}
|
||||||
|
return &MeUser{user.ID, user.Link, user.Name, groupID, user.Active, user.IsMod, user.IsSuperMod, user.IsAdmin, user.IsBanned, user.Session, user.Avatar, user.MicroAvatar, user.Tag, user.Level, user.Score, user.Liked}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For when users need to see their own data, I've omitted some redundancies and less useful items, so we don't wind up sending them on every request
|
||||||
|
type MeUser struct {
|
||||||
|
ID int
|
||||||
|
Link string
|
||||||
|
Name string
|
||||||
|
Group int
|
||||||
|
Active bool
|
||||||
|
IsMod bool
|
||||||
|
IsSuperMod bool
|
||||||
|
IsAdmin bool
|
||||||
|
IsBanned bool
|
||||||
|
|
||||||
|
// TODO: Implement these as copies (might already be the case for Perms, but we'll want to look at it's definition anyway)
|
||||||
|
//Perms Perms
|
||||||
|
//PluginPerms map[string]bool
|
||||||
|
|
||||||
|
Session string
|
||||||
|
Avatar string
|
||||||
|
MicroAvatar string
|
||||||
|
Tag string
|
||||||
|
Level int
|
||||||
|
Score int
|
||||||
|
Liked int
|
||||||
|
}
|
||||||
|
|
||||||
type UserStmts struct {
|
type UserStmts struct {
|
||||||
activate *sql.Stmt
|
activate *sql.Stmt
|
||||||
changeGroup *sql.Stmt
|
changeGroup *sql.Stmt
|
||||||
|
|
712
gen_router.go
712
gen_router.go
File diff suppressed because it is too large
Load Diff
|
@ -7,6 +7,7 @@ var alertList = [];
|
||||||
var alertCount = 0;
|
var alertCount = 0;
|
||||||
var moreTopicCount = 0;
|
var moreTopicCount = 0;
|
||||||
var conn;
|
var conn;
|
||||||
|
var me = {};
|
||||||
var selectedTopics = [];
|
var selectedTopics = [];
|
||||||
var attachItemCallback = function(){}
|
var attachItemCallback = function(){}
|
||||||
var hooks = {
|
var hooks = {
|
||||||
|
@ -196,7 +197,7 @@ function runWebSockets() {
|
||||||
console.log("The WebSockets connection was opened");
|
console.log("The WebSockets connection was opened");
|
||||||
conn.send("page " + document.location.pathname + '\r');
|
conn.send("page " + document.location.pathname + '\r');
|
||||||
// TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on
|
// TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on
|
||||||
if(loggedIn) {
|
if(me.User.ID > 0) {
|
||||||
Notification.requestPermission();
|
Notification.requestPermission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,14 +259,11 @@ function runWebSockets() {
|
||||||
for(var i = 0; i < messages.length; i++) {
|
for(var i = 0; i < messages.length; i++) {
|
||||||
let message = messages[i];
|
let message = messages[i];
|
||||||
//console.log("Message: ",message);
|
//console.log("Message: ",message);
|
||||||
|
let msgblocks = SplitN(message," ",3);
|
||||||
|
if(msgblocks.length < 3) continue;
|
||||||
if(message.startsWith("set ")) {
|
if(message.startsWith("set ")) {
|
||||||
//msgblocks = message.split(' ',3);
|
|
||||||
let msgblocks = SplitN(message," ",3);
|
|
||||||
if(msgblocks.length < 3) continue;
|
|
||||||
document.querySelector(msgblocks[1]).innerHTML = msgblocks[2];
|
document.querySelector(msgblocks[1]).innerHTML = msgblocks[2];
|
||||||
} else if(message.startsWith("set-class ")) {
|
} else if(message.startsWith("set-class ")) {
|
||||||
let msgblocks = SplitN(message," ",3);
|
|
||||||
if(msgblocks.length < 3) continue;
|
|
||||||
document.querySelector(msgblocks[1]).className = msgblocks[2];
|
document.querySelector(msgblocks[1]).className = msgblocks[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,7 +276,7 @@ function len(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadScript(name, callback) {
|
function loadScript(name, callback) {
|
||||||
let url = "//" +siteURL+"/static/"+name
|
let url = "//" +me.Site.URL+"/static/"+name
|
||||||
$.getScript(url)
|
$.getScript(url)
|
||||||
.done(callback)
|
.done(callback)
|
||||||
.fail((e,xhr,settings,ex) => {
|
.fail((e,xhr,settings,ex) => {
|
||||||
|
@ -296,7 +294,7 @@ function DoNothingButPassBack(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchPhrases() {
|
function fetchPhrases() {
|
||||||
fetch("//" +siteURL+"/api/phrases/?query=status,topic_list")
|
fetch("//" +me.Site.URL+"/api/phrases/?query=status,topic_list")
|
||||||
.then((resp) => resp.json())
|
.then((resp) => resp.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log("loaded phrase endpoint data");
|
console.log("loaded phrase endpoint data");
|
||||||
|
@ -328,29 +326,44 @@ function fetchPhrases() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
(() => {
|
||||||
runHook("start_init");
|
runHook("pre_me");
|
||||||
if(loggedIn) {
|
fetch("/api/me/")
|
||||||
let toLoad = 1;
|
.then((resp) => resp.json())
|
||||||
loadScript("template_topics_topic.js", () => {
|
.then((data) => {
|
||||||
console.log("Loaded template_topics_topic.js");
|
console.log("loaded me endpoint data");
|
||||||
toLoad--;
|
console.log("data:",data);
|
||||||
if(toLoad===0) fetchPhrases();
|
me = data;
|
||||||
|
runHook("pre_init");
|
||||||
|
|
||||||
|
if(me.User.ID > 0) {
|
||||||
|
let toLoad = 1;
|
||||||
|
loadScript("template_topics_topic.js", () => {
|
||||||
|
console.log("Loaded template_topics_topic.js");
|
||||||
|
toLoad--;
|
||||||
|
if(toLoad===0) fetchPhrases();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can only get away with this because template_alert has no phrases, otherwise it too would have to be part of the "dance", I miss Go concurrency :(
|
||||||
|
loadScript("template_alert.js", () => {
|
||||||
|
console.log("Loaded template_alert.js");
|
||||||
|
alertsInitted = true;
|
||||||
|
var alertMenuList = document.getElementsByClassName("menu_alerts");
|
||||||
|
for(var i = 0; i < alertMenuList.length; i++) {
|
||||||
|
loadAlerts(alertMenuList[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(window["WebSocket"]) runWebSockets();
|
||||||
|
else conn = false;
|
||||||
|
|
||||||
|
$(document).ready(mainInit);
|
||||||
});
|
});
|
||||||
}
|
})();
|
||||||
|
|
||||||
// We can only get away with this because template_alert has no phrases, otherwise it too would have to be part of the "dance", I miss Go concurrency :(
|
function mainInit(){
|
||||||
loadScript("template_alert.js", () => {
|
runHook("start_init");
|
||||||
console.log("Loaded template_alert.js");
|
|
||||||
alertsInitted = true;
|
|
||||||
var alertMenuList = document.getElementsByClassName("menu_alerts");
|
|
||||||
for(var i = 0; i < alertMenuList.length; i++) {
|
|
||||||
loadAlerts(alertMenuList[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(window["WebSocket"]) runWebSockets();
|
|
||||||
else conn = false;
|
|
||||||
|
|
||||||
$(".more_topics").click((event) => {
|
$(".more_topics").click((event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -484,7 +497,7 @@ $(document).ready(function(){
|
||||||
let formAction = $(this).closest('a').attr("href");
|
let formAction = $(this).closest('a').attr("href");
|
||||||
//console.log("Form Action:", formAction);
|
//console.log("Form Action:", formAction);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: formAction + "?session=" + session,
|
url: formAction + "?session=" + me.User.Session,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
error: ajaxError,
|
error: ajaxError,
|
||||||
|
@ -559,7 +572,7 @@ $(document).ready(function(){
|
||||||
var formAction = $(this).closest('a').attr("href");
|
var formAction = $(this).closest('a').attr("href");
|
||||||
//console.log("Form Action:", formAction);
|
//console.log("Form Action:", formAction);
|
||||||
//console.log(outData);
|
//console.log(outData);
|
||||||
$.ajax({ url: formAction + "?session=" + session, type:"POST", dataType:"json", data: outData, error: ajaxError });
|
$.ajax({ url: formAction + "?session=" + me.User.Session, type:"POST", dataType:"json", data: outData, error: ajaxError });
|
||||||
blockParent.find('.hide_on_edit').show();
|
blockParent.find('.hide_on_edit').show();
|
||||||
blockParent.find('.show_on_edit').hide();
|
blockParent.find('.show_on_edit').hide();
|
||||||
});
|
});
|
||||||
|
@ -654,8 +667,8 @@ $(document).ready(function(){
|
||||||
console.log("content.value", content.value);
|
console.log("content.value", content.value);
|
||||||
|
|
||||||
let attachItem;
|
let attachItem;
|
||||||
if(content.value == "") attachItem = "//" + siteURL + "/attachs/" + hash + "." + ext;
|
if(content.value == "") attachItem = "//" + me.Site.URL + "/attachs/" + hash + "." + ext;
|
||||||
else attachItem = "\r\n//" + siteURL + "/attachs/" + hash + "." + ext;
|
else attachItem = "\r\n//" + me.Site.URL + "/attachs/" + hash + "." + ext;
|
||||||
content.value = content.value + attachItem;
|
content.value = content.value + attachItem;
|
||||||
console.log("content.value", content.value);
|
console.log("content.value", content.value);
|
||||||
|
|
||||||
|
@ -667,9 +680,9 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
reader.readAsDataURL(files[i]);
|
reader.readAsDataURL(files[i]);
|
||||||
}
|
}
|
||||||
if(totalSize>maxRequestSize) {
|
if(totalSize > me.Site.MaxRequestSize) {
|
||||||
// TODO: Use a notice instead
|
// TODO: Use a notice instead
|
||||||
alert("You can't upload this much data at once, max: " + maxRequestSize);
|
alert("You can't upload this much data at once, max: " + me.Site.MaxRequestSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,7 +709,7 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
let bulkActionSender = function(action, selectedTopics, fragBit) {
|
let bulkActionSender = function(action, selectedTopics, fragBit) {
|
||||||
let url = "/topic/"+action+"/submit/"+fragBit+"?session=" + session;
|
let url = "/topic/"+action+"/submit/"+fragBit+"?session=" + me.User.Session;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
@ -746,7 +759,7 @@ $(document).ready(function(){
|
||||||
$("#themeSelectorSelect").change(function(){
|
$("#themeSelectorSelect").change(function(){
|
||||||
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
|
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: this.form.getAttribute("action") + "?session=" + session,
|
url: this.form.getAttribute("action") + "?session=" + me.User.Session,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: { "newTheme": this.options[this.selectedIndex].getAttribute("val"), isJs: "1" },
|
data: { "newTheme": this.options[this.selectedIndex].getAttribute("val"), isJs: "1" },
|
||||||
|
@ -825,4 +838,4 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
runHook("end_init");
|
runHook("end_init");
|
||||||
});
|
};
|
||||||
|
|
|
@ -645,6 +645,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
"routeMapEnum: ", routeMapEnum)
|
"routeMapEnum: ", routeMapEnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.routeSwitch(w, req, user, prefix, extraData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) {
|
||||||
var err common.RouteError
|
var err common.RouteError
|
||||||
switch(prefix) {` + out + `
|
switch(prefix) {` + out + `
|
||||||
/*case "/sitemaps": // TODO: Count these views
|
/*case "/sitemaps": // TODO: Count these views
|
||||||
|
|
|
@ -14,6 +14,7 @@ func routes() {
|
||||||
apiGroup := newRouteGroup("/api/",
|
apiGroup := newRouteGroup("/api/",
|
||||||
View("routeAPI", "/api/"),
|
View("routeAPI", "/api/"),
|
||||||
View("routeAPIPhrases", "/api/phrases/"), // TODO: Be careful with exposing the panel phrases here
|
View("routeAPIPhrases", "/api/phrases/"), // TODO: Be careful with exposing the panel phrases here
|
||||||
|
View("routes.APIMe", "/api/me/"),
|
||||||
View("routeJSAntispam", "/api/watches/"),
|
View("routeJSAntispam", "/api/watches/"),
|
||||||
)
|
)
|
||||||
addRouteGroup(apiGroup)
|
addRouteGroup(apiGroup)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -220,3 +221,35 @@ func SitemapUsers(w http.ResponseWriter, r *http.Request) common.RouteError {
|
||||||
w.Write([]byte("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n"))
|
w.Write([]byte("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JsonMe struct {
|
||||||
|
User *common.MeUser
|
||||||
|
Site MeSite
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want to expose too much information about the site, so we'll make this a small subset of common.site
|
||||||
|
type MeSite struct {
|
||||||
|
URL string
|
||||||
|
MaxRequestSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIMe returns information about the current logged-in user
|
||||||
|
// TODO: Find some way to stop intermediaries from doing compression to avoid the BREACH attack
|
||||||
|
// TODO: Decouple site settings into a different API? I'd like to avoid having too many requests, if possible, maybe we can use a different name for this?
|
||||||
|
func APIMe(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
// TODO: Don't make this too JSON dependent so that we can swap in newer more efficient formats
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
// We don't want an intermediary accidentally caching this
|
||||||
|
// TODO: Use this header anywhere with a user check?
|
||||||
|
w.Header().Set("Cache-Control", "private")
|
||||||
|
|
||||||
|
me := JsonMe{(&user).Me(), MeSite{common.Site.URL, common.Site.MaxRequestSize}}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(me)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJS(err, w, r)
|
||||||
|
}
|
||||||
|
w.Write(jsonBytes)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -11,12 +11,6 @@
|
||||||
{{range .Header.Scripts}}
|
{{range .Header.Scripts}}
|
||||||
<script type="text/javascript" src="/static/{{.}}"></script>
|
<script type="text/javascript" src="/static/{{.}}"></script>
|
||||||
{{end}}
|
{{end}}
|
||||||
<script type="text/javascript">
|
|
||||||
var session = "{{.CurrentUser.Session}}";
|
|
||||||
var loggedIn = {{.CurrentUser.Loggedin}};
|
|
||||||
var siteURL = "{{.Header.Site.URL}}";
|
|
||||||
var maxRequestSize = "{{.Header.Site.MaxRequestSize}}";
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript" src="/static/global.js"></script>
|
<script type="text/javascript" src="/static/global.js"></script>
|
||||||
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
|
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
|
||||||
{{if .Header.MetaDesc}}<meta name="description" content="{{.Header.MetaDesc}}" />{{end}}
|
{{if .Header.MetaDesc}}<meta name="description" content="{{.Header.MetaDesc}}" />{{end}}
|
||||||
|
|
Loading…
Reference in New Issue