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 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 PadUid(users []User, userArrayArray ...[]User) func(int) string
- func ProjectLevels() []string
- func Roles() []string
- func SGTime(t sql.NullTime) string
- func SanitizeHTML(policy *bluemonday.Policy) func(string) template.HTML
- func Stages() []string
- func TeamStatuses() []string
- func UserViewFuncs(funcs map[string]interface{}, data UserView) map[string]interface{}
- type Application
- type ApplicationEdit
- type ApplicationView
- type Config
- type DatabaseOp
- type Diagnosis
- type FormEdit
- type FormView
- type Form_Old
- type Formdata
- type Period
- type SidebarItem
- type Skylab
- func (skylb Skylab) AddInputSelects(funcs map[string]interface{}) map[string]interface{}
- 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) CreateTeam_Old(team Team_Old) (tid int, err error)
- func (skylb Skylab) CreateUser(user User) (uid int, err error)
- func (skylb Skylab) CreateUserWithRoles(user User, cohort string) (uid int, roles map[string]int, err error)
- 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) 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) GetPeriodTimestatus(cohort, stage, milestone string) (status Timestatus, err error)
- func (skylb Skylab) GetSession(next http.Handler) http.Handler
- func (skylb Skylab) GetTeam_Old(tid int) (Team_Old, error)
- 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 map[string]interface{}, w http.ResponseWriter, r *http.Request) map[string]interface{}
- 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) 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) 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) error
- func (skylb Skylab) SetFlashMsgsCtx(r *http.Request, msgs map[string][]string) context.Context
- func (skylb Skylab) SetRoleSectionCtx(w http.ResponseWriter, r *http.Request, role, section string) context.Context
- func (skylb Skylab) SetRoleSectionCtxHandler(role, section string) func(http.Handler) http.Handler
- func (skylb Skylab) SetSession(next http.Handler) http.Handler
- func (skylb Skylab) SetSessionUid(uid int) (sessionID string, sessionHash string, err error)
- func (skylb Skylab) ValidateCohortStageMilestone(cohort, stage, milestone string) error
- type Submission
- type SubmissionEdit
- type SubmissionView
- type Team
- type TeamEdit
- type TeamEvaluation
- type TeamEvaluationEdit
- type TeamEvaluationView
- type TeamEvaluation_Old
- type TeamFeedback
- type TeamView
- type Team_Old
- type Timestatus
- type User
- type UserEdit
- type UserEvaluation
- type UserEvaluation_Old
- 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" // orbital.User ContextAdmin skylabContext = "ContextAdmin" // orbital.User ContextCurrentRole skylabContext = "ContextCurrentRole" // string ContextCurrentSection skylabContext = "ContextCurrentSection" // string ContextDumpJson skylabContext = "ContextDumpJson" // bool ContextIsProd skylabContext = "ContextIsProd" // bool ContextAllowJS skylabContext = "ContextAllowJS" // 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" // 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" ErrApplicationMoreThanTwoApplicants erro.BaseError = "OC8VX Application [apnid:%d] has more than two applicants" ErrApplicationMagicstringNotExist erro.BaseError = "OC8UM Applicant [apnid:%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 [apnid:%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 [apnid:%d] that was already accepted" ErrApplicationDeleted erro.BaseError = "OC8W6 Application [apnid:%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" AdminCreateTeam = "/admin/create-team" AdminCreateTeamConfirm = "/admin/create-team/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" AdminDebugMode = "/debug-mode" 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 GorillaCsrfToken = "gorilla.csrf.Token" // will eventually be deleted, not really used
const LastRoleCookieName = "_skylab_role"
Variables ¶
var ( _,// SkylabDotGo is the filepath to the source file skylab.go SkylabDotGo, _, _ = runtime.Caller(0) // RootDir will point to wherever this project's root directory is located // on the user's computer. It is calculated by an offset of two // directories up from the skylab.go file RootDir = filepath.Join(filepath.Dir(SkylabDotGo), ".."+string(os.PathSeparator)+"..") + string(os.PathSeparator) )
Functions ¶
func ApplicationStatuses ¶
func ApplicationStatuses() []string
func ApplicationSubsections ¶
func ApplicationSubsections() []string
func EnsureDatabasePopulated ¶
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. This is the case when carrying out the automated tests in Github Actions. It is therefore important to ensure that the .env.default file has sane defaults set in it.
func MilestoneName ¶
MilestoneName pretty prints the name of the milestone
func Milestones ¶
func Milestones() []string
func PadUid ¶
PadUid pads a uid up to the max number of digits in the highest uid in a given slice of users
func ProjectLevels ¶
func ProjectLevels() []string
func SanitizeHTML ¶
func SanitizeHTML(policy *bluemonday.Policy) func(string) template.HTML
func TeamStatuses ¶
func TeamStatuses() []string
func UserViewFuncs ¶
Types ¶
type Application ¶
type ApplicationEdit ¶
type ApplicationEdit struct {
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 DatabaseOp ¶
func (*DatabaseOp) CreateRole ¶
func (db *DatabaseOp) CreateRole(cohort, role, email string)
func (*DatabaseOp) CreateUser ¶
func (db *DatabaseOp) CreateUser(displayname, email string)
func (*DatabaseOp) UpdateDisplayname ¶
func (db *DatabaseOp) UpdateDisplayname(displayname, email string)
type Form_Old ¶
type Form_Old struct { Cohort string `db:"cohort"` Stage string `db:"stage"` Milestone string `db:"milestone"` Name string `db:"name"` Subsection string `db:"subsection"` Fsid int `db:"fsid"` Questions formx.Questions `db:"questions"` StartAt sql.NullTime `db:"start_at"` EndAt sql.NullTime `db:"end_at"` }
type Formdata ¶
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 // Mailer 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 represents a common backend object that handles anything web related, but is blind to the database. It parses HTTP requests into Go variables to be handed to the Orbital object for database persistence/processing. The Apt & Stu & Adv & Mnt & Adm & Shr structs will embed the Skylab struct, hence inheriting any methods and fields exported by Skylab
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 fantastic for running database tests on, 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.
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 nusskylab-dev.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) CreateTeam_Old ¶
func (Skylab) CreateUser ¶
CreateUser creates a new user in the database, returning the uid of the user.
The only fields it needs to read from are user.Displayname and user.Email.
It is idempotent and safe to call on the same user multiple times.
func (Skylab) CreateUserWithRoles ¶
func (skylb Skylab) CreateUserWithRoles(user User, cohort string) (uid int, roles map[string]int, err error)
CreateUserWithRoles will create a user like Skylab.CreateUser, but it will also create new roles for every role specified in user.Roles. It returns the uid of the created user as well as the urids for each user role that was created.
The fields it reads from are user.Displayname, user.Email and user.Roles.
It is idempotent and safe to call on a user multiple times.
func (Skylab) CsrfTokenInvalid ¶
func (Skylab) CurrentCohort ¶
CurrentCohort returns the current cohort.
The CurrentCohort() is not the same as the LatestCohort(), as 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) 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 (and the skylb.Render call) which will automatically pick up the flash messages and display them if any exist. Make sure to include the flash message functions (flash.Funcs) into the skylb.Render call so that "helpers/flash/flash.html" can call this function:
var funcs template.FuncMap funcs = flash.Funcs(funcs) skylb.Render(w, r, data, funcs, "some_file.html", "helpers/flash/flash.html")
func (Skylab) GetPeriodTimestatus ¶
func (skylb Skylab) GetPeriodTimestatus(cohort, stage, milestone string) (status Timestatus, err error)
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
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(), as 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 map[string]interface{}, w http.ResponseWriter, r *http.Request) map[string]interface{}
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 != 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) error
SetFlashMsgs will set a bunch of flash messages into a cookie that can be read later by GetFlashMsgs. See also: SetFlashMsgsCtx.
NOTE: IF YOU ARE RUNNING INTO ISSUES setting flash messages with SetFlashMsgs and being unable to read flash messages with GetFlashMsgs, it is very likely you're setting the flash messages and reading it in the same request. This will not work because SetFlashMsgs writes the data into a cookie, and you won't be able to read from that cookie until the next request (such as a redirect). To set a flash message in a handler and read it later in another handler under the same request, use SetFlashMsgsCtx instead. It takes all the same arguments except you can leave out the `w http.ResponseWriter`.
TL;DR if this not work use SetFlashMsgsCtx: From:
skylb.SetFlashMsgs(w, r, msgs) skylb.Render(w, r, nil, nil, "some_file.html")
To:
r = r.WithContext(skylb.SetFlashMsgsCtx(r, msgs)) skylb.Render(w, r, nil, nil, "some_file.html")
func (Skylab) SetFlashMsgsCtx ¶ added in v0.2.0
SetFlashMsgsCtx will set a bunch of flash messages into the request context that can be read later by GetFlashMsgs. See also: SetFlashMsgs.
NOTE: this returns a context.Context, which you must explicitly include into your current request context with:
r = r.WithContext(skylb.SetFlashMsgsCtx(r, msgs))
NOTE: IF YOU ARE RUNNING INTO ISSUES setting flash messages with SetFlashMsgsCtx and being unable to read flash messages with GetFlashMsgs, it is likely you're setting the flash messages and reading it after a redirect. This will not work bacuse SetFlashMsgsCtx writes the data into the request context, which is gone at the start of a new request. A redirect counts as a new request. To set a flash message in a handler and read it after a redirect, use SetFlashMsgs instead.
TL;DR if this not work use SetFlashMsgs: From:
r = r.WithContext(skylb.SetFlashMsgsCtx(r, msgs)) skylb.Render(w, r, nil, nil, "some_file.html")
To:
skylb.SetFlashMsgs(w, r, msgs) skylb.Render(w, r, nil, nil, "some_file.html")
func (Skylab) SetRoleSectionCtx ¶
func (Skylab) SetRoleSectionCtxHandler ¶
func (Skylab) SetSession ¶
SetSession sets the session for the user
func (Skylab) SetSessionUid ¶
SetSessionUid sets the session for the given uid and returns the sessionID as well as the sessionHash. Prefer using SetSession over SetSessionUid if possible, as uid and sessionHash are considered more low level implementation details that are only needed in specific situations
func (Skylab) ValidateCohortStageMilestone ¶
type Submission ¶
type SubmissionEdit ¶
type SubmissionEdit struct { Submission Submission PeerEvaluations []TeamEvaluation AdviserEvaluation UserEvaluation MentorEvaluation UserEvaluation PreviewURL string UpdateURL string SubmitURL string }
type SubmissionView ¶
type SubmissionView struct { Submission Submission EditURL string SubmitURL string }
type TeamEvaluation ¶
type TeamEvaluation struct { Valid bool Tesid int Evaluator Team Evaluatee Submission Formdata Formdata Submitted bool OverrideOpen bool }
An Evaluation carried out *by a Team*, to another Team
type TeamEvaluationEdit ¶
type TeamEvaluationEdit struct { TeamEvaluation TeamEvaluation UpdateURL string SubmitURL string }
type TeamEvaluationView ¶
type TeamEvaluationView struct { TeamEvaluation TeamEvaluation SubmitURL string }
type TeamEvaluation_Old ¶
type TeamEvaluation_Old struct { Cohort string `db:"cohort"` Milestone string `db:"milestone"` // Submission Tsid sql.NullInt64 `db:"tsid"` EvaluateeTid int `db:"evaluatee_tid"` EvaluateeTeamName string `db:"evaluatee_team_name"` EvaluateeProjectLevel string `db:"evaluatee_project_level"` SubmissionQuestions formx.Questions `db:"submission_questions"` SubmissionAnswers formx.Answers `db:"submission_answers"` SubmissionQuestionAnswers []formx.QuestionAnswer `db:"-"` SubmissionStartAt sql.NullTime `db:"submission_start_at"` SubmissionEndAt sql.NullTime `db:"submission_end_at"` SubmissionSubmitted sql.NullBool `db:"submission_submitted"` SubmissionUpdatedAt sql.NullTime `db:"submission_updated_at"` SubmissionOverrideOpen sql.NullBool `db:"submission_override_open"` // Evaluation Tesid sql.NullInt64 `db:"tesid"` EvaluatorTid int `db:"evaluator_tid"` EvaluatorTeamName string `db:"evaluator_team_name"` EvaluatorProjectLevel string `db:"evaluator_project_level"` EvaluationQuestions formx.Questions `db:"evaluation_questions"` EvaluationAnswers formx.Answers `db:"evaluation_answers"` EvaluationQuestionAnswers []formx.QuestionAnswer `db:"-"` EvaluationStartAt sql.NullTime `db:"evaluation_start_at"` EvaluationEndAt sql.NullTime `db:"evaluation_end_at"` EvaluationSubmitted sql.NullBool `db:"evaluation_submitted"` EvaluationUpdatedAt sql.NullTime `db:"evaluation_updated_at"` EvaluationOverrideOpen sql.NullBool `db:"evaluation_override_open"` }
type TeamFeedback ¶
type TeamFeedback struct { Valid bool Tftid int Evaluator Team Evaluatee Team Formdata Formdata Submitted bool OverrideOpen bool }
Feedback given *to a Team*, by a Team
type Team_Old ¶
type Team_Old struct { Tid int `db:"tid"` Cohort string `db:"cohort"` TeamName string `db:"team_name"` ProjectLevel string `db:"project_level"` Status string `db:"status"` Student1Uid sql.NullInt64 `db:"stu1_uid"` Student1Displayname sql.NullString `db:"stu1_displayname"` Student1Email sql.NullString `db:"stu1_email"` Student2Uid sql.NullInt64 `db:"stu2_uid"` Student2Displayname sql.NullString `db:"stu2_displayname"` Student2Email sql.NullString `db:"stu2_email"` AdviserUid sql.NullInt64 `db:"adv_uid"` AdviserDisplayname sql.NullString `db:"adv_displayname"` AdviserEmail sql.NullString `db:"adv_email"` MentorUid sql.NullInt64 `db:"mnt_uid"` MentorDisplayname sql.NullString `db:"mnt_displayname"` MentorEmail sql.NullString `db:"mnt_email"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` DeletedAt sql.NullTime `db:"deleted_at"` }
type Timestatus ¶
type Timestatus struct { Start sql.NullTime End sql.NullTime IsOpen bool NotYetOpen bool AlreadyClosed bool InvalidStartEnd bool }
func ResolveTimestatus ¶
func ResolveTimestatus(start, end sql.NullTime) (status Timestatus)
type UserEvaluation ¶
type UserEvaluation struct { Valid bool Uesid int Evaluator User Role string Evaluatee Submission Formdata Formdata Submitted bool }
An Evaluation carried out *by a User*, to a Team
type UserEvaluation_Old ¶
type UserEvaluation_Old struct { Cohort string `db:"cohort"` Milestone string `db:"milestone"` // Submission Tsid sql.NullInt64 `db:"tsid"` EvaluateeTid int `db:"evaluatee_tid"` EvaluateeTeamName string `db:"evaluatee_team_name"` EvaluateeProjectLevel string `db:"evaluatee_project_level"` SubmissionQuestions formx.Questions `db:"submission_questions"` SubmissionAnswers formx.Answers `db:"submission_answers"` SubmissionQuestionAnswers []formx.QuestionAnswer `db:"-"` SubmissionStartAt sql.NullTime `db:"submission_start_at"` SubmissionEndAt sql.NullTime `db:"submission_end_at"` SubmissionSubmitted sql.NullBool `db:"submission_submitted"` SubmissionUpdatedAt sql.NullTime `db:"submission_updated_at"` SubmissionOverrideOpen sql.NullBool `db:"submission_override_open"` // Evaluation Uesid sql.NullInt64 `db:"uesid"` EvaluatorUrid int `db:"evaluator_urid"` EvaluatorDisplayname string `db:"evaluator_displayname"` EvaluationQuestions formx.Questions `db:"evaluation_questions"` EvaluationAnswers formx.Answers `db:"evaluation_answers"` EvaluationSubmitted sql.NullBool `db:"evaluation_submitted"` EvaluationQuestionAnswers []formx.QuestionAnswer `db:"-"` EvaluationStartAt sql.NullTime `db:"evaluation_start_at"` EvaluationEndAt sql.NullTime `db:"evaluation_end_at"` EvaluationUpdatedAt sql.NullTime `db:"evaluation_updated_at"` }
type UserFeedback ¶
type UserFeedback struct { Valid bool Tfuid int Evaluator Team Evaluatee User Role string Formdata Formdata Submitted bool OverrideOpen bool }
Feedback given *to a User*, by a Team