342 lines
10 KiB
V
342 lines
10 KiB
V
module heromodels
|
|
|
|
import incubaid.herolib.data.encoder
|
|
import incubaid.herolib.data.ourtime
|
|
import incubaid.herolib.hero.db
|
|
import incubaid.herolib.schemas.jsonrpc { Response, new_error, new_response, new_response_false, new_response_int, new_response_true }
|
|
import incubaid.herolib.hero.user { UserRef }
|
|
import json
|
|
|
|
// Planning, how do people or teams want to plan their time
|
|
// acls can be used to define who can change this planning
|
|
@[heap]
|
|
pub struct Planning {
|
|
db.Base
|
|
pub mut:
|
|
color string // Hex color code
|
|
timezone string
|
|
is_public bool
|
|
calendar_template_id u32 // link to calendarid which is relevant for this planning, this calendar event will be a template
|
|
registration_desk_id u32 // to arrange how we let people register, and track registrations
|
|
autoschedule_rules []PlanningRecurrenceRule // will automatically schedule, uses calendar_id as template
|
|
invite_rules []PlanningRecurrenceRule // times in which people can invite themselves
|
|
attendees_required []u32
|
|
attendees_optional []u32 // if we want to specify upfront
|
|
}
|
|
|
|
pub struct PlanningRecurrenceRule {
|
|
pub mut:
|
|
until u64 // End date (Unix timestamp)
|
|
by_weekday []u8 // Days of week (0=Sunday)
|
|
by_monthday []u8 // Days of month
|
|
hour_from u8 // Start hour (0-23)
|
|
hour_to u8 // End hour (0-23)
|
|
duration int // Duration in minutes
|
|
priority u8 // Priority level (0-10)
|
|
}
|
|
|
|
pub fn (self PlanningRecurrenceRule) dump(mut e encoder.Encoder) ! {
|
|
e.add_u64(self.until)
|
|
e.add_list_u8(self.by_weekday)
|
|
e.add_list_u8(self.by_monthday)
|
|
e.add_u8(self.hour_from)
|
|
e.add_u8(self.hour_to)
|
|
e.add_int(self.duration)
|
|
e.add_u8(self.priority)
|
|
}
|
|
|
|
pub fn (mut self PlanningRecurrenceRule) load(mut e encoder.Decoder) ! {
|
|
self.until = e.get_u64()!
|
|
self.by_weekday = e.get_list_u8()!
|
|
self.by_monthday = e.get_list_u8()!
|
|
self.hour_from = e.get_u8()!
|
|
self.hour_to = e.get_u8()!
|
|
self.duration = e.get_int()!
|
|
self.priority = e.get_u8()!
|
|
}
|
|
|
|
pub struct DBPlanning {
|
|
pub mut:
|
|
db &db.DB @[skip; str: skip]
|
|
}
|
|
|
|
@[params]
|
|
pub struct PlanningListArg {
|
|
pub mut:
|
|
is_public bool
|
|
calendar_template_id u32
|
|
registration_desk_id u32
|
|
limit int = 100 // Default limit is 100
|
|
}
|
|
|
|
pub fn (self Planning) type_name() string {
|
|
return 'planning'
|
|
}
|
|
|
|
// return example rpc call and result for each methodname
|
|
pub fn (self Planning) description(methodname string) string {
|
|
match methodname {
|
|
'set' {
|
|
return 'Create or update a planning. Returns the ID of the planning.'
|
|
}
|
|
'get' {
|
|
return 'Retrieve a planning by ID. Returns the planning object.'
|
|
}
|
|
'delete' {
|
|
return 'Delete a planning by ID. Returns true if successful.'
|
|
}
|
|
'exist' {
|
|
return 'Check if a planning exists by ID. Returns true or false.'
|
|
}
|
|
'list' {
|
|
return 'List all plannings. Returns an array of planning objects.'
|
|
}
|
|
else {
|
|
return 'This is generic method for the root object, TODO fill in, ...'
|
|
}
|
|
}
|
|
}
|
|
|
|
// return example rpc call and result for each methodname
|
|
pub fn (self Planning) example(methodname string) (string, string) {
|
|
match methodname {
|
|
'set' {
|
|
return '{"planning": {"name": "My Planning", "description": "A personal planning", "color": "#FF0000", "timezone": "UTC", "is_public": true, "calendar_template_id": 1, "registration_desk_id": 10, "autoschedule_rules": [{"until": 1893456000, "by_weekday": [1, 3, 5], "by_monthday": [], "hour_from": 9, "hour_to": 17, "duration": 30, "priority": 5}], "invite_rules": [{"until": 0, "by_weekday": [], "by_monthday": [1, 15], "hour_from": 10, "hour_to": 12, "duration": 60, "priority": 8}], "attendees_required": [100, 101], "attendees_optional": [200]}}', '1'
|
|
}
|
|
'get' {
|
|
return '{"id": 1}', '{"name": "My Planning", "description": "A personal planning", "color": "#FF0000", "timezone": "UTC", "is_public": true, "calendar_template_id": 1, "registration_desk_id": 10, "autoschedule_rules": [{"until": 1893456000, "by_weekday": [1, 3, 5], "by_monthday": [], "hour_from": 9, "hour_to": 17, "duration": 30, "priority": 5}], "invite_rules": [{"until": 0, "by_weekday": [], "by_monthday": [1, 15], "hour_from": 10, "hour_to": 12, "duration": 60, "priority": 8}], "attendees_required": [100, 101], "attendees_optional": [200]}'
|
|
}
|
|
'delete' {
|
|
return '{"id": 1}', 'true'
|
|
}
|
|
'exist' {
|
|
return '{"id": 1}', 'true'
|
|
}
|
|
'list' {
|
|
return '{}', '[{"name": "My Planning", "description": "A personal planning", "color": "#FF0000", "timezone": "UTC", "is_public": true, "calendar_template_id": 1, "registration_desk_id": 10, "autoschedule_rules": [{"until": 1893456000, "by_weekday": [1, 3, 5], "by_monthday": [], "hour_from": 9, "hour_to": 17, "duration": 30, "priority": 5}], "invite_rules": [{"until": 0, "by_weekday": [], "by_monthday": [1, 15], "hour_from": 10, "hour_to": 12, "duration": 60, "priority": 8}], "attendees_required": [100, 101], "attendees_optional": [200]}]'
|
|
}
|
|
else {
|
|
return '{}', '{}'
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn (self Planning) dump(mut e encoder.Encoder) ! {
|
|
e.add_string(self.color)
|
|
e.add_string(self.timezone)
|
|
e.add_bool(self.is_public)
|
|
e.add_u32(self.calendar_template_id)
|
|
e.add_u32(self.registration_desk_id)
|
|
|
|
// Encode autoschedule_rules array
|
|
e.add_u16(u16(self.autoschedule_rules.len))
|
|
for rule in self.autoschedule_rules {
|
|
rule.dump(mut e)!
|
|
}
|
|
|
|
// Encode invite_rules array
|
|
e.add_u16(u16(self.invite_rules.len))
|
|
for rule in self.invite_rules {
|
|
rule.dump(mut e)!
|
|
}
|
|
|
|
// Encode attendees_required array
|
|
e.add_list_u32(self.attendees_required)
|
|
|
|
// Encode attendees_optional array
|
|
e.add_list_u32(self.attendees_optional)
|
|
}
|
|
|
|
fn (mut self DBPlanning) load(mut o Planning, mut e encoder.Decoder) ! {
|
|
o.color = e.get_string()!
|
|
o.timezone = e.get_string()!
|
|
o.is_public = e.get_bool()!
|
|
o.calendar_template_id = e.get_u32()!
|
|
o.registration_desk_id = e.get_u32()!
|
|
|
|
// Decode autoschedule_rules array
|
|
autoschedule_rules_len := e.get_u16()!
|
|
mut autoschedule_rules := []PlanningRecurrenceRule{}
|
|
for _ in 0 .. autoschedule_rules_len {
|
|
mut rule := PlanningRecurrenceRule{}
|
|
rule.load(mut e)!
|
|
autoschedule_rules << rule
|
|
}
|
|
o.autoschedule_rules = autoschedule_rules
|
|
|
|
// Decode invite_rules array
|
|
invite_rules_len := e.get_u16()!
|
|
mut invite_rules := []PlanningRecurrenceRule{}
|
|
for _ in 0 .. invite_rules_len {
|
|
mut rule := PlanningRecurrenceRule{}
|
|
rule.load(mut e)!
|
|
invite_rules << rule
|
|
}
|
|
o.invite_rules = invite_rules
|
|
|
|
// Decode attendees_required array
|
|
o.attendees_required = e.get_list_u32()!
|
|
|
|
// Decode attendees_optional array
|
|
o.attendees_optional = e.get_list_u32()!
|
|
}
|
|
|
|
@[params]
|
|
pub struct PlanningArg {
|
|
pub mut:
|
|
id u32
|
|
name string
|
|
description string
|
|
color string
|
|
timezone string
|
|
is_public bool
|
|
calendar_template_id u32
|
|
registration_desk_id u32
|
|
autoschedule_rules []PlanningRecurrenceRule
|
|
invite_rules []PlanningRecurrenceRule
|
|
attendees_required []u32
|
|
attendees_optional []u32
|
|
securitypolicy u32
|
|
tags []string
|
|
messages []db.MessageArg
|
|
}
|
|
|
|
// get new calendar, not from the DB
|
|
pub fn (mut self DBPlanning) new(args PlanningArg) !Planning {
|
|
mut o := Planning{
|
|
color: args.color
|
|
timezone: args.timezone
|
|
is_public: args.is_public
|
|
calendar_template_id: args.calendar_template_id
|
|
registration_desk_id: args.registration_desk_id
|
|
autoschedule_rules: args.autoschedule_rules
|
|
invite_rules: args.invite_rules
|
|
attendees_required: args.attendees_required
|
|
attendees_optional: args.attendees_optional
|
|
}
|
|
|
|
// Set base fields
|
|
o.name = args.name
|
|
o.description = args.description
|
|
o.securitypolicy = args.securitypolicy
|
|
o.tags = self.db.tags_get(args.tags)!
|
|
o.messages = self.db.messages_get(args.messages)!
|
|
o.updated_at = ourtime.now().unix()
|
|
|
|
return o
|
|
}
|
|
|
|
pub fn (mut self DBPlanning) set(o Planning) !Planning {
|
|
// Use db set function which returns the object with assigned ID
|
|
return self.db.set[Planning](o)!
|
|
}
|
|
|
|
pub fn (mut self DBPlanning) delete(id u32) !bool {
|
|
// Check if the item exists before trying to delete
|
|
if !self.db.exists[Planning](id)! {
|
|
return false
|
|
}
|
|
self.db.delete[Planning](id)!
|
|
return true
|
|
}
|
|
|
|
pub fn (mut self DBPlanning) exist(id u32) !bool {
|
|
return self.db.exists[Planning](id)!
|
|
}
|
|
|
|
pub fn (mut self DBPlanning) get(id u32) !Planning {
|
|
mut o, data := self.db.get_data[Planning](id)!
|
|
mut e_decoder := encoder.decoder_new(data)
|
|
self.load(mut o, mut e_decoder)!
|
|
return o
|
|
}
|
|
|
|
pub fn (mut self DBPlanning) list(args PlanningListArg) ![]Planning {
|
|
// Get all plannings from the database
|
|
all_plannings := self.db.list[Planning]()!.map(self.get(it)!)
|
|
|
|
// Apply filters
|
|
mut filtered_plannings := []Planning{}
|
|
for planning in all_plannings {
|
|
// Filter by is_public if provided
|
|
if args.is_public && !planning.is_public {
|
|
continue
|
|
}
|
|
|
|
// Filter by calendar_template_id if provided
|
|
if args.calendar_template_id != 0
|
|
&& planning.calendar_template_id != args.calendar_template_id {
|
|
continue
|
|
}
|
|
|
|
// Filter by registration_desk_id if provided
|
|
if args.registration_desk_id != 0
|
|
&& planning.registration_desk_id != args.registration_desk_id {
|
|
continue
|
|
}
|
|
|
|
filtered_plannings << planning
|
|
}
|
|
|
|
// Limit results to 100 or the specified limit
|
|
mut limit := args.limit
|
|
if limit > 100 {
|
|
limit = 100
|
|
}
|
|
if filtered_plannings.len > limit {
|
|
return filtered_plannings[..limit]
|
|
}
|
|
|
|
return filtered_plannings
|
|
}
|
|
|
|
pub fn planning_handle(mut f ModelsFactory, rpcid int, servercontext map[string]string, userref UserRef, method string, params string) !Response {
|
|
match method {
|
|
'get' {
|
|
id := db.decode_u32(params)!
|
|
res := f.planning.get(id)!
|
|
return new_response(rpcid, json.encode(res))
|
|
}
|
|
'set' {
|
|
mut args := db.decode_generic[PlanningArg](params)!
|
|
mut o := f.planning.new(args)!
|
|
if args.id != 0 {
|
|
o.id = args.id
|
|
}
|
|
o = f.planning.set(o)!
|
|
return new_response_int(rpcid, int(o.id))
|
|
}
|
|
'delete' {
|
|
id := db.decode_u32(params)!
|
|
deleted := f.planning.delete(id)!
|
|
if deleted {
|
|
return new_response_true(rpcid)
|
|
} else {
|
|
return new_error(rpcid,
|
|
code: 404
|
|
message: 'Planning with ID ${id} not found'
|
|
)
|
|
}
|
|
}
|
|
'exist' {
|
|
id := db.decode_u32(params)!
|
|
if f.planning.exist(id)! {
|
|
return new_response_true(rpcid)
|
|
} else {
|
|
return new_response_false(rpcid)
|
|
}
|
|
}
|
|
'list' {
|
|
args := db.decode_generic[PlanningListArg](params)!
|
|
res := f.planning.list(args)!
|
|
return new_response(rpcid, json.encode(res))
|
|
}
|
|
else {
|
|
return new_error(rpcid,
|
|
code: 32601
|
|
message: 'Method ${method} not found on planning'
|
|
)
|
|
}
|
|
}
|
|
}
|