fix
This commit is contained in:
Generated
+2
@@ -1196,7 +1196,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"che-orm",
|
||||
"che-tauri",
|
||||
"jni",
|
||||
"reqwest",
|
||||
"rustls-platform-verifier",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
|
||||
@@ -27,3 +27,5 @@ serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
reqwest = { version = "0.13", default-features = false, features = ["json", "query", "rustls"] }
|
||||
jni = "0.21"
|
||||
rustls-platform-verifier = "0.6"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import java.util.Properties
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
@@ -53,11 +54,19 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = uri(rustlsPlatformVerifierMavenDir())
|
||||
metadataSources.artifact()
|
||||
}
|
||||
}
|
||||
|
||||
rust {
|
||||
rootDirRel = "../../../"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("rustls:rustls-platform-verifier:latest.release")
|
||||
implementation("androidx.webkit:webkit:1.14.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||
@@ -68,4 +77,28 @@ dependencies {
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||
}
|
||||
|
||||
apply(from = "tauri.build.gradle.kts")
|
||||
apply(from = "tauri.build.gradle.kts")
|
||||
|
||||
fun rustlsPlatformVerifierMavenDir(): String {
|
||||
val manifestPath = providers.exec {
|
||||
commandLine(
|
||||
"cargo",
|
||||
"metadata",
|
||||
"--format-version",
|
||||
"1",
|
||||
"--filter-platform",
|
||||
"aarch64-linux-android",
|
||||
"--manifest-path",
|
||||
rootProject.file("../../Cargo.toml").absolutePath,
|
||||
)
|
||||
}.standardOutput.asText.get()
|
||||
|
||||
val metadata = JsonSlurper().parseText(manifestPath) as Map<*, *>
|
||||
val packages = metadata["packages"] as List<*>
|
||||
val rustlsAndroidPackage = packages
|
||||
.map { it as Map<*, *> }
|
||||
.first { it["name"] == "rustls-platform-verifier-android" }
|
||||
val rustlsManifest = file(rustlsAndroidPackage["manifest_path"] as String)
|
||||
|
||||
return File(rustlsManifest.parentFile, "maven").path
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
package com.che.ewa_mobile
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
|
||||
class MainActivity : TauriActivity() {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("ewa_mobile_lib")
|
||||
}
|
||||
|
||||
@JvmStatic external fun initRustlsPlatformVerifier(context: Context)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
initRustlsPlatformVerifier(applicationContext)
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
use che_tauri::{Filter, FilterSet};
|
||||
|
||||
use super::models::{Memo, MemoCategory};
|
||||
|
||||
static MEMO_FILTERS: &[Filter] = &[
|
||||
Filter::exact("id"),
|
||||
Filter::contains("text"),
|
||||
Filter::exact("date"),
|
||||
Filter::exact("priority"),
|
||||
Filter::exact("archive"),
|
||||
Filter::exact("cancel"),
|
||||
Filter::exact_source("recipient", "recipient_id").remote("recipient"),
|
||||
Filter::exact_source("sender", "sender_id").remote("sender"),
|
||||
Filter::exact_source("category", "category_id").remote("category"),
|
||||
Filter::exact_source("project", "project_id").remote("project"),
|
||||
];
|
||||
|
||||
static MEMO_CATEGORY_FILTERS: &[Filter] = &[
|
||||
Filter::exact("id"),
|
||||
Filter::exact("name"),
|
||||
Filter::contains("name"),
|
||||
Filter::exact("code"),
|
||||
];
|
||||
|
||||
pub fn memo_filterset() -> FilterSet<Memo> {
|
||||
FilterSet::new(MEMO_FILTERS).remote_ordering("order_by")
|
||||
}
|
||||
|
||||
pub fn memo_category_filterset() -> FilterSet<MemoCategory> {
|
||||
FilterSet::new(MEMO_CATEGORY_FILTERS).remote_ordering("order_by")
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
pub mod filters;
|
||||
pub mod models;
|
||||
pub mod serializers;
|
||||
|
||||
use che_tauri::{AppModule, ModuleContext};
|
||||
|
||||
pub fn module() -> InternalmemoappModule {
|
||||
InternalmemoappModule
|
||||
}
|
||||
|
||||
pub struct InternalmemoappModule;
|
||||
|
||||
impl AppModule for InternalmemoappModule {
|
||||
fn name(&self) -> &'static str {
|
||||
"internalmemoapp"
|
||||
}
|
||||
|
||||
fn init(&self, ctx: &mut ModuleContext) {
|
||||
ctx.mapped_remote_resource::<models::Memo>(
|
||||
"memo",
|
||||
"/api/internalmemo/memo/",
|
||||
serializers::memo_serializer(),
|
||||
filters::memo_filterset(),
|
||||
);
|
||||
ctx.mapped_remote_resource::<models::MemoCategory>(
|
||||
"memo_category",
|
||||
"/api/internalmemo/category/",
|
||||
serializers::memo_category_serializer(),
|
||||
filters::memo_category_filterset(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use che_orm::Model;
|
||||
|
||||
use crate::apps::{personemanagment::models::Employee, projectapp::models::Project};
|
||||
|
||||
#[derive(Debug, Clone, Model)]
|
||||
#[model(table = "internal_memo")]
|
||||
pub struct Memo {
|
||||
#[field(primary_key)]
|
||||
pub id: i64,
|
||||
|
||||
#[field(foreign_key = Employee)]
|
||||
pub recipient_id: Option<i64>,
|
||||
|
||||
#[field(foreign_key = Employee)]
|
||||
pub sender_id: Option<i64>,
|
||||
|
||||
#[field(foreign_key = MemoCategory)]
|
||||
pub category_id: Option<i64>,
|
||||
|
||||
#[field(foreign_key = Project)]
|
||||
pub project_id: Option<i64>,
|
||||
|
||||
pub task_set: Option<String>,
|
||||
pub priority_display: String,
|
||||
pub absolute_url: String,
|
||||
pub date: String,
|
||||
pub my_approve: String,
|
||||
pub text: String,
|
||||
pub resalution: String,
|
||||
pub priority: String,
|
||||
pub archive: bool,
|
||||
pub cancel: bool,
|
||||
pub date_start: Option<String>,
|
||||
pub date_end: Option<String>,
|
||||
pub value: f64,
|
||||
pub archive_s: bool,
|
||||
pub current_step: i64,
|
||||
pub subject: Option<String>,
|
||||
pub employee_acl: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Model)]
|
||||
#[model(table = "internal_memo_category")]
|
||||
pub struct MemoCategory {
|
||||
#[field(primary_key)]
|
||||
pub id: i64,
|
||||
|
||||
pub name: String,
|
||||
pub template: String,
|
||||
pub template_text: String,
|
||||
pub code: String,
|
||||
pub in_month_limit: bool,
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
use che_tauri::{Field, ModelSerializer, RelatedModel};
|
||||
|
||||
use crate::apps::{
|
||||
personemanagment::{models::Employee, serializers::employee_serializer},
|
||||
projectapp::{models::Project, serializers::project_serializer},
|
||||
};
|
||||
|
||||
use super::models::{Memo, MemoCategory};
|
||||
|
||||
static MEMO_FIELDS: &[Field] = &[
|
||||
Field::new("id").read_only(),
|
||||
Field::new("recipient_id")
|
||||
.source("recipient")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::new("sender_id")
|
||||
.source("sender")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::new("category_id")
|
||||
.source("category")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::new("project_id")
|
||||
.source("project")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::json("task_set")
|
||||
.ts_type("unknown[]")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::new("priority_display").source("get_priority_display"),
|
||||
Field::new("absolute_url").source("get_absolute_url"),
|
||||
Field::new("date"),
|
||||
Field::new("my_approve"),
|
||||
Field::new("text"),
|
||||
Field::new("resalution"),
|
||||
Field::new("priority"),
|
||||
Field::new("archive"),
|
||||
Field::new("cancel"),
|
||||
Field::new("date_start").required(false).nullable(),
|
||||
Field::new("date_end").required(false).nullable(),
|
||||
Field::new("value"),
|
||||
Field::new("archive_s"),
|
||||
Field::new("current_step"),
|
||||
Field::json("subject")
|
||||
.ts_type("number[]")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::json("employee_acl")
|
||||
.ts_type("number[]")
|
||||
.required(false)
|
||||
.nullable(),
|
||||
Field::related("recipient", "recipient_id", &EMPLOYEE_RELATION),
|
||||
Field::related("sender", "sender_id", &EMPLOYEE_RELATION),
|
||||
Field::related("category", "category_id", &MEMO_CATEGORY_RELATION),
|
||||
Field::related("project", "project_id", &PROJECT_RELATION),
|
||||
];
|
||||
|
||||
static MEMO_CATEGORY_FIELDS: &[Field] = &[
|
||||
Field::new("id").read_only(),
|
||||
Field::new("name"),
|
||||
Field::new("template"),
|
||||
Field::new("template_text"),
|
||||
Field::new("code"),
|
||||
Field::new("in_month_limit"),
|
||||
];
|
||||
|
||||
static EMPLOYEE_RELATION: RelatedModel<Employee> = RelatedModel::new(employee_serializer);
|
||||
static PROJECT_RELATION: RelatedModel<Project> = RelatedModel::new(project_serializer);
|
||||
static MEMO_CATEGORY_RELATION: RelatedModel<MemoCategory> =
|
||||
RelatedModel::new(memo_category_serializer);
|
||||
|
||||
pub fn memo_serializer() -> ModelSerializer<Memo> {
|
||||
ModelSerializer::new(MEMO_FIELDS)
|
||||
}
|
||||
|
||||
pub fn memo_category_serializer() -> ModelSerializer<MemoCategory> {
|
||||
ModelSerializer::new(MEMO_CATEGORY_FIELDS)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod frcapp;
|
||||
pub mod internalmemoapp;
|
||||
pub mod personemanagment;
|
||||
pub mod projectapp;
|
||||
pub mod supplyapp;
|
||||
@@ -14,5 +15,6 @@ pub fn installed_apps() -> InstalledApps {
|
||||
.add(personemanagment::module())
|
||||
.add(contractapp::module())
|
||||
.add(supplyapp::module())
|
||||
.add(internalmemoapp::module())
|
||||
}
|
||||
pub mod contractapp;
|
||||
|
||||
@@ -15,6 +15,7 @@ static TASK_FILTERS: &[Filter] = &[
|
||||
Filter::contains("text"),
|
||||
Filter::remote_only("contract"),
|
||||
Filter::remote_only("bill"),
|
||||
Filter::remote_only("memo"),
|
||||
Filter::remote_only("doer"),
|
||||
Filter::remote_only("author"),
|
||||
Filter::exact("archive"),
|
||||
|
||||
+26
-3
@@ -1,7 +1,10 @@
|
||||
pub mod apps;
|
||||
pub mod sync;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use che_orm::SqliteBackend;
|
||||
use che_tauri::{
|
||||
@@ -13,6 +16,18 @@ use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
use crate::sync::SyncContractsResult;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_com_che_ewa_1mobile_MainActivity_initRustlsPlatformVerifier(
|
||||
mut env: jni::JNIEnv,
|
||||
_class: jni::objects::JClass,
|
||||
context: jni::objects::JObject,
|
||||
) {
|
||||
if let Err(error) = rustls_platform_verifier::android::init_with_env(&mut env, context) {
|
||||
eprintln!("failed to initialize rustls platform verifier: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
const REMOTE_BASE_URL: &str = "http://10.0.2.2:8000";
|
||||
|
||||
@@ -89,6 +104,14 @@ fn validate_settings(settings: &AppSettings) -> Result<(), ApiError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn remote_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(15))
|
||||
.connect_timeout(Duration::from_secs(5))
|
||||
.build()
|
||||
.expect("failed to build reqwest client")
|
||||
}
|
||||
|
||||
fn settings_path(app_data_dir: &Path) -> PathBuf {
|
||||
app_data_dir.join("settings.json")
|
||||
}
|
||||
@@ -219,7 +242,7 @@ async fn current_employee(api: tauri::State<'_, TauriApi>) -> Result<CurrentEmpl
|
||||
.auth_token()
|
||||
.ok_or_else(|| ApiError::new("not_authenticated", "authentication token is missing"))?;
|
||||
|
||||
let response = reqwest::Client::new()
|
||||
let response = remote_http_client()
|
||||
.get(format!(
|
||||
"{}/api/persone/employee/who_im/",
|
||||
remote.base_url.trim_end_matches('/')
|
||||
@@ -322,7 +345,7 @@ async fn cache_remote_file(
|
||||
.auth_token()
|
||||
.ok_or_else(|| ApiError::new("not_authenticated", "authentication token is missing"))?;
|
||||
|
||||
let response = reqwest::Client::new()
|
||||
let response = remote_http_client()
|
||||
.get(file_url)
|
||||
.header(reqwest::header::AUTHORIZATION, format!("Token {token}"))
|
||||
.send()
|
||||
|
||||
@@ -4,6 +4,8 @@ use che_orm::__private::sqlx;
|
||||
use che_tauri::{ApiError, TauriApi};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::remote_http_client;
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct SyncContractsResult {
|
||||
pub synced: usize,
|
||||
@@ -167,7 +169,7 @@ pub async fn sync_contracts(
|
||||
let remote = state
|
||||
.remote_config()
|
||||
.ok_or_else(|| ApiError::bad_request("sync requires [remote].base_url config"))?;
|
||||
let client = reqwest::Client::new();
|
||||
let client = remote_http_client();
|
||||
sync_contract_categories(api, &client, &token, &remote.base_url).await?;
|
||||
|
||||
let mut next_url = Some(format!(
|
||||
|
||||
Reference in New Issue
Block a user