hlfw.ca

webbing

Download patch

ref: edae5b94cd40ecf25d9d9104985110cb665a55b8
parent: 5ed44f3b7def5c6870ec1f1d55d0aa63de0301c4
author: Moses Olson, MD <52055478+nemo-olmax@users.noreply.github.com>
date: Mon Aug 12 06:47:44 PDT 2019

Add files via upload

--- /dev/null
+++ b/design/creatingpages
@@ -1,0 +1,107 @@
+Starting from html, a page is translated into a template. A template is the html with the header/footer removed. Example:
+
+```
+<div class="content">
+	<main>
+		<section>
+			<h1>Something</h1>
+			<p>Content</p>
+		</section>
+	</main>
+	<aside>
+		<h2>Something else</h2>
+		<p>Content</p>
+	</aside>
+</div>
+```
+
+Then, each `string` is taken out so that it can be ran through the internationalization stuff
+
+```
+<div class="content">
+	<main>
+		<section>
+			<h1>{{.mainHeader}}</h1>
+			<p>{{.mainContent}}</p>
+		</section>
+	</main>
+	<aside>
+		<h2>{{.otherHeader}}</h2>
+		<p>{{.otherContent}}</p>
+	</aside>
+</div>
+```
+
+The {{.foo}} corresponds to the contents of pages/path/to/this/page.go. A map[string]interface{} is used, with an entry for each key above, and the value.
+
+```
+import (
+	"golang.org/x/text/message"
+)
+
+func Mypage(p *message.Printer) map[string]interface{} {
+	return map[string]interface{} {
+		"mainHeader": p.Sprint("Something"),
+		"mainContent": p.Sprint("Content"),
+		"otherHeader": p.Sprint(Something else"),
+		"otherContent: p.Sprint("Content"),
+	}
+}
+```
+
+Now, the program when it starts up will run the init() function ofanything imported. In client.go, you would import the library that this page you've made belongs to as an empty import - this basically means it'll always run the init(). We use this to our advantage
+
+```
+func init() {
+	b := &router.Page{
+		// Who can access the page
+		Access: router.GuestAuth|router.PatientAuth, // or router.DoctorAuth
+		// There's a basic CSS for every given page that is already applied
+		// we use this if we want special css for this page
+		Css: "customstuffforonlythispage.css",
+		// would relate to, for example, olmaxmedical.com/path/to/this/page.html
+		Path: path/to/this/page 
+		Data: Mypage, // pointer to function we defined above
+		// These load your interface{} item above so you can access the lists
+		// This keeps the API boundaries clean, and more importantly drastically
+		// simplifies writing more pages
+		Extra: router.ListCountries|router.ListDoctors|router.ListSpecialties, 
+}
+```
+
+An example using one of the above extras would be like so
+
+```
+<div class="content">
+	<main>
+		<section>
+			<h1>Something</h1>
+			<p>Content</p>
+		</section>
+	</main>
+	<aside>
+		<form action="dosomething">
+			<select name="Specialties">
+			{{range .specialties}} <!-- this is from ListSpecialties-->
+				<option value="{{.ID}}">{{.Name}}</option>
+			{{end}}
+			</select>
+		</form>
+		<h2>Something else</h2>
+		<p>Content</p>
+	</aside>
+</div>
+```
+
+The structs for all of these are listed in their source files in router/, as they're only ever loaded and used there.
+
+So each page is basically `cached` at startup, and calling them has only the overhead of translation, which is very quick map lookups based on a numerical identifier.
+There's no further steps required; just make the two files, possibly the extra CSS, and if you are creating a new library (that is to say, a path in olmaxmedical.com/some/new/area.html) make sure it gets added in client.go
+
+```
+import (
+	...
+	_ "olmax/some/new"
+	...
+)
+```
--- /dev/null
+++ b/design/routing
@@ -1,0 +1,28 @@
+For now the router is a simple hand-made. It sends a majority of pages that aren't related to a client session via a default method: 
+
+```
+func (d *handle) normal(w http.ResponseWriter, r *http.Request) {
+	// Get the language for a given client request
+	accept := r.Header.Get("Accept-Language")
+	[...]
+	p := message.NewPrinter(tag)
+	// Get the session based on tokens
+	// If none exist, start a new one
+	us := d.manager.SessionStart(w, r)
+	[...]
+	// Check the auth for a given site, or return a 503 error
+	// Additionally, we get the data based on that identity for things like the header's links
+	// for example for someone authorized as a patient
+	// This pagedata calls the functions in pages/path/to/my/page
+	// Then adds all additional data to the map so a template can be fully Executed
+	// Then it returns a []byte with the actual HTML served to the client
+	data, _ := pagedata(p, requsted_path, loginstatus, "patient")
+	// Write the actual data to w
+	fmt.Fprintf(w, "%s", data)
+}
+```
+
+ * actual code is slightly different
+
+At the present time, generic form parsing is not implemented, but the pathway will be roughly similar; a switch on r.Method will be used (one of GET, POST, etc etc) and a similarily generic function to the above will be used to get form data, pass it through a validator that lives in forms/path/to/my/page
+Which returns an array of any validation errors.
--- /dev/null
+++ b/design/sessions
@@ -1,0 +1,4 @@
+The session management is pulled right out of astaxie's web design book.
+A client connects to the site, and is issued a token. The token is tied into session cookies, and is used to validate login status, tying the token to a username. The username itself is then queried against the database for any additional information
+
+There's not much that happens here as of yet, but eventually the design will generate tokens for each page the user visits, and generate tokens that are seperate and linked to a form on a given page. This allows us to do two things: Stop multiple form submissions, which can happen just from slow internet or user confusion, as well as remove the chance for nefarious people to hijack a client access cookie to do anything that would cause damage to the client
\ No newline at end of file
--- /dev/null
+++ b/design/startup
@@ -1,0 +1,8 @@
+the program starts up, caching all templates as structs with the function to call for page data, the various flags for additional data they want from the generic page handler, and the access flags
+
+Then, the program runs through every template and makes sure that they execute, at least using the English translations (the default ones) it'll error out and print every template error it encounters on stdout
+
+Then it spins up the (currently broken, so disabled) garbage collection. This garbage collection removes old session data, like tokens that have expired, rather than spinning up goroutines waiting to time out the token.
+We may revisit this, since a token, once used, is considered expired (and can be deleted) so it won't need garbage collection.
+
+Finally we start listening for incoming connections, using the router. It's handed a structure to use for accessing all the required session data through method calls, which keeps the sessions out of global scope
\ No newline at end of file