Split project into separate files
This commit is contained in:
parent
f5779ec55f
commit
57191c043e
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.linkedProjects": [
|
||||||
|
"./Cargo.toml",
|
||||||
|
"./Cargo.toml",
|
||||||
|
"./Cargo.toml"
|
||||||
|
]
|
||||||
|
}
|
||||||
247
src/main.rs
247
src/main.rs
@ -1,248 +1,11 @@
|
|||||||
// Webserver
|
// Webserver
|
||||||
#[macro_use] extern crate rocket;
|
#[macro_use] extern crate rocket;
|
||||||
|
mod database;
|
||||||
|
pub mod models;
|
||||||
|
use database::set_up_db;
|
||||||
|
|
||||||
use entities::members::ActiveModel;
|
mod webserver_member;
|
||||||
use rocket::{State, Error};
|
use webserver_member::*;
|
||||||
use rocket::response::status;
|
|
||||||
use rocket::serde::{Serialize, Deserialize, json::Json};
|
|
||||||
|
|
||||||
// Database
|
|
||||||
use sea_orm::*;
|
|
||||||
|
|
||||||
mod setup;
|
|
||||||
use setup::set_up_db;
|
|
||||||
|
|
||||||
mod entities;
|
|
||||||
use entities::{prelude::*, *};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct RfidCard {
|
|
||||||
cardId: String,
|
|
||||||
cardComment: String
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement `.into()` to auto map values from the database model to the local struct
|
|
||||||
impl From<<entities::rfid_cards::Entity as sea_orm::EntityTrait>::Model> for RfidCard {
|
|
||||||
fn from(rfid_card: <entities::rfid_cards::Entity as sea_orm::EntityTrait>::Model) -> RfidCard {
|
|
||||||
RfidCard {
|
|
||||||
cardId: rfid_card.card_id,
|
|
||||||
cardComment: rfid_card.card_comment,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct Member {
|
|
||||||
id: i32,
|
|
||||||
ntnuUsername: String,
|
|
||||||
firstName: String,
|
|
||||||
lastName: String,
|
|
||||||
email: String,
|
|
||||||
balance: i32,
|
|
||||||
imagePreference: String,
|
|
||||||
rfidCards: Vec<RfidCard>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the `.into()` functionality to auto map values from the database model to the local struct
|
|
||||||
// Don't be scared by the long model name, I typed `Members::Model` and applied the auto fix vscode suggested
|
|
||||||
impl From<entities::members::Model> for Member {
|
|
||||||
fn from(member: entities::members::Model) -> Member {
|
|
||||||
Member {
|
|
||||||
id: member.id,
|
|
||||||
ntnuUsername: member.ntnu_username,
|
|
||||||
firstName: member.first_name,
|
|
||||||
lastName: member.last_name,
|
|
||||||
email: member.email,
|
|
||||||
balance: member.balance,
|
|
||||||
imagePreference: member.image_preference,
|
|
||||||
rfidCards: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement DB Member Model -> MinimalMember
|
|
||||||
impl From<entities::members::Model> for MinimalMember {
|
|
||||||
fn from(member: entities::members::Model) -> MinimalMember {
|
|
||||||
MinimalMember {
|
|
||||||
id: member.id,
|
|
||||||
ntnuUsername: member.ntnu_username,
|
|
||||||
firstName: member.first_name,
|
|
||||||
lastName: member.last_name,
|
|
||||||
email: member.email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the functionality to create a database model member from the local struct model member
|
|
||||||
impl Into<entities::members::ActiveModel> for rocket::serde::json::Json<MinimalMemberWithoutId> {
|
|
||||||
fn into(self) -> entities::members::ActiveModel {
|
|
||||||
entities::members::ActiveModel {
|
|
||||||
ntnu_username: ActiveValue::Set(self.ntnuUsername.to_owned()),
|
|
||||||
first_name: ActiveValue::Set(self.firstName.to_owned()),
|
|
||||||
last_name: ActiveValue::Set(self.lastName.to_owned()),
|
|
||||||
email: ActiveValue::Set(self.email.to_owned()),
|
|
||||||
balance: ActiveValue::Set(0),
|
|
||||||
image_preference: ActiveValue::Set("".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct MinimalMember {
|
|
||||||
id: i32,
|
|
||||||
ntnuUsername: String,
|
|
||||||
firstName: String,
|
|
||||||
lastName: String,
|
|
||||||
email: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct MinimalMemberWithoutId {
|
|
||||||
ntnuUsername: String,
|
|
||||||
firstName: String,
|
|
||||||
lastName: String,
|
|
||||||
email: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct MultipleMembersStruct {
|
|
||||||
members: Vec<Member>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Responder)]
|
|
||||||
#[response(status = 500, content_type = "text/plain")]
|
|
||||||
struct ErrorResponder {
|
|
||||||
message: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DbErr> for ErrorResponder {
|
|
||||||
fn from(err: DbErr) -> ErrorResponder {
|
|
||||||
ErrorResponder { message: err.to_string() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<String> for ErrorResponder {
|
|
||||||
fn from(string: String) -> ErrorResponder {
|
|
||||||
ErrorResponder { message: string }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<&str> for ErrorResponder {
|
|
||||||
fn from(str: &str) -> ErrorResponder {
|
|
||||||
ErrorResponder { message: str.to_owned().into() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
fn index() -> &'static str {
|
|
||||||
"Hello, world!\nNothing useful is served here."
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/members")]
|
|
||||||
async fn get_members(db: &State<DatabaseConnection>) -> Result<Json<MultipleMembersStruct>, ErrorResponder> {
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
// Get a list of all members from the database
|
|
||||||
let members = Members::find().all(db).await?;
|
|
||||||
|
|
||||||
// Convert this vector from the database model to the local struct model
|
|
||||||
let mut members: Vec<Member> = members.into_iter().map(Member::from).collect();
|
|
||||||
|
|
||||||
// Fetch the member's RFID card
|
|
||||||
for member in &mut members {
|
|
||||||
// Look up all RFID cards associated with this member
|
|
||||||
let rfid_cards = RfidCards::find()
|
|
||||||
.filter(rfid_cards::Column::MemberId.eq(member.id))
|
|
||||||
.all(db)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Convert the RFID cards vector from the database model to the local struct model
|
|
||||||
let rfid_cards: Vec<RfidCard> = rfid_cards.into_iter().map(RfidCard::from).collect();
|
|
||||||
|
|
||||||
// Add these cards to the member's rfidCards field
|
|
||||||
member.rfidCards = rfid_cards;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Put this into the `MultipleMembersStruct` so that the aquired JSON will look as the API demands
|
|
||||||
let output = MultipleMembersStruct { members };
|
|
||||||
|
|
||||||
// Return the output
|
|
||||||
Ok(Json(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/member", data = "<minimal_member_without_id>")]
|
|
||||||
async fn add_member(db: &State<DatabaseConnection>, minimal_member_without_id: Json<MinimalMemberWithoutId>) -> Result<Json<MinimalMember>, ErrorResponder> {
|
|
||||||
// Grab the database connection
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
// Check if a member with the same NTNU username already exists
|
|
||||||
let matching_member: Option<members::Model> = Members::find() // Find a member in the "Members" table
|
|
||||||
.filter(members::Column::NtnuUsername.eq(minimal_member_without_id.ntnuUsername.to_owned())) // Filter by the provided username in the NtnuUsername column
|
|
||||||
.one(db) // We only care about one result
|
|
||||||
.await?; // Wait for the result
|
|
||||||
|
|
||||||
// If a member exists return an error
|
|
||||||
if matching_member.is_some() {
|
|
||||||
return Err(
|
|
||||||
ErrorResponder {
|
|
||||||
message: "A member with this NTNU username already exists".to_string(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the new member info from the provided JSON
|
|
||||||
let new_member: members::ActiveModel = minimal_member_without_id.into();
|
|
||||||
|
|
||||||
// Add the new member to the database
|
|
||||||
let res = Members::insert(new_member).exec(db).await?;
|
|
||||||
|
|
||||||
// Fetch the member's info back from the DB to verify
|
|
||||||
let new_member;
|
|
||||||
match Members::find_by_id(res.last_insert_id).one(db).await? {
|
|
||||||
Some(model) => new_member = model,
|
|
||||||
None => {
|
|
||||||
return Err(
|
|
||||||
ErrorResponder {
|
|
||||||
message: format!("Failed to fetch member for verification of creating new member with ID. memberId: {}", res.last_insert_id)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the fetched info into a minimal member for returning
|
|
||||||
let member: MinimalMember = new_member.into();
|
|
||||||
|
|
||||||
Ok(Json(member))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/member/<memberId>")]
|
|
||||||
async fn get_member_by_id(db: &State<DatabaseConnection>, memberId: i32) -> Result<Json<Member>, ErrorResponder> {
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
// Create an empty variable to store the resulting member info
|
|
||||||
let database_member;
|
|
||||||
// Search the database for the member based on the ID
|
|
||||||
match Members::find_by_id(memberId).one(db).await? {
|
|
||||||
Some(model) => database_member = model, // If the member is found, add the info to the previously created variable
|
|
||||||
None => {
|
|
||||||
return Err(
|
|
||||||
ErrorResponder {
|
|
||||||
message: format!("Failed to fetch member by ID. memberId: {}", memberId) // If it is not found return with this error
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the member's RFID cards
|
|
||||||
let member_rfid_cards: Vec<rfid_cards::Model> = database_member.find_related(RfidCards).all(db).await?;
|
|
||||||
let rfids: Vec<RfidCard> = member_rfid_cards.into_iter().map(RfidCard::from).collect();
|
|
||||||
|
|
||||||
// Create a member from the database model and append the RFID cards
|
|
||||||
let mut member: Member = database_member.into();
|
|
||||||
member.rfidCards = rfids;
|
|
||||||
|
|
||||||
Ok(Json(member))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[launch]
|
#[launch]
|
||||||
async fn rocket() -> _ {
|
async fn rocket() -> _ {
|
||||||
|
|||||||
99
src/models/member.rs
Normal file
99
src/models/member.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use rocket::serde::{Serialize, Deserialize};
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
use super::entities::{prelude::*, *};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct RfidCard {
|
||||||
|
pub cardId: String,
|
||||||
|
pub cardComment: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement `.into()` to auto map values from the database model to the local struct
|
||||||
|
impl From<rfid_cards::Model> for RfidCard {
|
||||||
|
fn from(rfid_card: rfid_cards::Model) -> RfidCard {
|
||||||
|
RfidCard {
|
||||||
|
cardId: rfid_card.card_id,
|
||||||
|
cardComment: rfid_card.card_comment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Member {
|
||||||
|
pub id: i32,
|
||||||
|
pub ntnuUsername: String,
|
||||||
|
pub firstName: String,
|
||||||
|
pub lastName: String,
|
||||||
|
pub email: String,
|
||||||
|
pub balance: i32,
|
||||||
|
pub imagePreference: String,
|
||||||
|
pub rfidCards: Vec<RfidCard>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the `.into()` functionality to auto map values from the database model to the local struct
|
||||||
|
// Don't be scared by the long model name, I typed `Members::Model` and applied the auto fix vscode suggested
|
||||||
|
impl From<members::Model> for Member {
|
||||||
|
fn from(member: members::Model) -> Member {
|
||||||
|
Member {
|
||||||
|
id: member.id,
|
||||||
|
ntnuUsername: member.ntnu_username,
|
||||||
|
firstName: member.first_name,
|
||||||
|
lastName: member.last_name,
|
||||||
|
email: member.email,
|
||||||
|
balance: member.balance,
|
||||||
|
imagePreference: member.image_preference,
|
||||||
|
rfidCards: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement DB Member Model -> MinimalMember
|
||||||
|
impl From<members::Model> for MinimalMember {
|
||||||
|
fn from(member: members::Model) -> MinimalMember {
|
||||||
|
MinimalMember {
|
||||||
|
id: member.id,
|
||||||
|
ntnuUsername: member.ntnu_username,
|
||||||
|
firstName: member.first_name,
|
||||||
|
lastName: member.last_name,
|
||||||
|
email: member.email,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the functionality to create a database model member from the local struct model member
|
||||||
|
impl Into<members::ActiveModel> for rocket::serde::json::Json<MinimalMemberWithoutId> {
|
||||||
|
fn into(self) -> members::ActiveModel {
|
||||||
|
members::ActiveModel {
|
||||||
|
ntnu_username: ActiveValue::Set(self.ntnuUsername.to_owned()),
|
||||||
|
first_name: ActiveValue::Set(self.firstName.to_owned()),
|
||||||
|
last_name: ActiveValue::Set(self.lastName.to_owned()),
|
||||||
|
email: ActiveValue::Set(self.email.to_owned()),
|
||||||
|
balance: ActiveValue::Set(0),
|
||||||
|
image_preference: ActiveValue::Set("".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct MinimalMember {
|
||||||
|
pub id: i32,
|
||||||
|
pub ntnuUsername: String,
|
||||||
|
pub firstName: String,
|
||||||
|
pub lastName: String,
|
||||||
|
pub email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct MinimalMemberWithoutId {
|
||||||
|
pub ntnuUsername: String,
|
||||||
|
pub firstName: String,
|
||||||
|
pub lastName: String,
|
||||||
|
pub email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct MultipleMembersStruct {
|
||||||
|
pub members: Vec<Member>,
|
||||||
|
}
|
||||||
2
src/models/mod.rs
Normal file
2
src/models/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod member;
|
||||||
|
pub mod entities;
|
||||||
148
src/webserver_member.rs
Normal file
148
src/webserver_member.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Import my models
|
||||||
|
// This feels like a really hacky way to import stuff, but it works
|
||||||
|
mod models {
|
||||||
|
include!("models/mod.rs");
|
||||||
|
}
|
||||||
|
use crate::webserver_member::models::member::*;
|
||||||
|
use crate::webserver_member::models::entities::{prelude::*, *};
|
||||||
|
|
||||||
|
// Webserver functions
|
||||||
|
use rocket::State;
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
|
// DB functions
|
||||||
|
use sea_orm::*;
|
||||||
|
|
||||||
|
#[derive(Responder)]
|
||||||
|
#[response(status = 500, content_type = "text/plain")]
|
||||||
|
struct ErrorResponder {
|
||||||
|
message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DbErr> for ErrorResponder {
|
||||||
|
fn from(err: DbErr) -> ErrorResponder {
|
||||||
|
ErrorResponder { message: err.to_string() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<String> for ErrorResponder {
|
||||||
|
fn from(string: String) -> ErrorResponder {
|
||||||
|
ErrorResponder { message: string }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<&str> for ErrorResponder {
|
||||||
|
fn from(str: &str) -> ErrorResponder {
|
||||||
|
ErrorResponder { message: str.to_owned().into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
pub fn index() -> &'static str {
|
||||||
|
"Hello, world!\nNothing useful is served here."
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/members")]
|
||||||
|
pub async fn get_members(db: &State<DatabaseConnection>) -> Result<Json<MultipleMembersStruct>, ErrorResponder> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
// Get a list of all members from the database
|
||||||
|
let members = Members::find().all(db).await?;
|
||||||
|
|
||||||
|
// Convert this vector from the database model to the local struct model
|
||||||
|
let mut members: Vec<Member> = members.into_iter().map(Member::from).collect();
|
||||||
|
|
||||||
|
// Fetch the member's RFID card
|
||||||
|
for member in &mut members {
|
||||||
|
// Look up all RFID cards associated with this member
|
||||||
|
let rfid_cards = RfidCards::find()
|
||||||
|
.filter(rfid_cards::Column::MemberId.eq(member.id))
|
||||||
|
.all(db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Convert the RFID cards vector from the database model to the local struct model
|
||||||
|
let rfid_cards: Vec<RfidCard> = rfid_cards.into_iter().map(RfidCard::from).collect();
|
||||||
|
|
||||||
|
// Add these cards to the member's rfidCards field
|
||||||
|
member.rfidCards = rfid_cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Put this into the `MultipleMembersStruct` so that the aquired JSON will look as the API demands
|
||||||
|
let output = MultipleMembersStruct { members };
|
||||||
|
|
||||||
|
// Return the output
|
||||||
|
Ok(Json(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/member", data = "<minimal_member_without_id>")]
|
||||||
|
pub async fn add_member(db: &State<DatabaseConnection>, minimal_member_without_id: Json<MinimalMemberWithoutId>) -> Result<Json<MinimalMember>, ErrorResponder> {
|
||||||
|
// Grab the database connection
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
// Check if a member with the same NTNU username already exists
|
||||||
|
let matching_member: Option<members::Model> = Members::find() // Find a member in the "Members" table
|
||||||
|
.filter(members::Column::NtnuUsername.eq(minimal_member_without_id.ntnuUsername.to_owned())) // Filter by the provided username in the NtnuUsername column
|
||||||
|
.one(db) // We only care about one result
|
||||||
|
.await?; // Wait for the result
|
||||||
|
|
||||||
|
// If a member exists return an error
|
||||||
|
if matching_member.is_some() {
|
||||||
|
return Err(
|
||||||
|
ErrorResponder {
|
||||||
|
message: "A member with this NTNU username already exists".to_string(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the new member info from the provided JSON
|
||||||
|
let new_member: members::ActiveModel = minimal_member_without_id.into();
|
||||||
|
|
||||||
|
// Add the new member to the database
|
||||||
|
let res = Members::insert(new_member).exec(db).await?;
|
||||||
|
|
||||||
|
// Fetch the member's info back from the DB to verify
|
||||||
|
let new_member;
|
||||||
|
match Members::find_by_id(res.last_insert_id).one(db).await? {
|
||||||
|
Some(model) => new_member = model,
|
||||||
|
None => {
|
||||||
|
return Err(
|
||||||
|
ErrorResponder {
|
||||||
|
message: format!("Failed to fetch member for verification of creating new member with ID. memberId: {}", res.last_insert_id)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the fetched info into a minimal member for returning
|
||||||
|
let member: MinimalMember = new_member.into();
|
||||||
|
|
||||||
|
Ok(Json(member))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/member/<memberId>")]
|
||||||
|
pub async fn get_member_by_id(db: &State<DatabaseConnection>, memberId: i32) -> Result<Json<Member>, ErrorResponder> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
// Create an empty variable to store the resulting member info
|
||||||
|
let database_member;
|
||||||
|
// Search the database for the member based on the ID
|
||||||
|
match Members::find_by_id(memberId).one(db).await? {
|
||||||
|
Some(model) => database_member = model, // If the member is found, add the info to the previously created variable
|
||||||
|
None => {
|
||||||
|
return Err(
|
||||||
|
ErrorResponder {
|
||||||
|
message: format!("Failed to fetch member by ID. memberId: {}", memberId) // If it is not found return with this error
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the member's RFID cards
|
||||||
|
let member_rfid_cards: Vec<rfid_cards::Model> = database_member.find_related(RfidCards).all(db).await?;
|
||||||
|
let rfids: Vec<RfidCard> = member_rfid_cards.into_iter().map(RfidCard::from).collect();
|
||||||
|
|
||||||
|
// Create a member from the database model and append the RFID cards
|
||||||
|
let mut member: Member = database_member.into();
|
||||||
|
member.rfidCards = rfids;
|
||||||
|
|
||||||
|
Ok(Json(member))
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user