Development post-it notes. #
Things/Snippets of code I should not forget.
Made as a quick cheatsheet for me and contributors to check if they're in doubt.
Using context to retrieve important values. #
Certain middlewares will store a couple of values on the context to make your developer life easier. Here's a couple examples:
user, ok := r.Context().Value(lib.UserKey).(*types.User)
session, ok := r.Context().Value(lib.SessionKey).(string)
loggedIn, ok := r.Context().Value(lib.LoggedInKey).(bool) // this should be fine to be used anywhere.
repo, ok := r.Context().Value(md.RepoKey).(types.Repo) // provided by the repo middleware
IMPORTANT AND TODO: use val, ok := ctx.Value(key).(Type); if !ok { ... } to check if the value is set.
Form validation. #
Use the md.ValidateForm such as
type LoginForm struct {
Email string `form:"email" validate:"required,email"`
Password string `form:"password" validate:"required,min=8"`
}
md.ValidateForm[LoginForm](http.HandlerFunc(a.login)) // Use handle, not handleFunc.
and retrieve the form using
form, ok := md.Form[LoginForm](r) // r being the request
Bear in mind forms have that special property because of contextKey.
Forms are CSRF-protected. {{ .csrfField }} must be added inside each form.
Mux routing. #
I use gorilla/mux as a router:
- Use a blank space
""for indexes. - Use
{path:.+}for those recursive paths. - Define all routers in app.go since it's be easier to manage.
Rendering templates. #
Use the following code:
a.Render(w, r, "base", "repo/view", map[string]any{"Repo": repo})
Where a is your *App, base the layout, repo/view is the template, and map[string]any{"Repo": repo} is the data, accessible as .Repo
Use {{.sshDomain}} and {{.sshPort}} to get the domain and port the SSH server will be listening at.
Useful variables:
{{.loggedIn}} // bool, is user logged in? self-explanatory.
{{.user}} // types.User (if loggedIn is true)
{{.sshDomain}} // domain of the SSH server.
{{.sshPort}} // port which the SSH server is listening from.
When you need to access the root "." while (e.g) ranging, use "$" to access it. Example:
{{range .Files}}
{{$.DirectoryName}}/{{.Name}}
{{end}}
Template rendering utils. #
I made a couple utils to be used on the templates.
For instance:
{{if IsText .Blob.Type}}
<pre><code>{{.Blob.Content}}</code></pre>
{{else if IsImage .Blob.Mime}}
<img src="{{Src .Blob.Content .Blob.Mime}}">
{{end}}
ALWAYS USE {{RepoRoot .Meta}} instead of "/~(user)/(repo-name)/". It's easier to change later.
It has a leading slash and no trailing slash.
{{RepoRoot .DBRepo}} -> "/~poyo/banana"
{{TruncateStr "hello world" 5}} // -> "hello"
{{Mime .Blob}} // -> "image/png"
You can check the full list at the templating function itself.
Time. #
When rendering a date, pass in a UTC date into any element with a class local-time, and time.js will convert it to the user's local time.
Example:
<time class="local-time" datetime="{{.CreatedAt}}">{{.CreatedAt}}</time>
CSS Styling: #
.inline for inlined and gapped containers.
Message and Error displaying. #
?msg=AuthSuccess and ?err=RequireAuth are examples of query params that will show a banner on the page.
Keep in mind, validation errors are Base64 encoded (urlencoded) and are passed as ?err=ValidationErr-(base64). The messages and validation middleware handle it, so don't worry about it much.
CSS for errors and messages is on the main stylesheet (styles.css).
.message, .warning and .error have a slight vertical margin. If you use the same class names as HTML attributes, they will have no margin.
Lib/Submodules. #
Please, separate stuff into lib submodules to avoid circular imports.
I had to suffer an hour of debugging because I implemented git handling on a db function. I scrapped everything and rewrote it separately, and it worked. That's proof separating is better!
Hackatime. #
Users can login using Hack Club's Hackatime. Why? To get stats on their projects.
Git. #
When opening a repo with git.Repo(), make sure to add defer repo.Close() after it.
Resources #
- [https://github.com/firecracker-microvm/firecracker/blob/main/docs/prod-host-setup.md](Firecracker production guide)