First pass of an API
+ Implemented register, find, and add_location + Bunch of changes to the DB and the Models to make this work + API models are defined in GeoffreyModels so things that call the API don't need to define their own types + Still needs a lot of work, and need to design the api a bit more + Clippy + fmtmain
parent
9bf31f17f6
commit
b92308da67
|
@ -3,3 +3,4 @@
|
||||||
/database
|
/database
|
||||||
/test_database
|
/test_database
|
||||||
config.toml
|
config.toml
|
||||||
|
*.http
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
use crate::commands::{Command, RequestType};
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::helper::get_player_from_req;
|
||||||
|
use crate::Result;
|
||||||
|
use geoffrey_models::models::locations::Location;
|
||||||
|
use geoffrey_models::models::parameters::add_location_params::AddLocationParams;
|
||||||
|
use geoffrey_models::models::parameters::CommandRequest;
|
||||||
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||||
|
use geoffrey_models::models::CommandLevel;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct AddLocation {}
|
||||||
|
|
||||||
|
impl Command for AddLocation {
|
||||||
|
type Req = CommandRequest<AddLocationParams>;
|
||||||
|
type Resp = Location;
|
||||||
|
|
||||||
|
fn command_name() -> String {
|
||||||
|
"add_location".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_type() -> RequestType {
|
||||||
|
RequestType::POST
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_level() -> CommandLevel {
|
||||||
|
CommandLevel::REGISTERED
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_command(ctx: Arc<Context>, req: Self::Req) -> Result<Self::Resp> {
|
||||||
|
if let Some(player) = get_player_from_req(&ctx.db, &req)? {
|
||||||
|
let args = &req.arguments;
|
||||||
|
let location = Location::new(
|
||||||
|
args.name.as_str(),
|
||||||
|
args.position,
|
||||||
|
player.id.unwrap(),
|
||||||
|
args.tunnel.clone(),
|
||||||
|
args.loc_type.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.db
|
||||||
|
.insert(location)
|
||||||
|
.map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string()))
|
||||||
|
} else {
|
||||||
|
Err(GeoffreyAPIError::PlayerNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
use crate::commands::{Command, RequestType};
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::Result;
|
||||||
|
use geoffrey_models::models::locations::Location;
|
||||||
|
use geoffrey_models::models::parameters::find_params::FindParams;
|
||||||
|
use geoffrey_models::models::parameters::CommandRequest;
|
||||||
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||||
|
use geoffrey_models::models::CommandLevel;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct FindCommand {}
|
||||||
|
|
||||||
|
impl Command for FindCommand {
|
||||||
|
type Req = CommandRequest<FindParams>;
|
||||||
|
type Resp = Vec<Location>;
|
||||||
|
|
||||||
|
fn command_name() -> String {
|
||||||
|
"find".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_type() -> RequestType {
|
||||||
|
RequestType::GET
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_level() -> CommandLevel {
|
||||||
|
CommandLevel::ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_command(ctx: Arc<Context>, req: Self::Req) -> Result<Self::Resp> {
|
||||||
|
let locations = ctx
|
||||||
|
.db
|
||||||
|
.filter(|_, loc: &Location| {
|
||||||
|
let name = loc.name.to_lowercase();
|
||||||
|
let query = req.arguments.query.to_lowercase();
|
||||||
|
|
||||||
|
name.contains(&query)
|
||||||
|
})
|
||||||
|
.map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string()))?
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(locations)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::commands::add_location::AddLocation;
|
||||||
|
use crate::commands::find::FindCommand;
|
||||||
|
use crate::commands::register::Register;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::Result;
|
||||||
|
use geoffrey_models::models::response::APIResponse;
|
||||||
|
use geoffrey_models::models::CommandLevel;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use warp::filters::BoxedFilter;
|
||||||
|
use warp::Filter;
|
||||||
|
|
||||||
|
pub mod add_location;
|
||||||
|
pub mod find;
|
||||||
|
pub mod register;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub enum RequestType {
|
||||||
|
POST,
|
||||||
|
GET,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Command {
|
||||||
|
type Req: Serialize + DeserializeOwned + Send + 'static;
|
||||||
|
type Resp: Serialize + DeserializeOwned + Send;
|
||||||
|
|
||||||
|
fn command_name() -> String;
|
||||||
|
fn request_type() -> RequestType;
|
||||||
|
fn command_level() -> CommandLevel;
|
||||||
|
fn run_command(ctx: Arc<Context>, req: Self::Req) -> Result<Self::Resp>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_return)]
|
||||||
|
pub fn create_command_filter<T: Command>(ctx: Arc<Context>) -> BoxedFilter<(impl warp::Reply,)> {
|
||||||
|
let filter = warp::path(T::command_name())
|
||||||
|
.and(warp::any().map(move || ctx.clone()))
|
||||||
|
.and(warp::body::json())
|
||||||
|
.map(|ctx: Arc<Context>, req: T::Req| {
|
||||||
|
let reply = T::run_command(ctx, req);
|
||||||
|
if let Ok(reply) = reply {
|
||||||
|
warp::reply::json(&APIResponse::Response::<T::Resp>(reply))
|
||||||
|
} else {
|
||||||
|
warp::reply::json(&APIResponse::<T::Resp>::Error(reply.err().unwrap()))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if T::request_type() == RequestType::POST {
|
||||||
|
return filter.and(warp::post()).boxed();
|
||||||
|
} else {
|
||||||
|
return filter.and(warp::get()).boxed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command_filter(
|
||||||
|
ctx: Arc<Context>,
|
||||||
|
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||||
|
warp::path("command").and(
|
||||||
|
create_command_filter::<FindCommand>(ctx.clone())
|
||||||
|
.or(create_command_filter::<AddLocation>(ctx.clone()))
|
||||||
|
.or(create_command_filter::<Register>(ctx)),
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::commands::{Command, RequestType};
|
||||||
|
use crate::context::Context;
|
||||||
|
use geoffrey_models::models::parameters::register_params::RegisterParameters;
|
||||||
|
use geoffrey_models::models::parameters::CommandRequest;
|
||||||
|
use geoffrey_models::models::player::Player;
|
||||||
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||||
|
use geoffrey_models::models::CommandLevel;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Register {}
|
||||||
|
|
||||||
|
impl Command for Register {
|
||||||
|
type Req = CommandRequest<RegisterParameters>;
|
||||||
|
type Resp = Player;
|
||||||
|
|
||||||
|
fn command_name() -> String {
|
||||||
|
"register".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_type() -> RequestType {
|
||||||
|
RequestType::POST
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_level() -> CommandLevel {
|
||||||
|
CommandLevel::ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_command(ctx: Arc<Context>, req: Self::Req) -> crate::Result<Self::Resp> {
|
||||||
|
let player = Player::new(req.arguments.username.as_str(), req.arguments.user_id);
|
||||||
|
|
||||||
|
ctx.db
|
||||||
|
.insert(player)
|
||||||
|
.map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
use config::{Config, ConfigError, File};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
pub struct GeoffreyAPIConfig {
|
||||||
|
pub db_path: PathBuf,
|
||||||
|
pub host: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeoffreyAPIConfig {
|
||||||
|
pub fn new(config_path: &Path) -> Result<Self, ConfigError> {
|
||||||
|
let mut cfg = Config::new();
|
||||||
|
cfg.merge(File::from(config_path.to_path_buf()))?;
|
||||||
|
|
||||||
|
cfg.try_into()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
use crate::config::GeoffreyAPIConfig;
|
||||||
|
use crate::Result;
|
||||||
|
use geoffrey_db::database::Database;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Context {
|
||||||
|
pub db: Database,
|
||||||
|
pub cfg: GeoffreyAPIConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn new(cfg: GeoffreyAPIConfig) -> Result<Arc<Self>> {
|
||||||
|
let ctx = Self {
|
||||||
|
db: Database::new(cfg.db_path.as_path()).unwrap(),
|
||||||
|
cfg,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Arc::new(ctx))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
use crate::Result;
|
||||||
|
use geoffrey_db::database::Database;
|
||||||
|
use geoffrey_models::models::parameters::CommandRequest;
|
||||||
|
use geoffrey_models::models::player::Player;
|
||||||
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||||
|
|
||||||
|
pub fn get_player_from_req<T>(db: &Database, req: &CommandRequest<T>) -> Result<Option<Player>> {
|
||||||
|
if let Some(user_id) = &req.user {
|
||||||
|
Ok(db
|
||||||
|
.filter(|_, player: &Player| player.has_user_id(user_id))
|
||||||
|
.map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string()))?
|
||||||
|
.next())
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,18 @@
|
||||||
mod commands;
|
mod commands;
|
||||||
mod error;
|
|
||||||
mod context;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod responses;
|
mod context;
|
||||||
|
mod helper;
|
||||||
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use crate::config::GeoffreyAPIConfig;
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use crate::context::Context;
|
|
||||||
use crate::commands::command_filter;
|
use crate::commands::command_filter;
|
||||||
|
use crate::config::GeoffreyAPIConfig;
|
||||||
|
use crate::context::Context;
|
||||||
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, GeoffreyAPIError>;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
#[structopt(name = "GeoffreyAPI", about = "Geoffrey Central API")]
|
#[structopt(name = "GeoffreyAPI", about = "Geoffrey Central API")]
|
||||||
|
@ -23,7 +25,7 @@ struct Args {
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let args: Args = Args::from_args();
|
let args: Args = Args::from_args();
|
||||||
|
|
||||||
let cfg= GeoffreyAPIConfig::new(args.config.as_path()).unwrap();
|
let cfg = GeoffreyAPIConfig::new(args.config.as_path()).unwrap();
|
||||||
|
|
||||||
let ctx = Context::new(cfg).unwrap();
|
let ctx = Context::new(cfg).unwrap();
|
||||||
|
|
||||||
|
@ -32,4 +34,4 @@ async fn main() {
|
||||||
warp::serve(api)
|
warp::serve(api)
|
||||||
.run(SocketAddr::from_str(ctx.cfg.host.as_str()).unwrap())
|
.run(SocketAddr::from_str(ctx.cfg.host.as_str()).unwrap())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::{Result, GeoffreyDBError};
|
use crate::error::{GeoffreyDBError, Result};
|
||||||
use std::path::Path;
|
|
||||||
use geoffrey_models::GeoffreyDatabaseModel;
|
use geoffrey_models::GeoffreyDatabaseModel;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
db: sled::Db,
|
db: sled::Db,
|
||||||
|
@ -11,16 +11,20 @@ impl Database {
|
||||||
pub fn new(db_path: &Path) -> Result<Self> {
|
pub fn new(db_path: &Path) -> Result<Self> {
|
||||||
let db = sled::open(db_path)?;
|
let db = sled::open(db_path)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { db })
|
||||||
db,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tree<T>(&self) -> Result<sled::Tree> where T: GeoffreyDatabaseModel {
|
fn get_tree<T>(&self) -> Result<sled::Tree>
|
||||||
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
Ok(self.db.open_tree::<String>(T::tree())?)
|
Ok(self.db.open_tree::<String>(T::tree())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert<T>(&self, mut model: T) -> Result<T> where T: GeoffreyDatabaseModel {
|
pub fn insert<T>(&self, mut model: T) -> Result<T>
|
||||||
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
let id = match model.id() {
|
let id = match model.id() {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -30,12 +34,10 @@ impl Database {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let match_count = self.filter(|_, o: &T| {
|
let match_count = self.filter(|_, o: &T| !o.check_unique(&model))?.count();
|
||||||
!o.check_unique(&model)
|
|
||||||
})?.count();
|
|
||||||
|
|
||||||
if match_count > 0 {
|
if match_count > 0 {
|
||||||
return Err(GeoffreyDBError::NotUnique)
|
return Err(GeoffreyDBError::NotUnique);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = self.get_tree::<T>()?;
|
let tree = self.get_tree::<T>()?;
|
||||||
|
@ -46,25 +48,34 @@ impl Database {
|
||||||
Ok(model)
|
Ok(model)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get<T>(&self, id: u64) -> Result<Option<T>>
|
||||||
pub fn get<T>(&self, id: u64) -> Result<Option<T>> where T: GeoffreyDatabaseModel {
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
let tree = self.get_tree::<T>()?;
|
let tree = self.get_tree::<T>()?;
|
||||||
let id_bytes = id.to_be_bytes();
|
let id_bytes = id.to_be_bytes();
|
||||||
|
|
||||||
if let Some(bytes) = tree.get(id_bytes)? {
|
if let Some(bytes) = tree.get(id_bytes)? {
|
||||||
Ok(Some(T::try_from_bytes(&bytes)?))
|
Ok(Some(T::try_from_bytes(&bytes)?))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_tree<T>(&self) -> Result<()> where T: GeoffreyDatabaseModel {
|
pub fn clear_tree<T>(&self) -> Result<()>
|
||||||
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
Ok(self.db.open_tree(T::tree())?.clear()?)
|
Ok(self.db.open_tree(T::tree())?.clear()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter<'a, T>(&self, f: impl Fn(u64, &T) -> bool + 'a) -> Result<impl Iterator<Item=T> + 'a> where T: GeoffreyDatabaseModel {
|
pub fn filter<'a, T>(
|
||||||
|
&self,
|
||||||
|
f: impl Fn(u64, &T) -> bool + 'a,
|
||||||
|
) -> Result<impl Iterator<Item = T> + 'a>
|
||||||
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
let tree = self.db.open_tree(T::tree())?;
|
let tree = self.db.open_tree(T::tree())?;
|
||||||
|
|
||||||
Ok(tree.iter().filter_map(move |e| {
|
Ok(tree.iter().filter_map(move |e| {
|
||||||
|
@ -74,31 +85,32 @@ impl Database {
|
||||||
|
|
||||||
if f(id, &data) {
|
if f(id, &data) {
|
||||||
Some(data)
|
Some(data)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tree_iter<T>(&self) -> Result<sled::Iter> where T: GeoffreyDatabaseModel {
|
pub fn tree_iter<T>(&self) -> Result<sled::Iter>
|
||||||
|
where
|
||||||
|
T: GeoffreyDatabaseModel,
|
||||||
|
{
|
||||||
Ok(self.db.open_tree(T::tree()).map(|tree| tree.iter())?)
|
Ok(self.db.open_tree(T::tree()).map(|tree| tree.iter())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::database::{Database};
|
use crate::database::Database;
|
||||||
use std::path::Path;
|
|
||||||
use geoffrey_models::models::player::{Player, UserID};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use geoffrey_models::GeoffreyDatabaseModel;
|
|
||||||
use geoffrey_models::models::locations::{Location, LocationType};
|
use geoffrey_models::models::locations::{Location, LocationType};
|
||||||
use geoffrey_models::models::{Position, Dimension};
|
use geoffrey_models::models::player::{Player, UserID};
|
||||||
|
use geoffrey_models::models::{Dimension, Position};
|
||||||
|
use geoffrey_models::GeoffreyDatabaseModel;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::path::Path;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -120,7 +132,6 @@ mod tests {
|
||||||
assert!(p2.id().is_some());
|
assert!(p2.id().is_some());
|
||||||
assert_eq!(player.name, p2.name);
|
assert_eq!(player.name, p2.name);
|
||||||
|
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,13 +163,22 @@ mod tests {
|
||||||
fn test_filter() {
|
fn test_filter() {
|
||||||
let player = Player::new("CoolZero123", UserID::DiscordUUID(0u64));
|
let player = Player::new("CoolZero123", UserID::DiscordUUID(0u64));
|
||||||
let player = DB.insert::<Player>(player.clone()).unwrap();
|
let player = DB.insert::<Player>(player.clone()).unwrap();
|
||||||
let loc = Location::new("Test Shop", Position::new(0, 0, Dimension::Overworld), player.id.unwrap(), None, LocationType::Shop(0));
|
let loc = Location::new(
|
||||||
|
"Test Shop",
|
||||||
|
Position::new(0, 0, Dimension::Overworld),
|
||||||
|
player.id.unwrap(),
|
||||||
|
None,
|
||||||
|
LocationType::Shop(0),
|
||||||
|
);
|
||||||
let loc = DB.insert::<Location>(loc.clone()).unwrap();
|
let loc = DB.insert::<Location>(loc.clone()).unwrap();
|
||||||
|
|
||||||
let count = DB.filter(|id: u64, l: &Location| {
|
let count = DB
|
||||||
assert_eq!(id, l.id().unwrap());
|
.filter(|id: u64, l: &Location| {
|
||||||
loc.id().unwrap() == id
|
assert_eq!(id, l.id().unwrap());
|
||||||
}).unwrap().count();
|
loc.id().unwrap() == id
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.count();
|
||||||
|
|
||||||
assert_eq!(count, 1);
|
assert_eq!(count, 1);
|
||||||
DB.db.flush().unwrap();
|
DB.db.flush().unwrap();
|
||||||
|
@ -178,9 +198,12 @@ mod tests {
|
||||||
|
|
||||||
DB.db.flush().unwrap();
|
DB.db.flush().unwrap();
|
||||||
let sec_elapsed = timer.elapsed().as_secs_f32();
|
let sec_elapsed = timer.elapsed().as_secs_f32();
|
||||||
println!("Completed in {}s. {} inserts per second", sec_elapsed, insert_count as f32/sec_elapsed);
|
println!(
|
||||||
|
"Completed in {}s. {} inserts per second",
|
||||||
|
sec_elapsed,
|
||||||
|
insert_count as f32 / sec_elapsed
|
||||||
|
);
|
||||||
|
|
||||||
cleanup()
|
cleanup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl std::fmt::Display for GeoffreyDBError {
|
||||||
match self {
|
match self {
|
||||||
GeoffreyDBError::SledError(e) => write!(f, "Sled Error: {}", e),
|
GeoffreyDBError::SledError(e) => write!(f, "Sled Error: {}", e),
|
||||||
GeoffreyDBError::SerdeJsonError(e) => write!(f, "Serde JSON Error: {}", e),
|
GeoffreyDBError::SerdeJsonError(e) => write!(f, "Serde JSON Error: {}", e),
|
||||||
GeoffreyDBError::NotUnique => write!(f, "Entry is not unique.")
|
GeoffreyDBError::NotUnique => write!(f, "Entry is not unique."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use serde::Serialize;
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
pub mod models;
|
pub mod models;
|
||||||
|
|
||||||
|
@ -31,4 +31,3 @@ pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned {
|
||||||
serde_json::from_slice(b)
|
serde_json::from_slice(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub struct Item {
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn new(name: &str) -> Self {
|
pub fn new(name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string()
|
name: name.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,18 @@ pub struct ItemListing {
|
||||||
pub item: Item,
|
pub item: Item,
|
||||||
pub price: u32,
|
pub price: u32,
|
||||||
pub count_per_price: u32,
|
pub count_per_price: u32,
|
||||||
pub restocked_time: DateTime<Utc>
|
pub restocked_time: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemListing {
|
impl ItemListing {
|
||||||
fn new(item: &str, price: u32, count_per_price: u32, restocked_time: DateTime<Utc>) -> Self {
|
fn new(item: &str, price: u32, count_per_price: u32, restocked_time: DateTime<Utc>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
item: Item {name: item.to_string()},
|
item: Item {
|
||||||
|
name: item.to_string(),
|
||||||
|
},
|
||||||
price,
|
price,
|
||||||
count_per_price,
|
count_per_price,
|
||||||
restocked_time,
|
restocked_time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use crate::models::item::Item;
|
use crate::models::item::Item;
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
pub struct FarmData {
|
pub struct FarmData {
|
||||||
id: Option<u64>,
|
id: Option<u64>,
|
||||||
pub items_produced: HashSet<Item>
|
pub items_produced: HashSet<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeoffreyDatabaseModel for FarmData {
|
impl GeoffreyDatabaseModel for FarmData {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
pub struct Market {
|
pub struct Market {
|
||||||
pub id: Option<u64>,
|
pub id: Option<u64>,
|
||||||
pub shops: HashSet<u64>
|
pub shops: HashSet<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeoffreyDatabaseModel for Market {
|
impl GeoffreyDatabaseModel for Market {
|
||||||
|
@ -21,4 +21,3 @@ impl GeoffreyDatabaseModel for Market {
|
||||||
"market".to_string()
|
"market".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
|
||||||
use crate::models::{Position, Tunnel};
|
use crate::models::{Position, Tunnel};
|
||||||
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
|
||||||
pub mod farm;
|
pub mod farm;
|
||||||
pub mod market;
|
pub mod market;
|
||||||
pub mod shop;
|
pub mod shop;
|
||||||
pub mod town;
|
pub mod town;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub enum LocationType {
|
pub enum LocationType {
|
||||||
Base,
|
Base,
|
||||||
|
@ -27,11 +26,17 @@ pub struct Location {
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
owners: HashSet<u64>,
|
owners: HashSet<u64>,
|
||||||
pub tunnel: Option<Tunnel>,
|
pub tunnel: Option<Tunnel>,
|
||||||
loc_type: LocationType
|
loc_type: LocationType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Location {
|
impl Location {
|
||||||
pub fn new (name: &str, position: Position, owner: u64, tunnel: Option<Tunnel>, loc_type: LocationType) -> Self {
|
pub fn new(
|
||||||
|
name: &str,
|
||||||
|
position: Position,
|
||||||
|
owner: u64,
|
||||||
|
tunnel: Option<Tunnel>,
|
||||||
|
loc_type: LocationType,
|
||||||
|
) -> Self {
|
||||||
let mut owners = HashSet::new();
|
let mut owners = HashSet::new();
|
||||||
owners.insert(owner);
|
owners.insert(owner);
|
||||||
|
|
||||||
|
@ -41,19 +46,19 @@ impl Location {
|
||||||
position,
|
position,
|
||||||
owners,
|
owners,
|
||||||
tunnel,
|
tunnel,
|
||||||
loc_type
|
loc_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn owners(&self) -> Vec<u64> {
|
pub fn owners(&self) -> Vec<u64> {
|
||||||
self.owners.iter().cloned().collect()
|
self.owners.iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_owner(&mut self, owner: u64) {
|
pub fn add_owner(&mut self, owner: u64) {
|
||||||
self.owners.insert(owner);
|
self.owners.insert(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_owner(&mut self, owner: u64) {
|
pub fn remove_owner(&mut self, owner: u64) {
|
||||||
self.owners.remove(&owner);
|
self.owners.remove(&owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,19 +83,43 @@ impl GeoffreyDatabaseModel for Location {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::GeoffreyDatabaseModel;
|
|
||||||
use crate::models::locations::{Location, LocationType};
|
use crate::models::locations::{Location, LocationType};
|
||||||
use crate::models::{Position, Dimension};
|
use crate::models::{Dimension, Position};
|
||||||
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_location_check_unique() {
|
fn test_location_check_unique() {
|
||||||
let l1 = Location::new("Test", Position::new(0, 0, Dimension::Overworld), 0u64, None, LocationType::Base);
|
let l1 = Location::new(
|
||||||
let l2 = Location::new("NotTest", Position::new(0, 0, Dimension::Overworld), 0u64, None, LocationType::Base);
|
"Test",
|
||||||
|
Position::new(0, 0, Dimension::Overworld),
|
||||||
|
0u64,
|
||||||
|
None,
|
||||||
|
LocationType::Base,
|
||||||
|
);
|
||||||
|
let l2 = Location::new(
|
||||||
|
"NotTest",
|
||||||
|
Position::new(0, 0, Dimension::Overworld),
|
||||||
|
0u64,
|
||||||
|
None,
|
||||||
|
LocationType::Base,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(l1.check_unique(&l2));
|
assert!(l1.check_unique(&l2));
|
||||||
|
|
||||||
let l1 = Location::new("Test", Position::new(0, 0, Dimension::Overworld), 0u64, None, LocationType::Base);
|
let l1 = Location::new(
|
||||||
let l2 = Location::new("teSt", Position::new(0, 0, Dimension::Overworld), 0u64, None, LocationType::Base);
|
"Test",
|
||||||
|
Position::new(0, 0, Dimension::Overworld),
|
||||||
|
0u64,
|
||||||
|
None,
|
||||||
|
LocationType::Base,
|
||||||
|
);
|
||||||
|
let l2 = Location::new(
|
||||||
|
"teSt",
|
||||||
|
Position::new(0, 0, Dimension::Overworld),
|
||||||
|
0u64,
|
||||||
|
None,
|
||||||
|
LocationType::Base,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(!l1.check_unique(&l2));
|
assert!(!l1.check_unique(&l2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
|
||||||
use crate::models::item::ItemListing;
|
use crate::models::item::ItemListing;
|
||||||
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Shop {
|
pub struct Shop {
|
||||||
|
@ -24,4 +24,3 @@ impl GeoffreyDatabaseModel for Shop {
|
||||||
"shop".to_string()
|
"shop".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
pub struct Town {
|
pub struct Town {
|
||||||
id: Option<u64>,
|
id: Option<u64>,
|
||||||
pub residents: HashSet<u64>
|
pub residents: HashSet<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeoffreyDatabaseModel for Town {
|
impl GeoffreyDatabaseModel for Town {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Meta {
|
struct Meta {
|
||||||
|
@ -20,4 +20,4 @@ impl GeoffreyDatabaseModel for Meta {
|
||||||
fn tree() -> String {
|
fn tree() -> String {
|
||||||
"meta".to_string()
|
"meta".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod player;
|
|
||||||
pub mod item;
|
pub mod item;
|
||||||
pub mod token;
|
|
||||||
pub mod meta;
|
|
||||||
pub mod locations;
|
pub mod locations;
|
||||||
|
pub mod meta;
|
||||||
|
pub mod parameters;
|
||||||
|
pub mod player;
|
||||||
|
pub mod response;
|
||||||
|
pub mod token;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
pub enum Dimension {
|
pub enum Dimension {
|
||||||
Overworld,
|
Overworld,
|
||||||
Nether,
|
Nether,
|
||||||
TheEnd
|
TheEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Dimension {
|
impl Default for Dimension {
|
||||||
|
@ -36,17 +38,19 @@ pub struct Position {
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
pub fn new(x: i32, y: i32, dimension: Dimension) -> Self {
|
pub fn new(x: i32, y: i32, dimension: Dimension) -> Self {
|
||||||
Self {
|
Self { x, y, dimension }
|
||||||
x,
|
|
||||||
y,
|
|
||||||
dimension
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Tunnel {
|
pub struct Tunnel {
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
number: i32
|
number: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
|
||||||
|
pub enum CommandLevel {
|
||||||
|
ALL = 0,
|
||||||
|
REGISTERED = 1,
|
||||||
|
ADMIN = 2,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::models::locations::LocationType;
|
||||||
|
use crate::models::{Position, Tunnel};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct AddLocationParams {
|
||||||
|
pub name: String,
|
||||||
|
pub position: Position,
|
||||||
|
pub loc_type: LocationType,
|
||||||
|
pub tunnel: Option<Tunnel>,
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct FindParams {
|
||||||
|
pub query: String,
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
pub mod add_location_params;
|
||||||
|
pub mod find_params;
|
||||||
|
pub mod register_params;
|
||||||
|
|
||||||
|
use crate::models::player::{Player, UserID};
|
||||||
|
use crate::models::token::{Permissions, Token};
|
||||||
|
use crate::models::CommandLevel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct CommandRequest<T> {
|
||||||
|
pub user: Option<UserID>,
|
||||||
|
pub arguments: T,
|
||||||
|
pub token: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CommandRequest<T> {
|
||||||
|
fn has_user_id(&self) -> bool {
|
||||||
|
self.user.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_permission(
|
||||||
|
&self,
|
||||||
|
player: &Player,
|
||||||
|
command_level: &CommandLevel,
|
||||||
|
token: &Token,
|
||||||
|
) -> bool {
|
||||||
|
if player.auth_level >= *command_level {
|
||||||
|
if *command_level == CommandLevel::ADMIN {
|
||||||
|
token.check_permission(Permissions::Admin)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
use crate::models::player::UserID;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct RegisterParameters {
|
||||||
|
pub username: String,
|
||||||
|
pub user_id: UserID,
|
||||||
|
}
|
|
@ -1,17 +1,19 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use crate::models::CommandLevel;
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum UserID {
|
pub enum UserID {
|
||||||
DiscordUUID(u64),
|
DiscordUUID { discord_uuid: u64 },
|
||||||
MinecraftUUID(String),
|
MinecraftUUID { mc_uuid: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub id: Option<u64>,
|
pub id: Option<u64>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub user_ids: Vec<UserID>
|
pub user_ids: Vec<UserID>,
|
||||||
|
pub auth_level: CommandLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
|
@ -19,9 +21,14 @@ impl Player {
|
||||||
Self {
|
Self {
|
||||||
id: None,
|
id: None,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
user_ids: vec![user_id]
|
user_ids: vec![user_id],
|
||||||
|
auth_level: CommandLevel::REGISTERED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_user_id(&self, user_id: &UserID) -> bool {
|
||||||
|
self.user_ids.iter().any(|id| id == user_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeoffreyDatabaseModel for Player {
|
impl GeoffreyDatabaseModel for Player {
|
||||||
|
@ -66,4 +73,4 @@ mod tests {
|
||||||
|
|
||||||
assert!(!p1.check_unique(&p2));
|
assert!(!p1.check_unique(&p2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum GeoffreyAPIError {
|
||||||
|
PlayerNotFound,
|
||||||
|
LocationNotFound,
|
||||||
|
PermissionInsufficient,
|
||||||
|
DatabaseError(String),
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
use crate::models::response::api_error::GeoffreyAPIError;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub mod api_error;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum APIResponse<T> {
|
||||||
|
Response(T),
|
||||||
|
Error(GeoffreyAPIError),
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use crate::GeoffreyDatabaseModel;
|
use crate::GeoffreyDatabaseModel;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub enum Permissions {
|
pub enum Permissions {
|
||||||
ModelGet = 0,
|
ModelGet = 0,
|
||||||
|
@ -11,29 +11,20 @@ pub enum Permissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Token {
|
pub struct Token {
|
||||||
pub id: Option<u64>,
|
pub id: Option<u64>,
|
||||||
permission: u64,
|
permission: u64,
|
||||||
pub created: DateTime<Utc>,
|
pub created: DateTime<Utc>,
|
||||||
pub modified: DateTime<Utc>
|
pub modified: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
id: None,
|
|
||||||
permission: 0,
|
|
||||||
created: Utc::now(),
|
|
||||||
modified: Utc::now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_permission(&mut self, permission: Permissions) {
|
pub fn set_permission(&mut self, permission: Permissions) {
|
||||||
self.permission = self.permission | (1u64 << permission as u32);
|
self.permission |= 1u64 << permission as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_permission(&mut self, permission: Permissions) {
|
pub fn clear_permission(&mut self, permission: Permissions) {
|
||||||
self.permission = self.permission & !(1u64 << permission as u32);
|
self.permission &= !(1u64 << permission as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_permission(&self, permission: Permissions) -> bool {
|
pub fn check_permission(&self, permission: Permissions) -> bool {
|
||||||
|
@ -45,6 +36,17 @@ impl Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Token {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
id: None,
|
||||||
|
permission: 0,
|
||||||
|
created: Utc::now(),
|
||||||
|
modified: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GeoffreyDatabaseModel for Token {
|
impl GeoffreyDatabaseModel for Token {
|
||||||
fn id(&self) -> Option<u64> {
|
fn id(&self) -> Option<u64> {
|
||||||
self.id
|
self.id
|
||||||
|
@ -67,18 +69,16 @@ impl PartialEq for Token {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::token::{Token, Permissions};
|
use crate::models::token::{Permissions, Token};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_token() {
|
fn test_token() {
|
||||||
let mut token = Token::new();
|
let mut token = Token::default();
|
||||||
|
|
||||||
token.set_permission(Permissions::ModelGet);
|
token.set_permission(Permissions::ModelGet);
|
||||||
assert_eq!(token.permission, 0x1u64);
|
assert_eq!(token.permission, 0x1u64);
|
||||||
|
|
||||||
token.set_permission(Permissions::ModelPost);
|
token.set_permission(Permissions::ModelPost);
|
||||||
assert_eq!(token.permission, 0x3u64);
|
assert_eq!(token.permission, 0x3u64);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue