diff --git a/.sqlx/query-18495d6198079fdb8e4806d8a59aa0a1abee44a8b568ce74fa275ab936e8362f.json b/.sqlx/query-18495d6198079fdb8e4806d8a59aa0a1abee44a8b568ce74fa275ab936e8362f.json
new file mode 100644
index 0000000..1125f1f
--- /dev/null
+++ b/.sqlx/query-18495d6198079fdb8e4806d8a59aa0a1abee44a8b568ce74fa275ab936e8362f.json
@@ -0,0 +1,16 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n UPDATE\n survey_mcaptcha_upload_jobs\n SET\n job_state = (SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $1),\n scheduled_at = $2\n WHERE public_id = $3;",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Timestamptz",
+ "Text"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "18495d6198079fdb8e4806d8a59aa0a1abee44a8b568ce74fa275ab936e8362f"
+}
diff --git a/.sqlx/query-1e41c42d89762ff4dc4b60a534a54db2741b325727c01852cbc68ea8442d15ef.json b/.sqlx/query-1e41c42d89762ff4dc4b60a534a54db2741b325727c01852cbc68ea8442d15ef.json
new file mode 100644
index 0000000..a285802
--- /dev/null
+++ b/.sqlx/query-1e41c42d89762ff4dc4b60a534a54db2741b325727c01852cbc68ea8442d15ef.json
@@ -0,0 +1,64 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n survey_mcaptcha_upload_jobs.ID,\n survey_mcaptcha_upload_jobs.public_id,\n survey_mcaptcha_campaign.campaign_id,\n survey_mcaptcha_campaign.public_id as campaign_public_id,\n survey_mcaptcha_upload_job_states.name,\n survey_mcaptcha_upload_jobs.created_at,\n survey_mcaptcha_upload_jobs.scheduled_at,\n survey_mcaptcha_upload_jobs.finished_at\n\n FROM survey_mcaptcha_upload_jobs\n INNER JOIN\n survey_mcaptcha_upload_job_states\n ON\n survey_mcaptcha_upload_job_states.ID = survey_mcaptcha_upload_jobs.job_state\n INNER JOIN\n survey_mcaptcha_campaign\n ON\n survey_mcaptcha_campaign.ID = survey_mcaptcha_upload_jobs.campaign_id\n WHERE\n survey_mcaptcha_upload_job_states.name = $1;",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 1,
+ "name": "public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "campaign_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "campaign_public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 4,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "scheduled_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "finished_at",
+ "type_info": "Timestamptz"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true
+ ]
+ },
+ "hash": "1e41c42d89762ff4dc4b60a534a54db2741b325727c01852cbc68ea8442d15ef"
+}
diff --git a/.sqlx/query-4237df28c12e17ca68a1e1b33ae80ce5a4a8dff6d0795f277fb18b7b40dc69ef.json b/.sqlx/query-4237df28c12e17ca68a1e1b33ae80ce5a4a8dff6d0795f277fb18b7b40dc69ef.json
deleted file mode 100644
index cf0ca95..0000000
--- a/.sqlx/query-4237df28c12e17ca68a1e1b33ae80ce5a4a8dff6d0795f277fb18b7b40dc69ef.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "SELECT\n campaign_id\n FROM\n survey_mcaptcha_campaign\n WHERE ID = (\n SELECT\n campaign_id\n FROM\n survey_mcaptcha_upload_jobs\n WHERE\n job_state = (SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $1)\n AND\n finished_at is NULL\n AND\n scheduled_at is NULL\n ORDER BY created_at ASC\n );",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "campaign_id",
- "type_info": "Varchar"
- }
- ],
- "parameters": {
- "Left": [
- "Text"
- ]
- },
- "nullable": [
- false
- ]
- },
- "hash": "4237df28c12e17ca68a1e1b33ae80ce5a4a8dff6d0795f277fb18b7b40dc69ef"
-}
diff --git a/.sqlx/query-722f2d297a318f9804c1388d427d069a315b45c0c85c0b344d34cd8928b22c9c.json b/.sqlx/query-722f2d297a318f9804c1388d427d069a315b45c0c85c0b344d34cd8928b22c9c.json
new file mode 100644
index 0000000..b7a9262
--- /dev/null
+++ b/.sqlx/query-722f2d297a318f9804c1388d427d069a315b45c0c85c0b344d34cd8928b22c9c.json
@@ -0,0 +1,64 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n survey_mcaptcha_upload_jobs.ID,\n survey_mcaptcha_upload_jobs.public_id,\n survey_mcaptcha_campaign.campaign_id,\n survey_mcaptcha_campaign.public_id as campaign_public_id,\n survey_mcaptcha_upload_job_states.name,\n survey_mcaptcha_upload_jobs.created_at,\n survey_mcaptcha_upload_jobs.scheduled_at,\n survey_mcaptcha_upload_jobs.finished_at\n\n FROM survey_mcaptcha_upload_jobs\n INNER JOIN\n survey_mcaptcha_upload_job_states\n ON\n survey_mcaptcha_upload_job_states.ID = survey_mcaptcha_upload_jobs.job_state\n INNER JOIN\n survey_mcaptcha_campaign\n ON\n survey_mcaptcha_campaign.ID = survey_mcaptcha_upload_jobs.campaign_id\n WHERE\n survey_mcaptcha_upload_jobs.public_id = $1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 1,
+ "name": "public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "campaign_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "campaign_public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 4,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "scheduled_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "finished_at",
+ "type_info": "Timestamptz"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true
+ ]
+ },
+ "hash": "722f2d297a318f9804c1388d427d069a315b45c0c85c0b344d34cd8928b22c9c"
+}
diff --git a/.sqlx/query-8be51483900058d0bcc4c121440fe551bc57096826119ad914cc1ef2d9ccb79d.json b/.sqlx/query-8be51483900058d0bcc4c121440fe551bc57096826119ad914cc1ef2d9ccb79d.json
new file mode 100644
index 0000000..3987ac3
--- /dev/null
+++ b/.sqlx/query-8be51483900058d0bcc4c121440fe551bc57096826119ad914cc1ef2d9ccb79d.json
@@ -0,0 +1,28 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT\n survey_mcaptcha_campaign.campaign_id,\n survey_mcaptcha_upload_jobs.public_id\n FROM\n survey_mcaptcha_campaign\n INNER JOIN\n survey_mcaptcha_upload_jobs\n ON\n survey_mcaptcha_upload_jobs.campaign_id = survey_mcaptcha_campaign.ID\n WHERE\n survey_mcaptcha_upload_jobs.job_state = (\n SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $1\n )\n AND\n survey_mcaptcha_upload_jobs.finished_at is NULL\n AND\n survey_mcaptcha_upload_jobs.scheduled_at is NULL\n ORDER BY created_at ASC;",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "campaign_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 1,
+ "name": "public_id",
+ "type_info": "Varchar"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text"
+ ]
+ },
+ "nullable": [
+ false,
+ false
+ ]
+ },
+ "hash": "8be51483900058d0bcc4c121440fe551bc57096826119ad914cc1ef2d9ccb79d"
+}
diff --git a/.sqlx/query-ca41f4e15fa5c5657a525ed9385a92214b644194443ae165957d9659d30dc3f9.json b/.sqlx/query-ca41f4e15fa5c5657a525ed9385a92214b644194443ae165957d9659d30dc3f9.json
new file mode 100644
index 0000000..92e330d
--- /dev/null
+++ b/.sqlx/query-ca41f4e15fa5c5657a525ed9385a92214b644194443ae165957d9659d30dc3f9.json
@@ -0,0 +1,65 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n survey_mcaptcha_upload_jobs.ID,\n survey_mcaptcha_upload_jobs.public_id,\n survey_mcaptcha_campaign.campaign_id,\n survey_mcaptcha_campaign.public_id as campaign_public_id,\n survey_mcaptcha_upload_job_states.name,\n survey_mcaptcha_upload_jobs.created_at,\n survey_mcaptcha_upload_jobs.scheduled_at,\n survey_mcaptcha_upload_jobs.finished_at\n\n FROM survey_mcaptcha_upload_jobs\n INNER JOIN\n survey_mcaptcha_upload_job_states\n ON\n survey_mcaptcha_upload_job_states.ID = survey_mcaptcha_upload_jobs.job_state\n INNER JOIN\n survey_mcaptcha_campaign\n ON\n survey_mcaptcha_campaign.ID = survey_mcaptcha_upload_jobs.campaign_id\n WHERE\n survey_mcaptcha_campaign.campaign_id = $1\n AND\n survey_mcaptcha_upload_job_states.name = $2;",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 1,
+ "name": "public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "campaign_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "campaign_public_id",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 4,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "scheduled_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "finished_at",
+ "type_info": "Timestamptz"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Text"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true
+ ]
+ },
+ "hash": "ca41f4e15fa5c5657a525ed9385a92214b644194443ae165957d9659d30dc3f9"
+}
diff --git a/.sqlx/query-ebfc456dd76b3fb2e5484f935703ad6aa4712c782222f2015b92916827f81079.json b/.sqlx/query-ebfc456dd76b3fb2e5484f935703ad6aa4712c782222f2015b92916827f81079.json
new file mode 100644
index 0000000..af67acf
--- /dev/null
+++ b/.sqlx/query-ebfc456dd76b3fb2e5484f935703ad6aa4712c782222f2015b92916827f81079.json
@@ -0,0 +1,17 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "INSERT INTO survey_mcaptcha_upload_jobs\n (campaign_id, job_state, created_at, public_id)\n VALUES (\n (SELECT ID FROM survey_mcaptcha_campaign WHERE campaign_id = $1),\n (SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $2),\n $3, $4)",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Text",
+ "Timestamptz",
+ "Varchar"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "ebfc456dd76b3fb2e5484f935703ad6aa4712c782222f2015b92916827f81079"
+}
diff --git a/.sqlx/query-fade9f99846165c34486f6492ece38148bf0dd2d79e1a4f97b8cbf04015ceff0.json b/.sqlx/query-fade9f99846165c34486f6492ece38148bf0dd2d79e1a4f97b8cbf04015ceff0.json
new file mode 100644
index 0000000..068f3db
--- /dev/null
+++ b/.sqlx/query-fade9f99846165c34486f6492ece38148bf0dd2d79e1a4f97b8cbf04015ceff0.json
@@ -0,0 +1,16 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n UPDATE\n survey_mcaptcha_upload_jobs\n SET\n job_state = (SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $1),\n finished_at = $2\n WHERE public_id = $3;",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Timestamptz",
+ "Text"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "fade9f99846165c34486f6492ece38148bf0dd2d79e1a4f97b8cbf04015ceff0"
+}
diff --git a/src/api/v1/mcaptcha/db.rs b/src/api/v1/mcaptcha/db.rs
index a6315bc..9de3643 100644
--- a/src/api/v1/mcaptcha/db.rs
+++ b/src/api/v1/mcaptcha/db.rs
@@ -15,12 +15,22 @@
* along with this program. If not, see .
*/
use url::Url;
+use uuid::Uuid;
use crate::api::v1::get_random;
+use crate::db::{
+ JobState, JOB_STATES, JOB_STATE_CREATE, JOB_STATE_FINISH, JOB_STATE_RUNNING,
+};
use crate::errors::*;
use crate::mcaptcha::PerformanceAnalytics;
use crate::Data;
+use sqlx::types::time::OffsetDateTime;
+
+fn now_unix_time_stamp() -> OffsetDateTime {
+ OffsetDateTime::now_utc()
+}
+
impl Data {
/// Check if an mCaptcha instance is registered on the database
pub async fn mcaptcha_url_exists(&self, url: &str) -> ServiceResult {
@@ -127,14 +137,14 @@ impl Data {
.await?;
Ok(())
}
- /// Delete mCaptcha camapign from database
+ /// Delete mCaptcha campaign from database
pub async fn mcaptcha_delete_mcaptcha_campaign(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
) -> ServiceResult<()> {
let campaign_str = campaign_id.to_string();
- let res = sqlx::query!(
+ sqlx::query!(
"DELETE FROM
survey_mcaptcha_campaign
WHERE
@@ -160,7 +170,7 @@ impl Data {
/// Check if an mCaptcha instance campaign is registered on DB
pub async fn mcaptcha_campaign_is_registered(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
) -> ServiceResult {
let campaign_str = campaign_id.to_string();
@@ -201,11 +211,11 @@ impl Data {
/// Register an mCaptcha instance campaign on DB
pub async fn mcaptcha_register_campaign(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
) -> ServiceResult<()> {
let campaign_str = campaign_id.to_string();
- let public_id = uuid::Uuid::new_v4();
+ let public_id = Uuid::new_v4();
sqlx::query!(
"INSERT INTO
@@ -223,9 +233,9 @@ impl Data {
/// Register an mCaptcha instance campaign on DB
pub async fn mcaptcha_get_campaign_public_id(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
- ) -> ServiceResult {
+ ) -> ServiceResult {
let campaign_str = campaign_id.to_string();
struct S {
public_id: String,
@@ -247,13 +257,13 @@ impl Data {
.fetch_one(&self.db)
.await?;
- Ok(uuid::Uuid::parse_str(&res.public_id).unwrap())
+ Ok(Uuid::parse_str(&res.public_id).unwrap())
}
/// Get an mCaptcha instance campaign checkpoint
pub async fn mcaptcha_get_checkpoint(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
) -> ServiceResult {
let campaign_str = campaign_id.to_string();
@@ -286,7 +296,7 @@ impl Data {
/// Set an mCaptcha instance campaign checkpoint
pub async fn mcaptcha_set_checkpoint(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
checkpoint: usize,
) -> ServiceResult<()> {
@@ -316,7 +326,7 @@ impl Data {
/// Store mCaptcha instance campaign analytics
pub async fn mcaptcha_insert_analytics(
&self,
- campaign_id: &uuid::Uuid,
+ campaign_id: &Uuid,
secret: &str,
r: &PerformanceAnalytics,
) -> ServiceResult<()> {
@@ -353,7 +363,7 @@ impl Data {
/// fetch PoW analytics
pub async fn mcaptcha_analytics_fetch(
&self,
- public_id: &uuid::Uuid,
+ public_id: &Uuid,
limit: usize,
offset: usize,
) -> ServiceResult> {
@@ -402,12 +412,294 @@ impl Data {
Ok(res)
}
+
+ pub async fn get_next_job_to_run(&self) -> ServiceResult {
+ let res = sqlx::query_as!(
+ InnerSchedulerJob,
+ "SELECT
+ survey_mcaptcha_campaign.campaign_id,
+ survey_mcaptcha_upload_jobs.public_id
+ FROM
+ survey_mcaptcha_campaign
+ INNER JOIN
+ survey_mcaptcha_upload_jobs
+ ON
+ survey_mcaptcha_upload_jobs.campaign_id = survey_mcaptcha_campaign.ID
+ WHERE
+ survey_mcaptcha_upload_jobs.job_state = (
+ SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $1
+ )
+ AND
+ survey_mcaptcha_upload_jobs.finished_at is NULL
+ AND
+ survey_mcaptcha_upload_jobs.scheduled_at is NULL
+ ORDER BY created_at ASC;",
+ &JOB_STATE_CREATE.name
+ )
+ .fetch_one(&self.db)
+ .await?;
+ Ok(res.into())
+ }
+
+ pub async fn add_job(&self, campaign_id: &Uuid) -> ServiceResult {
+ let now = now_unix_time_stamp();
+
+ if let Some(unfinished_job) =
+ self.get_unfinished_job_for_campaign(campaign_id).await?
+ {
+ return Ok(unfinished_job.public_job_id);
+ }
+
+ let public_id = Uuid::new_v4();
+ let public_id_str = public_id.to_string();
+
+ let campaign_str = campaign_id.to_string();
+ sqlx::query!(
+ "INSERT INTO survey_mcaptcha_upload_jobs
+ (campaign_id, job_state, created_at, public_id)
+ VALUES (
+ (SELECT ID FROM survey_mcaptcha_campaign WHERE campaign_id = $1),
+ (SELECT ID FROM survey_mcaptcha_upload_job_states WHERE name = $2),
+ $3, $4)",
+ &campaign_str,
+ &JOB_STATE_CREATE.name,
+ now,
+ public_id_str
+ )
+ .execute(&self.db)
+ .await?;
+ Ok(public_id)
+ }
+
+ pub async fn get_unfinished_job_for_campaign(
+ &self,
+ campaign_id: &Uuid,
+ ) -> ServiceResult