Files
herolib/lib/hero/heromodels/message.v
Mahmoud-Emad be18d30de3 fix: Improve delete operations with existence checks
- Update delete functions to return bool indicating success
- Add existence checks before deleting items
- Return 404 error for non-existent items in RPC delete operations
- Remove unused 'new_response_ok' result from RPC delete operations
2025-10-01 10:11:12 +03:00

277 lines
6.8 KiB
V

module heromodels
import freeflowuniverse.herolib.data.encoder
import freeflowuniverse.herolib.data.ourtime
import freeflowuniverse.herolib.hero.db
import freeflowuniverse.herolib.schemas.jsonrpc { Response, new_error, new_response, new_response_false, new_response_int, new_response_true }
import freeflowuniverse.herolib.hero.user { UserRef }
import json
@[heap]
pub struct Message {
db.Base
pub mut:
// id u32
subject string
message string
parent u32 // id of parent message if any, 0 means none
author u32 // links to user
to []u32 // if message/message has been sent to someone specifically
cc []u32 // like to but then for cc
send_log []SendLog
}
pub struct SendLog {
pub mut:
to []u32 // if message/message has been sent to someone specifically
cc []u32 // like to but then for cc
status SendStatus
timestamp u64 // when was it done
}
enum SendStatus {
sent
received
acknowledged
}
//////////TO BE GENERATED BY AI////////////////////////////////
///BASIC CRUD FUNCTIONS
pub struct DBMessages {
pub mut:
db &db.DB @[skip; str: skip]
}
@[params]
pub struct MessageListArg {
pub mut:
parent u32
author u32
limit int = 100 // Default limit is 100
}
pub fn (self Message) type_name() string {
return 'messages'
}
// return example rpc call and result for each methodname
pub fn (self Message) description(methodname string) string {
match methodname {
'set' {
return 'Create or update a message. Returns the ID of the message.'
}
'get' {
return 'Retrieve a message by ID. Returns the message object.'
}
'delete' {
return 'Delete a message by ID. Returns true if successful.'
}
'exist' {
return 'Check if a message exists by ID. Returns true or false.'
}
'list' {
return 'List all messages. Returns an array of message 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 Message) example(methodname string) (string, string) {
match methodname {
'set' {
return '{"message": {"subject": "Test Subject", "message": "This is a test message.", "parent": 0, "author": 1, "to": [2, 3], "cc": [4], "send_log": [{"to": [2], "cc": [], "status": "sent", "timestamp": 1678886400}]}}', '1'
}
'get' {
return '{"id": 1}', '{"subject": "Test Subject", "message": "This is a test message.", "parent": 0, "author": 1, "to": [2, 3], "cc": [4], "send_log": [{"to": [2], "cc": [], "status": "sent", "timestamp": 1678886400}]}'
}
'delete' {
return '{"id": 1}', 'true'
}
'exist' {
return '{"id": 1}', 'true'
}
'list' {
return '{}', '[{"subject": "Test Subject", "message": "This is a test message.", "parent": 0, "author": 1, "to": [2, 3], "cc": [4], "send_log": [{"to": [2], "cc": [], "status": "sent", "timestamp": 1678886400}]}]'
}
else {
return '{}', '{}'
}
}
}
pub fn (self Message) dump(mut e encoder.Encoder) ! {
e.add_string(self.subject)
e.add_string(self.message)
e.add_u32(self.parent)
e.add_u32(self.author)
e.add_list_u32(self.to)
e.add_list_u32(self.cc)
// Encode send_log array
e.add_u16(u16(self.send_log.len))
for log_entry in self.send_log {
e.add_list_u32(log_entry.to)
e.add_list_u32(log_entry.cc)
e.add_u8(u8(log_entry.status))
e.add_u64(log_entry.timestamp)
}
}
pub fn (mut self DBMessages) load(mut o Message, mut e encoder.Decoder) ! {
o.subject = e.get_string()!
o.message = e.get_string()!
o.parent = e.get_u32()!
o.author = e.get_u32()!
o.to = e.get_list_u32()!
o.cc = e.get_list_u32()!
// Decode send_log array
send_log_len := e.get_u16()!
mut send_logs := []SendLog{}
for _ in 0 .. send_log_len {
to_list := e.get_list_u32()!
cc_list := e.get_list_u32()!
status := unsafe { SendStatus(e.get_u8()!) }
timestamp := e.get_u64()!
send_logs << SendLog{
to: to_list
cc: cc_list
status: status
timestamp: timestamp
}
}
o.send_log = send_logs
}
@[params]
pub struct MessageArg {
pub mut:
subject string
message string @[required]
parent u32
author u32
to []u32
cc []u32
}
// get new message, not from the DB
pub fn (mut self DBMessages) new(args MessageArg) !Message {
mut o := Message{
subject: args.subject
message: args.message
parent: args.parent
author: args.author
to: args.to
cc: args.cc
send_log: []SendLog{} // Initialize as empty
updated_at: ourtime.now().unix()
}
return o
}
pub fn (mut self DBMessages) set(o Message) !Message {
// Use db set function which returns the object with assigned ID
return self.db.set[Message](o)!
}
pub fn (mut self DBMessages) delete(id u32) !bool {
// Check if the item exists before trying to delete
if !self.db.exists[Message](id)! {
return false
}
self.db.delete[Message](id)!
return true
}
pub fn (mut self DBMessages) exist(id u32) !bool {
return self.db.exists[Message](id)!
}
pub fn (mut self DBMessages) get(id u32) !Message {
mut o, data := self.db.get_data[Message](id)!
mut e_decoder := encoder.decoder_new(data)
self.load(mut o, mut e_decoder)!
return o
}
pub fn (mut self DBMessages) list(args MessageListArg) ![]Message {
// Get all messages from the database
all_messages := self.db.list[Message]()!.map(self.get(it)!)
// Apply filters
mut filtered_messages := []Message{}
for message in all_messages {
// Filter by parent if provided
if args.parent != 0 && message.parent != args.parent {
continue
}
// Filter by author if provided
if args.author != 0 && message.author != args.author {
continue
}
filtered_messages << message
}
// Limit results to 100 or the specified limit
mut limit := args.limit
if limit > 100 {
limit = 100
}
if filtered_messages.len > limit {
return filtered_messages[..limit]
}
return filtered_messages
}
pub fn message_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.messages.get(id)!
return new_response(rpcid, json.encode(res))
}
'set' {
mut o := db.decode_generic[Message](params)!
o = f.messages.set(o)!
return new_response_int(rpcid, int(o.id))
}
'delete' {
id := db.decode_u32(params)!
deleted := f.messages.delete(id)!
if deleted {
return new_response_true(rpcid)
} else {
return new_error(rpcid,
code: 404
message: 'Message with ID ${id} not found'
)
}
}
'exist' {
id := db.decode_u32(params)!
if f.messages.exist(id)! {
return new_response_true(rpcid)
} else {
return new_response_false(rpcid)
}
}
'list' {
args := db.decode_generic[MessageListArg](params)!
res := f.messages.list(args)!
return new_response(rpcid, json.encode(res))
}
else {
return new_error(rpcid,
code: 32601
message: 'Method ${method} not found on message'
)
}
}
}