use crate as odoo_api;
use crate::jsonrpc::{OdooApiMethod, OdooId};
use odoo_api_macros::odoo_api;
use serde::ser::SerializeTuple;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use serde_tuple::Serialize_tuple;
#[odoo_api(
service = "common",
method = "login",
name = "common_login",
auth = true
)]
#[derive(Debug, Serialize_tuple)]
pub struct Login {
pub db: String,
pub login: String,
pub password: String,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LoginResponse {
pub uid: OdooId,
}
#[odoo_api(
service = "common",
method = "authenticate",
name = "common_authenticate",
auth = true
)]
#[derive(Debug, Serialize_tuple)]
pub struct Authenticate {
pub db: String,
pub login: String,
pub password: String,
pub user_agent_env: Map<String, Value>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct AuthenticateResponse {
pub uid: OdooId,
}
#[odoo_api(
service = "common",
method = "version",
name = "common_version",
auth = false
)]
#[derive(Debug)]
pub struct Version {}
impl Serialize for Version {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let state = serializer.serialize_tuple(0)?;
state.end()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VersionResponse {
pub server_version: String,
pub server_version_info: ServerVersionInfo,
pub server_serie: String,
pub protocol_version: u32,
}
#[derive(Debug, Serialize_tuple, Deserialize)]
pub struct ServerVersionInfo {
pub major: u32,
pub minor: u32,
pub micro: u32,
pub release_level: String,
pub serial: u32,
pub enterprise: Option<String>,
}
#[odoo_api(
service = "common",
method = "about",
name = "common_about",
auth = false
)]
#[derive(Debug, Serialize_tuple)]
pub struct About {
pub extended: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AboutResponse {
Basic(AboutResponseBasic),
Extended(AboutResponseExtended),
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct AboutResponseBasic {
pub info: String,
}
#[derive(Debug, Serialize_tuple, Deserialize)]
pub struct AboutResponseExtended {
pub info: String,
pub server_version: String,
}
#[cfg(test)]
mod test {
use super::*;
use crate::client::error::Result;
use crate::jmap;
use crate::jsonrpc::{JsonRpcParams, JsonRpcResponse};
use serde_json::{from_value, json, to_value};
#[test]
fn login() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "common",
"method": "login",
"args": [
"some-database",
"admin",
"password",
]
}
});
let actual = to_value(
Login {
db: "some-database".into(),
login: "admin".into(),
password: "password".into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn login_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": 2
});
let response: JsonRpcResponse<LoginResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn authenticate() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "common",
"method": "authenticate",
"args": [
"some-database",
"admin",
"password",
{
"base_location": "https://demo.odoo.com"
}
]
}
});
let actual = to_value(
Authenticate {
db: "some-database".into(),
login: "admin".into(),
password: "password".into(),
user_agent_env: jmap! {
"base_location": "https://demo.odoo.com"
},
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn authenticate_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": 2
});
let response: JsonRpcResponse<AuthenticateResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn version() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "common",
"method": "version",
"args": []
}
});
let actual = to_value(Version {}.build(1000))?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn version_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": {
"server_version": "14.0+e",
"server_version_info": [
14,
0,
0,
"final",
0,
"e"
],
"server_serie": "14.0",
"protocol_version": 1
}
});
let response: JsonRpcResponse<VersionResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn about_basic() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "common",
"method": "about",
"args": [
false
]
}
});
let actual = to_value(About { extended: false }.build(1000))?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn about_basic_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": "See http://openerp.com"
});
let response: JsonRpcResponse<AboutResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(data) => match data.result {
AboutResponse::Basic(_) => Ok(()),
AboutResponse::Extended(_) => {
panic!("Expected the `Basic` response, but got `Extended`")
}
},
}
}
#[test]
fn about_extended() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "common",
"method": "about",
"args": [
true
]
}
});
let actual = to_value(About { extended: true }.build(1000))?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn about_extended_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
"See http://openerp.com",
"14.0+e"
]
});
let response: JsonRpcResponse<AboutResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(data) => match data.result {
AboutResponse::Extended(_) => Ok(()),
AboutResponse::Basic(_) => {
panic!("Expected the `Extended` response, but got `Basic`")
}
},
}
}
}