Documentation ¶
Overview ¶
Package app implements the Skylab website for Orbital
Index ¶
- Constants
- Variables
- func AddSections(funcs template.FuncMap) template.FuncMap
- func ApplicationStatuses() []string
- func ApplicationSubsections() []string
- func Contains(values []string, target string) bool
- func EnsureDatabasePopulated(databaseURL, migrationDir string) error
- func GetVars(ctx context.Context) map[string]interface{}
- func InputSelect(vds []ValueDisplay, name, defaultValue, class string) template.HTML
- func InputSelectMilestoneOptional(name, defaultValue, class string) template.HTML
- func InputSelectProjectLevel(name, defaultValue, class string) template.HTML
- func InputSelectRole(name, defaultValue, class string) template.HTML
- func InputSelectStageOptional(name, defaultValue, class string) template.HTML
- func IsValidSection(section string) bool
- func JSONifyResponse(next http.HandlerFunc) http.HandlerFunc
- func LastSectionCookieName(role string) string
- func LoadDotenv()
- func MilestoneName(milestone string) string
- func MilestoneNameAbbrev(milestone string) string
- func Milestones() []string
- func ProjectLevels() []string
- func Roles() []string
- func SGTime(t sql.NullTime) string
- func SanitizeHTML(policy *bluemonday.Policy) func(string) template.HTML
- func SetVars(namespace string, ctx context.Context) context.Context
- func SetVarsHandler(namespace string) func(http.Handler) http.Handler
- func Stages() []string
- func TeamStatuses() []string
- func UserViewFuncs(funcs template.FuncMap, data UserView) template.FuncMap
- type Application
- type ApplicationEdit
- type ApplicationView
- type Config
- type Diagnosis
- type Form
- type FormEdit
- type FormView
- type Period
- type SidebarItem
- type Skylab
- func (skylb Skylab) AddInputSelects(funcs template.FuncMap) template.FuncMap
- func (skylb Skylab) AddProdContext(next http.Handler) http.Handler
- func (skylb Skylab) AllowIfDevelopment(next http.Handler) http.Handler
- func (skylb Skylab) BadRequest(w http.ResponseWriter, r *http.Request, msg string)
- func (skylb Skylab) BaseURLWithProtocol() string
- func (skylb Skylab) ChooseProvider(next http.Handler) http.Handler
- func (skylb Skylab) Cohorts() []string
- func (skylb Skylab) CsrfTokenInvalid() http.Handler
- func (skylb Skylab) CurrentCohort() string
- func (skylb Skylab) DecodeVariableFromCookie(r *http.Request, cookiename string, variablePtr interface{}) error
- func (skylb Skylab) EncodeVariableInCookie(w http.ResponseWriter, cookiename string, variable interface{}, ...) error
- func (skylb Skylab) EnsureIsUser(next http.Handler) http.Handler
- func (skylb Skylab) EnsureRole(role string) func(http.Handler) http.Handler
- func (skylb Skylab) GetFlashMsgs(w http.ResponseWriter, r *http.Request) (map[string][]flash.FlashMsg, error)
- func (skylb Skylab) GetSession(next http.Handler) http.Handler
- func (skylb Skylab) GetUserFromCookie(r *http.Request, cookieName string) (user User, err error)
- func (skylb Skylab) GetUserFromSessionID(sessionID string) (user User, err error)
- func (skylb Skylab) HasValidRole(next http.Handler) http.Handler
- func (skylb Skylab) Hash(input []byte) (output string)
- func (skylb Skylab) InputSelectCohort(name, defaultValue, class string) template.HTML
- func (skylb Skylab) InputSelectCohortOptional(name, defaultValue, class string) template.HTML
- func (skylb Skylab) InternalServerError(w http.ResponseWriter, r *http.Request, err error)
- func (skylb Skylab) LatestCohort() string
- func (skylb Skylab) MethodNotAllowed(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NavbarFuncs(funcs template.FuncMap, w http.ResponseWriter, r *http.Request) template.FuncMap
- func (skylb Skylab) NotAMentor(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotARole(role string) func(http.ResponseWriter, *http.Request)
- func (skylb Skylab) NotAStudent(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotAUser(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotAnAdmin(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotAnAdviser(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotAnApplicant(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotAuthorized(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotFound(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) NotLoggedIn(w http.ResponseWriter, r *http.Request)
- func (skylab Skylab) Port() string
- func (skylb Skylab) Redirect(url string) http.HandlerFunc
- func (skylb Skylab) RedirectAfterLogout(w http.ResponseWriter, r *http.Request)
- func (skylb Skylab) RedirectToLastSection(role string) func(http.Handler) http.Handler
- func (skylb Skylab) RedirectUserrole(w http.ResponseWriter, r *http.Request)
- func (skylb *Skylab) RefreshCohorts() error
- func (skylb Skylab) Render(w http.ResponseWriter, r *http.Request, data interface{}, ...)
- func (skylb Skylab) Render2(w http.ResponseWriter, r *http.Request, templateName string, ...)
- func (skylb Skylab) RevokeSession(next http.Handler) http.Handler
- func (skylb Skylab) RevokeSessionCookie(w http.ResponseWriter, r *http.Request, cookieName string) (err error)
- func (skylb Skylab) SessionIdIsValidRole(sessionID string, role string) (valid bool, err error)
- func (skylb Skylab) SetFlashMsgs(w http.ResponseWriter, r *http.Request, msgs map[string][]string) (*http.Request, error)
- func (skylb Skylab) SetRoleSection(w http.ResponseWriter, r *http.Request, role, section string) *http.Request
- func (skylb Skylab) SetRoleSectionHandler(role, section string) func(http.Handler) http.Handler
- func (skylb Skylab) SetSession(next http.Handler) http.Handler
- func (skylb Skylab) SetSessionForUserID(userID int) (sessionID string, sessionHash string, err error)
- func (skylb Skylab) SubmissionEdit(role string) http.HandlerFunc
- func (skylb Skylab) SubmissionView(role string) http.HandlerFunc
- func (skylb Skylab) TeamEvaluationView(role string) http.HandlerFunc
- func (skylb Skylab) UserEvaluationEdit(role string) http.HandlerFunc
- func (skylb Skylab) UserEvaluationView(role string) http.HandlerFunc
- func (skylb Skylab) ValidateCohortStageMilestone(cohort, stage, milestone string) error
- type Submission
- type SubmissionEditData
- type SubmissionViewData
- type Team
- type TeamEdit
- type TeamEvaluation
- type TeamEvaluationEdit
- type TeamEvaluationView
- type TeamFeedback
- type TeamView
- type User
- type UserEdit
- type UserEvaluation
- type UserEvaluationEdit
- type UserEvaluationView
- type UserFeedback
- type UserView
- type ValueDisplay
Constants ¶
const ( ProjectLevelVostok = "vostok" ProjectLevelGemini = "gemini" ProjectLevelApollo = "apollo" ProjectLevelArtemis = "artemis" )
ProjectLevel consts correspond to the project levels present inside the project_level_enum table in the database
const ( RoleApplicant = "applicant" RoleStudent = "student" RoleAdviser = "adviser" RoleMentor = "mentor" RoleAdmin = "admin" RoleNull = "" // RolePreserve is a special role that does not exist in the database, but // is only for facilitating the app RolePreserve = "preserve" )
Role consts correspond to the roles present inside the role_enum table in the database
const ( ApplicationStatusPending = "pending" ApplicationStatusAccepted = "accepted" ApplicationStatusDeleted = "deleted" )
ApplicationStatus consts correspond to the statuses present inside the applications_status_enum table in the database
const ( TeamStatusGood = "good" TeamStatusOk = "ok" TeamStatusUncontactable = "uncontactable" )
TeamStatus consts correspond to the statuses present inside the teams_status_enum table in the database
const ( StageApplication = "application" StageSubmission = "submission" StageEvaluation = "evaluation" StageFeedback = "feedback" StageNull = "" )
Stage consts correspond to the stages present inside the stage_enum table in the database
const ( Milestone1 = "milestone1" Milestone2 = "milestone2" Milestone3 = "milestone3" MilestoneNull = "" )
Milestone consts correspond to the milestones present inside the milestone_enum table in the database
const ( ApplicationSubsectionApplication = "application" ApplicationSubsectionApplicant = "applicant" )
ApplicationSubsection consts correspond to the subsection columns inside the form_schema table in the database, only applicable to application form schemas
const ( ContextUser skylabContext = "ContextUser" // skylab.User ContextAdmin skylabContext = "ContextAdmin" // skylab.User ContextCurrentRole skylabContext = "ContextCurrentRole" // string ContextCurrentSection skylabContext = "ContextCurrentSection" // string ContextCurrentMilestone skylabContext = "ContextCurrentMilestone" // string ContextDumpJson skylabContext = "ContextDumpJson" // bool ContextIsProd skylabContext = "ContextIsProd" // bool // Submission ContextCanViewSubmission skylabContext = "ContextCanViewSubmission" // bool ContextCanEditSubmission skylabContext = "ContextCanEditSubmission" // bool // Evaluation ContextCanViewEvaluation skylabContext = "ContextCanViewEvaluation" // bool ContextCanEditEvaluation skylabContext = "ContextCanEditEvaluation" // bool // User ContextCanViewUser skylabContext = "ContextCanViewUser" // bool ContextCanEditUser skylabContext = "ContextCanEditUser" // bool // Team ContextCanViewTeam skylabContext = "ContextCanViewTeam" // bool ContextCanEditTeam skylabContext = "ContextCanEditTeam" // bool // Form ContextCanViewForm skylabContext = "ContextCanViewForm" // bool ContextCanEditForm skylabContext = "ContextCanEditForm" // bool // Application ContextCanViewApplication skylabContext = "ContextCanViewApplication" // bool ContextCanEditApplication skylabContext = "ContextCanEditApplication" // bool )
The Context consts are used as keys to access various objects from the request context. Every app handler that sets/gets an object from the context must use one of these keys, so that all objects that are accessible from the context are effectively documented by this list here
const ( // Roles ErrNoRoles erro.BaseError = "OLAJQ User %+v has no roles" ErrNotAnApplicant erro.BaseError = "OC8FY User %+v is not an applicant" ErrNotAStudent erro.BaseError = "ONXIU User %+v is not a student" ErrNotAMentor erro.BaseError = "OQVPW User %+v is not a mentor" ErrNotAnAdviser erro.BaseError = "OKDRA User %+v is not an adviser" ErrNotAnAdmin erro.BaseError = "OD6HR User %+v is not an admin" ErrNoPeerTeams erro.BaseError = "OO6BX Team %+v has no peer teams" // Skylab Enums ErrCohortInvalid erro.BaseError = "OLALE Cohort '%s' is not a valid Skylab cohort" ErrStageInvalid erro.BaseError = "OLASP Stage '%s' is not a valid Skylab stage" ErrMilestoneInvalid erro.BaseError = "OLADN Milestone '%s' is not a valid Skylab milestone" ErrRoleInvalid erro.BaseError = "OLAZN Role '%s' is not a valid Skylab role" ErrProjectLevelInvalid erro.BaseError = "OEHGC Project Level '%s' is not a valid Skylab Project Level" // Forms ErrSubmissionFormNotExist erro.BaseError = "OYOE8 Submission form doesn't exist" ErrApplicationFormNotExist erro.BaseError = "OC8BK Application Form doesn't exist" // APPLICATION C8 ErrApplicationNotExist erro.BaseError = "OC8U9 Application doesn't exist" ErrApplicationPeriodNotFound erro.BaseError = "OC8EX Application period not found" ErrApplicationMagicstringNotExist erro.BaseError = "OC8UM Applicant {application_id:%d} tried joining an application with an invalid magicstring" ErrApplicantJoinedOwnApplication erro.BaseError = "OC8JK Applicant {uid:%d} tried joining an application created by himself" ErrApplicationAlreadyFull erro.BaseError = "OC8FB Application {application_id:%d} is already full" ErrApplicantLeaveNonExistentApplication erro.BaseError = "OC8EN Applicant {uid:%d} tried leaving an application when he isn't in one" ErrApplicantLeaveAcceptedApplication erro.BaseError = "OC8A4 Applicant {uid:%d} tried leaving an application [application_id:%d] that was already accepted" ErrApplicationDeleted erro.BaseError = "OC8W6 Application {application_id:%d} already accepted/deleted" ErrApplicationIncomplete erro.BaseError = "OC8KH Tried accepting an incomplete application" ErrApplicationNoTeam erro.BaseError = "OC8R1 Tried un-accepting an application that had never been accepted" // Misc ErrStudentNoTeam erro.BaseError = "ONXDI Student {uid:%d} does not belong to any team" ErrTeamMoreThanTwoStudents erro.BaseError = "OYSGQ Team {tid:%d} has more than two students" ErrEmailNotAuthorized erro.BaseError = "OLALP Email '%s' is not authorized to signup for any role" ErrEmailEmpty erro.BaseError = "OLAR9 Email must be non-empty" // Not exist ErrUserNotExist erro.BaseError = "OLAMC User does not exist: %s" ErrTeamNotExist erro.BaseError = "OWHZT Team does not exist: %s" ErrSubmissionNotExist erro.BaseError = "OQ7WT Submission does not exist: %s" ErrFormdataNotExist erro.BaseError = "ON354 Formdata {fdid:%d} does not exist" ErrTeamEvaluationNotExist erro.BaseError = "OSF99 Team Evaluation does not exist: %s" ErrUserEvaluationNotExist erro.BaseError = "OR2KO User Evaluation does not exist: %s" ErrTeamFeedbackNotExist erro.BaseError = "ONDHA Team Feedback does not exist: %s" ErrUserFeedbackNotExist erro.BaseError = "OXZW4 User Feedback does not exist: %s" ErrFormNotExist erro.BaseError = "OLAJX Form does not exist: %s" ErrPeriodNotExist erro.BaseError = "OLAEE Period does not exist: %s" )
Each error starts with a 5 letter error code, intended to represent the custom error codes that can be returned from postgres stored procedures.
How to name custom error codes https://stackoverflow.com/a/22600394 • Start with a capital letter but not F (predefined config file errors), H (fdw), P (PL/pgSQL) or X (internal). • Do not use 0 (zero) or P in the 3rd column. Predefined error codes use these commonly. • Use a capital letter in the 4th position. No predefined error codes have this. 'As an example, start with a character for your app: "T". Then a two-char error class: "3G". Then a sequential code "A0"-"A9", "B0"-"B9", etc. Yields T3GA0, T3GA1, etc.'
const ( SectionPreserve = "preserve" StudentDashboard = "/student/dashboard" StudentSubmission = "/student/submission" StudentUserEvaluation = "/student/user-evaluation" StudentTeamEvaluation = "/student/team-evaluation" StudentM1Submission = "/student/milestone1/submission" StudentM1Evaluation = "/student/milestone1/evaluation" StudentM2Submission = "/student/milestone2/submission" StudentM2Evaluation = "/student/milestone2/evaluation" StudentM3Submission = "/student/milestone3/submission" StudentM3Evaluation = "/student/milestone3/evaluation" StudentTeamFeedback = "/student/feedback/team" StudentUserFeedback = "/student/feedback/user" StudentListFeedbacks = "/student/feedbacks" StudentTeam = "/student/teams" AdviserDashboard = "/adviser/dashboard" AdviserTeams = "/adviser/teams" AdviserEvaluateeEvaluators = "/adviser/evaluatee-evaluators" AdviserEvaluatorEvaluatees = "/adviser/evaluator-evaluatees" AdviserSubmission = "/adviser/submission" AdviserUserEvaluation = "/adviser/user-evaluation" AdviserTeamEvaluation = "/adviser/team-evaluation" AdviserM1MakeEvaluation = "/adviser/milestone1/evaluation" AdviserM1ViewEvaluation = "/adviser/milestone1/evaluations" AdviserM2MakeEvaluation = "/adviser/milestone2/evaluation" AdviserM2ViewEvaluation = "/adviser/milestone2/evaluations" AdviserM3MakeEvaluation = "/adviser/milestone3/evaluation" AdviserM3ViewEvaluation = "/adviser/milestone3/evaluations" MentorDashboard = "/mentor/dashboard" AdminDashboard = "/admin/dashboard" AdminCreateUser = "/admin/create-user" AdminCreateUserConfirm = "/admin/create-user/confirm" AdminListCohorts = "/admin/cohorts" AdminListUsers = "/admin/users" AdminUser = "/admin/user" AdminListPeriods = "/admin/periods" AdminListForms = "/admin/forms" AdminForm = "/admin/form" AdminListTeams = "/admin/teams" AdminTeam = "/admin/team" AdminListApplications = "/admin/applications" AdminApplication = "/admin/application" AdminListFeedbacks = "/admin/feedbacks" AdminDumpJson = "/dump-json" AdminTestmail = "/testmail" // experimental )
const ( SessionCookieName = "_skylab_session" // The name of the cookie that stores the user's session AdminSessionCookieName = "_skylab_session_admin" // The name of the cookie that stores the admin's session )
const LastRoleCookieName = "_skylab_role"
const MultipartMaxSize = 32 << 20
Variables ¶
var ( // ProjectRootDir will point to wherever this project's root directory is located // on the user's computer. It is calculated as an offset of two // directories up from the skylab.go file ProjectRootDir = filepath.Join(filepath.Dir(sourcefile), ".."+string(os.PathSeparator)+"..") + string(os.PathSeparator) )
Functions ¶
func ApplicationStatuses ¶
func ApplicationStatuses() []string
func ApplicationSubsections ¶
func ApplicationSubsections() []string
func Contains ¶
Contains is general purpose string function that checks if a slice of values contains the target string.
func EnsureDatabasePopulated ¶
TODO: instead of being a custom function, EnsureDatabasePopulated should utilise loadsql's functions with the configuration -clean. So running `go run main.go` is enough to bootstrap everything (tables, triggers, views, functions, data). loadsql should accept an io.Writer to write to instead of taking control of stdout, and EnsureDatabasePopulated simply has to pass in os.Stdout to print to stdout as usual.
func InputSelect ¶
func InputSelect(vds []ValueDisplay, name, defaultValue, class string) template.HTML
func InputSelectProjectLevel ¶
func InputSelectRole ¶
func IsValidSection ¶
func JSONifyResponse ¶
func JSONifyResponse(next http.HandlerFunc) http.HandlerFunc
JSONifyResponse will set the value of ContextDumpJson to true, effectively signalling to (*Skylab).Render that it should render its output as JSON, not as HTML
func LastSectionCookieName ¶
func LoadDotenv ¶
func LoadDotenv()
LoadDotenv will read load the environment variables from the .env file in the project root directory. The environment variable can then be accessed normally with os.Getenv.
If the .env file is not found, it will read from the .env.default file instead. Such is the case when carrying out the automated tests in Github Actions. It is therefore important to ensure that the .env.default file has useful defaults set in it.
func MilestoneName ¶
MilestoneName pretty prints the name of the milestone
func Milestones ¶
func Milestones() []string
func ProjectLevels ¶
func ProjectLevels() []string
func SanitizeHTML ¶
func SanitizeHTML(policy *bluemonday.Policy) func(string) template.HTML
func TeamStatuses ¶
func TeamStatuses() []string
Types ¶
type Application ¶
type Application struct { Valid bool ApplicationID int Cohort string ProjectLevel string Status string Submitted bool Magicstring sql.NullString Applicant1 User Applicant2 User ApplicationForm Form ApplicationAnswers formx.Answers ApplicantForm Form Applicant1Answers formx.Answers Applicant2Answers formx.Answers }
func (*Application) RowMapper ¶
func (a *Application) RowMapper(tbl tables.VIEW_V_APPLICATIONS) func(*sq.Row)
type ApplicationEdit ¶
type ApplicationEdit struct { ApplicantUserID int Application Application }
type ApplicationView ¶
type ApplicationView struct {
Application Application
}
type Config ¶
type Config struct { BaseURL string // optional Port string // optional DatabaseURL string // !REQUIRED MigrationDir string // !REQUIRED IsProd string // optional DebugMode string // optional SecretKey string // optional DisableCsrf string // optional // Experimental MailerEnabled string SmtpHost string SmtpPort string SmtpUsername string SmtpPassword string }
Config contains all the parameters needed to start an instance of the Skylab application
type Form ¶
type SidebarItem ¶
type Skylab ¶
type Skylab struct { BaseURL string IsProd bool SecretKey string Policy *bluemonday.Policy DB *sqlx.DB Mux *chi.Mux Bufpool *bpool.BufferPool Log *logutil.Logger DisableCsrf bool Templates *template.Template // Mailer // NOTE: not used MailerEnabled bool SmtpHost string SmtpPort int SmtpUsername string SmtpPassword string // These fields below are not safe for concurrent access and access must be // synchronized with a mutex. RW *sync.RWMutex // contains filtered or unexported fields }
Skylab is the server struct.
func NewTestDefault ¶
NewTestDefault is the same as NewWithTestDB, except it uses a default skylab.Config instead of requiring the caller to pass one
func NewWithTestDB ¶
NewWithTestDB creates a new instance of Skylab with a test database. The test database reuses the same DATABASE_URL as the actual database, except all changes are rolled back once the test database is closed i.e. DB.Close(). This makes it easy for running database-related tests, without affecting the actual state of the database. You can optionally provide a txdbIdentifier string to id the test database being created, or you can leave it blank for a random identifier to be used. I assume databases with the same txdbIdentifier will share the same state, making it possible to share the same database between two tests by using the same txdbIdentifier.
func NewWithoutDB ¶
NewWithoutDB creates a new instance of Skylab that initializes everything except the database connection.
func (Skylab) AddInputSelects ¶
func (Skylab) AddProdContext ¶
AddProdContext will inject Skylab's environment (production or development) into the request context for handlers down the chain to pick up on
func (Skylab) AllowIfDevelopment ¶
func (Skylab) BadRequest ¶
func (Skylab) BaseURLWithProtocol ¶
BaseURL returns the base URL of the website e.g. localhost or nusskylabx.comp.nus.edu.sg.
This is purely for display purposes as the actual application is always running on localhost, even in production. On the production server, Nginx will reverse proxy the localhost application to the outside world. This greatly simplifies deploying the app in production as everything is exactly the same as in the development environment. The application also need not concern itself with a HTTPS certificate as that is handled on the Nginx layer.
func (Skylab) ChooseProvider ¶
ChooseProvider will check if there is a valid authentication provider (either openid or oauth) in the current request's queryparams and if there isn't, it will render a page for the user to choose their preferred provider. The page will contain the same links that it was called with, effectively redirecting to itself (except this time with a valid provider)
func (Skylab) CsrfTokenInvalid ¶
func (Skylab) CurrentCohort ¶
CurrentCohort returns the current cohort.
The CurrentCohort() is not the same as the LatestCohort(). CurrentCohort() only points to the current calendar year. LatestCohort() points to the latest created cohort in the database, which may not be the same as cohorts may be created ahead of the current calendar year.
func (Skylab) DecodeVariableFromCookie ¶
func (skylb Skylab) DecodeVariableFromCookie(r *http.Request, cookiename string, variablePtr interface{}) error
DecodeVariableFromCookie will retrieve a go variable from a client side cookie that was previously set by EncodeVariableInCookie. If the named cookie does not exist, it will fail with a cookies.ErrNoCookie error. Note that you need to pass a pointer to the variable you wish to decode the cookie value into, not the variable itself.
The cookie's digital hash signature will be checked for any tampering. If the signature is wrong, DecodeVariableFromCookie will fail with an auth.ErrDeserializeOutputInvalid error.
func (Skylab) EncodeVariableInCookie ¶
func (skylb Skylab) EncodeVariableInCookie(w http.ResponseWriter, cookiename string, variable interface{}, opts ...cookies.CookieOpt) error
EncodeVariableInCookie will serialize any go variable into a string and store it in a client side cookie, where it can later be retrieved from the cookie with DecodeVariableFromCookie.
The cookie will be securely signed with a digital hash signature to prevent anyone from tampering with the cookie's contents.
func (Skylab) EnsureIsUser ¶
EnsureIsUser ensures that the email from auth.Authenticate is a valid user in the system
func (Skylab) EnsureRole ¶
GetSession gets a User and an Admin from the database using their corresponding cookie session IDs, and injects them into the current context. If the User or Admin does not have the required roles, the user will be redirected to "app/skylab/403.html" instead
Calling EnsureRole(RoleNull) is equivalent to calling GetSession() directly
func (Skylab) GetFlashMsgs ¶
func (skylb Skylab) GetFlashMsgs(w http.ResponseWriter, r *http.Request) (map[string][]flash.FlashMsg, error)
GetFlashMsgs will get all flash messages from both the cookie and request context, after which it will delete the cookie (hence a 'flash' message).
Usually you won't call this function directly, instead you will include the "helpers/flash/flash.html" template in your html file which will automatically pick up the flash messages and display them if any exist.
func (Skylab) GetSession ¶
GetSession gets a User and an Admin from the database using their corresponding cookie session IDs, and injects them into the current context
func (Skylab) GetUserFromCookie ¶
GetUserFromCookie gets a User from the database using a cookie's session ID
func (Skylab) GetUserFromSessionID ¶
GetUserFromSessionID retrieves a User by sessionID.
Even if the user cannot be found in the database, this function will return without error. It is up to you to check the if the returned user's 'Valid' field is set to true. This makes it easier to distinguish between whether a user is valid (the user's Valid field is false) or whether an actual error occurred while querying the database (the returned error is non-nil).
Alternatively you can also check if the returned user has a particular role that is required to view the resource.
func (Skylab) InputSelectCohort ¶
func (Skylab) InputSelectCohortOptional ¶
func (Skylab) InternalServerError ¶
InternalServerError is a catch-all handler that will direct the user to a generic error page indicating 500 Internal Server Error.
InternalServerError must not depend on any function that calls InternalServerError on error (such as (*Skylab).Render), otherwise it will spin into an infinite loop
func (Skylab) LatestCohort ¶
LatestCohort returns the latest cohort in the database.
The LatestCohort() is not the same as the CurrentCohort(). LatestCohort() points to the latest cohort created in the database. CurrentCohort() points only to the current calendar year, which may not be the same as cohorts may be created ahead of the current calendar year.
func (Skylab) MethodNotAllowed ¶
func (skylb Skylab) MethodNotAllowed(w http.ResponseWriter, r *http.Request)
func (Skylab) NavbarFuncs ¶
func (skylb Skylab) NavbarFuncs(funcs template.FuncMap, w http.ResponseWriter, r *http.Request) template.FuncMap
NavbarFuncs contain the Template Functions required for rendering the navbar "app/skylab/navbar.html"
func (Skylab) NotAMentor ¶
func (skylb Skylab) NotAMentor(w http.ResponseWriter, r *http.Request)
func (Skylab) NotAStudent ¶
func (skylb Skylab) NotAStudent(w http.ResponseWriter, r *http.Request)
func (Skylab) NotAnAdmin ¶
func (skylb Skylab) NotAnAdmin(w http.ResponseWriter, r *http.Request)
func (Skylab) NotAnAdviser ¶
func (skylb Skylab) NotAnAdviser(w http.ResponseWriter, r *http.Request)
func (Skylab) NotAnApplicant ¶
func (skylb Skylab) NotAnApplicant(w http.ResponseWriter, r *http.Request)
func (Skylab) NotAuthorized ¶
func (skylb Skylab) NotAuthorized(w http.ResponseWriter, r *http.Request)
Authentication is not Authorization. Not authenticated means the user is not logged in. Not authorized means user is logged in but not allowed to carry out the action e.g. student trying to access an admin page
401 Unauthorized == Authentication error; 403 Forbidden == Authorization error
It seems contradictory that an *Authorization* error is actually 403 Forbidden and not 401 Unauthorized, but it's true. The people who designed the spec made a mistake and now we're all suffering for it. https://stackoverflow.com/a/6937030
func (Skylab) NotLoggedIn ¶
func (skylb Skylab) NotLoggedIn(w http.ResponseWriter, r *http.Request)
func (Skylab) Redirect ¶
func (skylb Skylab) Redirect(url string) http.HandlerFunc
Redirect returns a http.HandlerFunc that redirects to the given url
func (Skylab) RedirectAfterLogout ¶
func (skylb Skylab) RedirectAfterLogout(w http.ResponseWriter, r *http.Request)
func (Skylab) RedirectToLastSection ¶
func (Skylab) RedirectUserrole ¶
func (skylb Skylab) RedirectUserrole(w http.ResponseWriter, r *http.Request)
func (*Skylab) RefreshCohorts ¶
RefreshCohorts refreshes the current list of cohorts (kept in memory) by refreshing it from the database.
The reason why a list of cohorts is kept in-memory instead of querying it from the database on demand is because the cohort list rarely changes (once every year). That makes it inefficient to request it from database all the time. By keeping it in-memory, cohort retrieval is much faster but we have to refresh the cohort list everytime we add or remove a cohort from the database.
This may be a premature optimization.
func (Skylab) Render ¶
func (skylb Skylab) Render(w http.ResponseWriter, r *http.Request, data interface{}, funcs template.FuncMap, filename string, filenames ...string)
Render will render one or more html templates together with the given data and funcs. Crucially, this function is where all the global template functions (prefixed by "Skylab") and templates (such as the global navbar template "app/skylab/navbar.html") are injected. If you want to add any globally available template functions or templates files, this is the place to do it
func (Skylab) RevokeSession ¶
RevokeSession will revoke the user's or admin's (or both) sessions depending on whether the 'user' and 'admin' query params were provided. If neither was provided, both sessions will be revoked.
If only the user's session is revoked and the admin's session is not, the admin's existing session ID will be copied over as the new user session cookie. This ensures that the user session cookie is always present if someone is logged in.
func (Skylab) RevokeSessionCookie ¶
func (skylb Skylab) RevokeSessionCookie(w http.ResponseWriter, r *http.Request, cookieName string) (err error)
RevokeSessionCookie will revoke a cookie's session ID from the database, followed by deleting the cookie
func (Skylab) SessionIdIsValidRole ¶
SessionIdIsValidRole checks if the given sessionID (hashed into a sessionHash) exists in the database together with the given role
func (Skylab) SetFlashMsgs ¶
func (skylb Skylab) SetFlashMsgs(w http.ResponseWriter, r *http.Request, msgs map[string][]string) (*http.Request, error)
SetFlashMsgs will set a bunch of flash messages into a cookie that can be read later by GetFlashMsgs. See also: SetFlashMsgsCtx.
NOTE: This returns a new request with the flash messages in the context updated, so make sure to re-assign the request:
r, _ = skylb.SetFlashMsgs(w, r, msgs)
func (Skylab) SetRoleSection ¶
func (Skylab) SetRoleSectionHandler ¶
func (Skylab) SetSession ¶
SetSession sets the session for the user
func (Skylab) SetSessionForUserID ¶
func (skylb Skylab) SetSessionForUserID(userID int) (sessionID string, sessionHash string, err error)
SetSessionForUserID sets the session for the given userID and returns the sessionID as well as the sessionHash. Prefer using SetSession over SetSessionForUserID if possible, as userID and sessionHash are considered more low level implementation details that are only needed in specific situations
func (Skylab) SubmissionEdit ¶
func (skylb Skylab) SubmissionEdit(role string) http.HandlerFunc
func (Skylab) SubmissionView ¶
func (skylb Skylab) SubmissionView(role string) http.HandlerFunc
func (Skylab) TeamEvaluationView ¶
func (skylb Skylab) TeamEvaluationView(role string) http.HandlerFunc
func (Skylab) UserEvaluationEdit ¶
func (skylb Skylab) UserEvaluationEdit(role string) http.HandlerFunc
func (Skylab) UserEvaluationView ¶
func (skylb Skylab) UserEvaluationView(role string) http.HandlerFunc
func (Skylab) ValidateCohortStageMilestone ¶
type Submission ¶
type Submission struct { Valid bool SubmissionID int Team Team SubmissionForm Form SubmissionAnswers formx.Answers OverrideOpen bool Submitted bool UpdatedAt sql.NullTime }
func (*Submission) RowMapper ¶
func (s *Submission) RowMapper(tbl tables.VIEW_V_SUBMISSIONS) func(*sq.Row)
type SubmissionEditData ¶
type SubmissionEditData struct { Submission Submission PeerEvaluations []TeamEvaluation AdviserEvaluation UserEvaluation MentorEvaluation UserEvaluation PreviewURL string UpdateURL string SubmitURL string }
SubmissionEditData is the data struct that targets the "app/skylab/submission_edit.html" template
type SubmissionViewData ¶
type SubmissionViewData struct { Submission Submission EditURL string SubmitURL string }
SubmissionViewData is the data struct that targets the "app/skylab/submission_view.html" template
type Team ¶
type TeamEvaluation ¶
type TeamEvaluation struct { Valid bool TeamEvaluationID int Evaluator Team Evaluatee Submission EvaluationForm Form EvaluationAnswers formx.Answers OverrideOpen bool Submitted bool UpdatedAt sql.NullTime }
A TeamEvaluation is carried out by a Team on a Team
func (*TeamEvaluation) RowMapper ¶
func (e *TeamEvaluation) RowMapper(tbl tables.VIEW_V_TEAM_EVALUATIONS) func(*sq.Row)
type TeamEvaluationEdit ¶
type TeamEvaluationEdit struct { TeamEvaluation TeamEvaluation UpdateURL string SubmitURL string SubmissionURL string PreviewURL string }
type TeamEvaluationView ¶
type TeamEvaluationView struct { TeamEvaluation TeamEvaluation SubmitURL string SubmissionURL string EditURL string }
type TeamFeedback ¶
type TeamFeedback struct { Valid bool FeedbackIDOnTeam int Evaluator Team Evaluatee Team FeedbackForm Form FeedbackAnswers formx.Answers Submitted bool OverrideOpen bool }
Feedback given to a Team, by a Team
type UserEvaluation ¶
type UserEvaluation struct { Valid bool UserEvaluationID int Evaluator User Role string Evaluatee Submission EvaluationAnswers formx.Answers EvaluationForm Form Submitted bool OverrideOpen bool UpdatedAt sql.NullTime }
An UserEvaluation is carried out by a User on a Team
func (*UserEvaluation) RowMapper ¶
func (e *UserEvaluation) RowMapper(tbl tables.VIEW_V_USER_EVALUATIONS) func(*sq.Row)
type UserEvaluationEdit ¶
type UserEvaluationEdit struct { Evaluation UserEvaluation SubmissionURL string SubmitURL string PreviewURL string UpdateURL string }
type UserEvaluationView ¶
type UserEvaluationView struct { Evaluation UserEvaluation SubmissionURL string SubmitURL string EditURL string }
type UserFeedback ¶
type UserFeedback struct { Valid bool FeedbackIDOnUser int Evaluator Team Evaluatee User Role string FeedbackForm Form FeedbackAnswers formx.Answers Submitted bool OverrideOpen bool }
Feedback given to a User, by a Team