1use std::fmt;
2
3use crate::{
4 certificate_configuration_to_requirements::{
5 CertificateAllRequirements, get_all_requirements_for_certificate_configuration,
6 },
7 prelude::*,
8};
9
10#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, sqlx::Type)]
11#[cfg_attr(feature = "ts_rs", derive(TS))]
12#[serde(rename_all = "kebab-case")]
13#[sqlx(type_name = "certificate_paper_size", rename_all = "kebab-case")]
14pub enum PaperSize {
15 HorizontalA4,
16 VerticalA4,
17}
18
19impl PaperSize {
20 pub fn width_px(&self) -> u32 {
21 match self {
22 PaperSize::HorizontalA4 => 3508,
23 PaperSize::VerticalA4 => 2480,
24 }
25 }
26 pub fn height_px(&self) -> u32 {
27 match self {
28 PaperSize::HorizontalA4 => 2480,
29 PaperSize::VerticalA4 => 3508,
30 }
31 }
32}
33
34#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, sqlx::Type)]
36#[cfg_attr(feature = "ts_rs", derive(TS))]
37#[serde(rename_all = "kebab-case")]
38#[sqlx(type_name = "certificate_text_anchor", rename_all = "kebab-case")]
39pub enum CertificateTextAnchor {
40 Start,
41 Middle,
42 End,
43}
44
45impl fmt::Display for CertificateTextAnchor {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 Self::Start => f.write_str("start"),
49 Self::Middle => f.write_str("middle"),
50 Self::End => f.write_str("end"),
51 }
52 }
53}
54
55#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
56#[cfg_attr(feature = "ts_rs", derive(TS))]
57pub struct CertificateConfigurationAndRequirements {
58 pub certificate_configuration: CertificateConfiguration,
59 pub requirements: CertificateAllRequirements,
60}
61
62#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
63#[cfg_attr(feature = "ts_rs", derive(TS))]
64pub struct CertificateConfiguration {
65 pub id: Uuid,
66 pub created_at: DateTime<Utc>,
67 pub updated_at: DateTime<Utc>,
68 pub deleted_at: Option<DateTime<Utc>>,
69 pub certificate_owner_name_y_pos: String,
70 pub certificate_owner_name_x_pos: String,
71 pub certificate_owner_name_font_size: String,
72 pub certificate_owner_name_text_color: String,
73 pub certificate_owner_name_text_anchor: CertificateTextAnchor,
74 pub certificate_validate_url_y_pos: String,
75 pub certificate_validate_url_x_pos: String,
76 pub certificate_validate_url_font_size: String,
77 pub certificate_validate_url_text_color: String,
78 pub certificate_validate_url_text_anchor: CertificateTextAnchor,
79 pub certificate_date_y_pos: String,
80 pub certificate_date_x_pos: String,
81 pub certificate_date_font_size: String,
82 pub certificate_date_text_color: String,
83 pub certificate_date_text_anchor: CertificateTextAnchor,
84 pub certificate_locale: String,
85 pub paper_size: PaperSize,
86 pub background_svg_path: String,
87 pub background_svg_file_upload_id: Uuid,
88 pub overlay_svg_path: Option<String>,
89 pub overlay_svg_file_upload_id: Option<Uuid>,
90 pub render_certificate_grade: bool,
91 pub certificate_grade_y_pos: Option<String>,
92 pub certificate_grade_x_pos: Option<String>,
93 pub certificate_grade_font_size: Option<String>,
94 pub certificate_grade_text_color: Option<String>,
95 pub certificate_grade_text_anchor: Option<CertificateTextAnchor>,
96}
97
98pub async fn get_required_course_instance_ids(
99 conn: &mut PgConnection,
100 certificate_configuration_id: Uuid,
101) -> ModelResult<Vec<Uuid>> {
102 let res = sqlx::query!(
103 r#"
104SELECT course_instance_id
105FROM certificate_configuration_to_requirements
106WHERE certificate_configuration_id = $1
107 AND deleted_at IS NULL
108 "#,
109 certificate_configuration_id,
110 )
111 .fetch_all(&mut *conn)
112 .await?;
113 Ok(res.iter().filter_map(|r| r.course_instance_id).collect())
114}
115
116pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<CertificateConfiguration> {
117 let res = sqlx::query_as!(
118 CertificateConfiguration,
119 r#"
120SELECT cc.id,
121 cc.created_at,
122 cc.updated_at,
123 cc.deleted_at,
124 cc.certificate_owner_name_y_pos,
125 cc.certificate_owner_name_x_pos,
126 cc.certificate_owner_name_font_size,
127 cc.certificate_owner_name_text_color,
128 cc.certificate_owner_name_text_anchor AS "certificate_owner_name_text_anchor: _",
129 cc.certificate_validate_url_y_pos,
130 cc.certificate_validate_url_x_pos,
131 cc.certificate_validate_url_font_size,
132 cc.certificate_validate_url_text_color,
133 cc.certificate_validate_url_text_anchor AS "certificate_validate_url_text_anchor: _",
134 cc.certificate_date_y_pos,
135 cc.certificate_date_x_pos,
136 cc.certificate_date_font_size,
137 cc.certificate_date_text_color,
138 cc.certificate_date_text_anchor AS "certificate_date_text_anchor: _",
139 cc.certificate_locale,
140 cc.paper_size AS "paper_size: _",
141 cc.background_svg_path,
142 cc.background_svg_file_upload_id,
143 cc.overlay_svg_path,
144 cc.overlay_svg_file_upload_id,
145 cc.render_certificate_grade,
146 cc.certificate_grade_y_pos,
147 cc.certificate_grade_x_pos,
148 cc.certificate_grade_font_size,
149 cc.certificate_grade_text_color,
150 cc.certificate_grade_text_anchor AS "certificate_grade_text_anchor: _"
151FROM certificate_configurations cc
152WHERE id = $1
153 AND cc.deleted_at IS NULL "#,
154 id,
155 )
156 .fetch_one(&mut *conn)
157 .await?;
158 Ok(res)
159}
160
161pub async fn get_default_configuration_by_course_module_and_course_instance(
162 conn: &mut PgConnection,
163 course_module_id: Uuid,
164 course_instance_id: Option<Uuid>,
165) -> ModelResult<CertificateConfiguration> {
166 let all_certificate_configurations = sqlx::query_as!(
167 CertificateConfiguration,
168 r#"
169SELECT cc.id,
170 cc.created_at,
171 cc.updated_at,
172 cc.deleted_at,
173 cc.certificate_owner_name_y_pos,
174 cc.certificate_owner_name_x_pos,
175 cc.certificate_owner_name_font_size,
176 cc.certificate_owner_name_text_color,
177 cc.certificate_owner_name_text_anchor as "certificate_owner_name_text_anchor: _",
178 cc.certificate_validate_url_y_pos,
179 cc.certificate_validate_url_x_pos,
180 cc.certificate_validate_url_font_size,
181 cc.certificate_validate_url_text_color,
182 cc.certificate_validate_url_text_anchor as "certificate_validate_url_text_anchor: _",
183 cc.certificate_date_y_pos,
184 cc.certificate_date_x_pos,
185 cc.certificate_date_font_size,
186 cc.certificate_date_text_color,
187 cc.certificate_date_text_anchor as "certificate_date_text_anchor: _",
188 cc.certificate_locale,
189 cc.paper_size as "paper_size: _",
190 cc.background_svg_path,
191 cc.background_svg_file_upload_id,
192 cc.overlay_svg_path,
193 cc.overlay_svg_file_upload_id,
194 cc.render_certificate_grade,
195 cc.certificate_grade_y_pos,
196 cc.certificate_grade_x_pos,
197 cc.certificate_grade_font_size,
198 cc.certificate_grade_text_color,
199 cc.certificate_grade_text_anchor AS "certificate_grade_text_anchor: _"
200FROM certificate_configurations cc
201JOIN certificate_configuration_to_requirements cctr ON cc.id = cctr.certificate_configuration_id
202WHERE cctr.course_module_id = $1
203 AND cc.deleted_at IS NULL
204 AND cctr.deleted_at IS NULL
205 "#,
206 course_module_id,
207 )
208 .fetch_all(&mut *conn)
209 .await?;
210 if let Some(course_instance_id) = course_instance_id {
211 for certificate_configuration in &all_certificate_configurations {
214 let requirements = get_all_requirements_for_certificate_configuration(
215 conn,
216 certificate_configuration.id,
217 )
218 .await?;
219
220 if requirements.is_default_certificate_configuration()
221 && requirements.course_instance_ids.first() == Some(&course_instance_id)
222 {
223 return Ok(certificate_configuration.clone());
224 }
225 }
226 }
227
228 Err(ModelError::new(
234 ModelErrorType::RecordNotFound,
235 "No certificate configuration found for the course module or the course instance"
236 .to_string(),
237 None,
238 ))
239}
240
241pub async fn get_default_certificate_configurations_and_requirements_by_course_instance(
243 conn: &mut PgConnection,
244 course_instance_id: Uuid,
245) -> ModelResult<Vec<CertificateConfigurationAndRequirements>> {
246 let mut res = Vec::new();
247 let all_certificate_configurations = sqlx::query_as!(
248 CertificateConfiguration,
249 r#"
250SELECT cc.id,
251 cc.created_at,
252 cc.updated_at,
253 cc.deleted_at,
254 cc.certificate_owner_name_y_pos,
255 cc.certificate_owner_name_x_pos,
256 cc.certificate_owner_name_font_size,
257 cc.certificate_owner_name_text_color,
258 cc.certificate_owner_name_text_anchor as "certificate_owner_name_text_anchor: _",
259 cc.certificate_validate_url_y_pos,
260 cc.certificate_validate_url_x_pos,
261 cc.certificate_validate_url_font_size,
262 cc.certificate_validate_url_text_color,
263 cc.certificate_validate_url_text_anchor as "certificate_validate_url_text_anchor: _",
264 cc.certificate_date_y_pos,
265 cc.certificate_date_x_pos,
266 cc.certificate_date_font_size,
267 cc.certificate_date_text_color,
268 cc.certificate_date_text_anchor as "certificate_date_text_anchor: _",
269 cc.certificate_locale,
270 cc.paper_size as "paper_size: _",
271 cc.background_svg_path,
272 cc.background_svg_file_upload_id,
273 cc.overlay_svg_path,
274 cc.overlay_svg_file_upload_id,
275 cc.render_certificate_grade,
276 cc.certificate_grade_y_pos,
277 cc.certificate_grade_x_pos,
278 cc.certificate_grade_font_size,
279 cc.certificate_grade_text_color,
280 cc.certificate_grade_text_anchor AS "certificate_grade_text_anchor: _"
281FROM certificate_configurations cc
282JOIN certificate_configuration_to_requirements cctr ON cc.id = cctr.certificate_configuration_id
283WHERE cctr.course_instance_id = $1
284 AND cc.deleted_at IS NULL
285 AND cctr.deleted_at IS NULL
286 "#,
287 course_instance_id,
288 )
289 .fetch_all(&mut *conn)
290 .await?;
291 for certificate_configuration in &all_certificate_configurations {
293 let requirements =
294 get_all_requirements_for_certificate_configuration(conn, certificate_configuration.id)
295 .await?;
296 if requirements.is_default_certificate_configuration() {
297 res.push(CertificateConfigurationAndRequirements {
298 certificate_configuration: certificate_configuration.clone(),
299 requirements,
300 });
301 }
302 }
303 Ok(res)
304}
305
306pub async fn get_all_certifcate_configurations_requiring_only_one_module_and_no_course_instance(
308 conn: &mut PgConnection,
309 course_module_ids: &[Uuid],
310) -> ModelResult<Vec<CertificateConfigurationAndRequirements>> {
311 let mut res = Vec::new();
312 let cadidate_certificate_configurations = sqlx::query_as!(
313 CertificateConfiguration,
314 r#"
315SELECT cc.id,
316 cc.created_at,
317 cc.updated_at,
318 cc.deleted_at,
319 cc.certificate_owner_name_y_pos,
320 cc.certificate_owner_name_x_pos,
321 cc.certificate_owner_name_font_size,
322 cc.certificate_owner_name_text_color,
323 cc.certificate_owner_name_text_anchor as "certificate_owner_name_text_anchor: _",
324 cc.certificate_validate_url_y_pos,
325 cc.certificate_validate_url_x_pos,
326 cc.certificate_validate_url_font_size,
327 cc.certificate_validate_url_text_color,
328 cc.certificate_validate_url_text_anchor as "certificate_validate_url_text_anchor: _",
329 cc.certificate_date_y_pos,
330 cc.certificate_date_x_pos,
331 cc.certificate_date_font_size,
332 cc.certificate_date_text_color,
333 cc.certificate_date_text_anchor as "certificate_date_text_anchor: _",
334 cc.certificate_locale,
335 cc.paper_size as "paper_size: _",
336 cc.background_svg_path,
337 cc.background_svg_file_upload_id,
338 cc.overlay_svg_path,
339 cc.overlay_svg_file_upload_id,
340 cc.render_certificate_grade,
341 cc.certificate_grade_y_pos,
342 cc.certificate_grade_x_pos,
343 cc.certificate_grade_font_size,
344 cc.certificate_grade_text_color,
345 cc.certificate_grade_text_anchor as "certificate_grade_text_anchor: _"
346FROM certificate_configurations cc
347JOIN certificate_configuration_to_requirements cctr ON cc.id = cctr.certificate_configuration_id
348WHERE cctr.course_module_id = ANY($1)
349 AND cctr.course_instance_id IS NULL
350 AND cc.deleted_at IS NULL
351 AND cctr.deleted_at IS NULL
352 "#,
353 course_module_ids,
354 )
355 .fetch_all(&mut *conn)
356 .await?;
357 for certificate_configuration in &cadidate_certificate_configurations {
358 let requirements =
359 get_all_requirements_for_certificate_configuration(conn, certificate_configuration.id)
360 .await?;
361 if requirements.requires_only_one_course_module_and_does_not_require_course_instance() {
362 res.push(CertificateConfigurationAndRequirements {
363 certificate_configuration: certificate_configuration.clone(),
364 requirements,
365 });
366 }
367 }
368 Ok(res)
369}
370
371#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
372#[cfg_attr(feature = "ts_rs", derive(TS))]
373pub struct DatabaseCertificateConfiguration {
374 pub id: Uuid,
375 pub certificate_owner_name_y_pos: Option<String>,
376 pub certificate_owner_name_x_pos: Option<String>,
377 pub certificate_owner_name_font_size: Option<String>,
378 pub certificate_owner_name_text_color: Option<String>,
379 pub certificate_owner_name_text_anchor: Option<CertificateTextAnchor>,
380 pub certificate_validate_url_y_pos: Option<String>,
381 pub certificate_validate_url_x_pos: Option<String>,
382 pub certificate_validate_url_font_size: Option<String>,
383 pub certificate_validate_url_text_color: Option<String>,
384 pub certificate_validate_url_text_anchor: Option<CertificateTextAnchor>,
385 pub certificate_date_y_pos: Option<String>,
386 pub certificate_date_x_pos: Option<String>,
387 pub certificate_date_font_size: Option<String>,
388 pub certificate_date_text_color: Option<String>,
389 pub certificate_date_text_anchor: Option<CertificateTextAnchor>,
390 pub certificate_locale: Option<String>,
391 pub paper_size: Option<PaperSize>,
392 pub background_svg_path: String,
393 pub background_svg_file_upload_id: Uuid,
394 pub overlay_svg_path: Option<String>,
395 pub overlay_svg_file_upload_id: Option<Uuid>,
396 pub render_certificate_grade: bool,
397 pub certificate_grade_y_pos: Option<String>,
398 pub certificate_grade_x_pos: Option<String>,
399 pub certificate_grade_font_size: Option<String>,
400 pub certificate_grade_text_color: Option<String>,
401 pub certificate_grade_text_anchor: Option<CertificateTextAnchor>,
402}
403
404impl DatabaseCertificateConfiguration {
405 fn build(&self) -> DatabaseCertificateConfigurationInner<'_> {
408 DatabaseCertificateConfigurationInner {
409 id: self.id,
410 certificate_owner_name_y_pos: self
411 .certificate_owner_name_y_pos
412 .as_deref()
413 .unwrap_or("70%"),
414 certificate_owner_name_x_pos: self
415 .certificate_owner_name_x_pos
416 .as_deref()
417 .unwrap_or("50%"),
418 certificate_owner_name_font_size: self
419 .certificate_owner_name_font_size
420 .as_deref()
421 .unwrap_or("150px"),
422 certificate_owner_name_text_color: self
423 .certificate_owner_name_text_color
424 .as_deref()
425 .unwrap_or("black"),
426 certificate_owner_name_text_anchor: self
427 .certificate_owner_name_text_anchor
428 .unwrap_or(CertificateTextAnchor::Middle),
429 certificate_validate_url_y_pos: self
430 .certificate_validate_url_y_pos
431 .as_deref()
432 .unwrap_or("80%"),
433 certificate_validate_url_x_pos: self
434 .certificate_validate_url_x_pos
435 .as_deref()
436 .unwrap_or("88.5%"),
437 certificate_validate_url_font_size: self
438 .certificate_validate_url_font_size
439 .as_deref()
440 .unwrap_or("30px"),
441 certificate_validate_url_text_color: self
442 .certificate_validate_url_text_color
443 .as_deref()
444 .unwrap_or("black"),
445 certificate_validate_url_text_anchor: self
446 .certificate_validate_url_text_anchor
447 .unwrap_or(CertificateTextAnchor::End),
448 certificate_date_y_pos: self.certificate_date_y_pos.as_deref().unwrap_or("88.5%"),
449 certificate_date_x_pos: self.certificate_date_x_pos.as_deref().unwrap_or("15%"),
450 certificate_date_font_size: self
451 .certificate_date_font_size
452 .as_deref()
453 .unwrap_or("30px"),
454 certificate_date_text_color: self
455 .certificate_date_text_color
456 .as_deref()
457 .unwrap_or("black"),
458 certificate_date_text_anchor: self
459 .certificate_date_text_anchor
460 .unwrap_or(CertificateTextAnchor::Start),
461 certificate_locale: self.certificate_locale.as_deref().unwrap_or("en"),
462 paper_size: self.paper_size.unwrap_or(PaperSize::HorizontalA4),
463 background_svg_path: &self.background_svg_path,
464 background_svg_file_upload_id: self.background_svg_file_upload_id,
465 overlay_svg_path: self.overlay_svg_path.as_deref(),
466 overlay_svg_file_upload_id: self.overlay_svg_file_upload_id,
467 render_certificate_grade: self.render_certificate_grade,
468 certificate_grade_y_pos: self.certificate_grade_y_pos.as_deref().unwrap_or(""),
469 certificate_grade_x_pos: self.certificate_grade_x_pos.as_deref().unwrap_or(""),
470 certificate_grade_font_size: self.certificate_grade_font_size.as_deref().unwrap_or(""),
471 certificate_grade_text_color: self
472 .certificate_grade_text_color
473 .as_deref()
474 .unwrap_or(""),
475 certificate_grade_text_anchor: self
476 .certificate_grade_text_anchor
477 .unwrap_or(CertificateTextAnchor::Middle),
478 }
479 }
480}
481
482#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
483struct DatabaseCertificateConfigurationInner<'a> {
484 pub id: Uuid,
485 pub certificate_owner_name_y_pos: &'a str,
486 pub certificate_owner_name_x_pos: &'a str,
487 pub certificate_owner_name_font_size: &'a str,
488 pub certificate_owner_name_text_color: &'a str,
489 pub certificate_owner_name_text_anchor: CertificateTextAnchor,
490 pub certificate_validate_url_y_pos: &'a str,
491 pub certificate_validate_url_x_pos: &'a str,
492 pub certificate_validate_url_font_size: &'a str,
493 pub certificate_validate_url_text_color: &'a str,
494 pub certificate_validate_url_text_anchor: CertificateTextAnchor,
495 pub certificate_date_y_pos: &'a str,
496 pub certificate_date_x_pos: &'a str,
497 pub certificate_date_font_size: &'a str,
498 pub certificate_date_text_color: &'a str,
499 pub certificate_date_text_anchor: CertificateTextAnchor,
500 pub certificate_locale: &'a str,
501 pub paper_size: PaperSize,
502 pub background_svg_path: &'a str,
503 pub background_svg_file_upload_id: Uuid,
504 pub overlay_svg_path: Option<&'a str>,
505 pub overlay_svg_file_upload_id: Option<Uuid>,
506 pub render_certificate_grade: bool,
507 pub certificate_grade_y_pos: &'a str,
508 pub certificate_grade_x_pos: &'a str,
509 pub certificate_grade_font_size: &'a str,
510 pub certificate_grade_text_color: &'a str,
511 pub certificate_grade_text_anchor: CertificateTextAnchor,
512}
513
514pub async fn insert(
515 conn: &mut PgConnection,
516 conf: &DatabaseCertificateConfiguration,
517) -> ModelResult<CertificateConfiguration> {
518 let conf = conf.build();
519 let configuration = sqlx::query_as!(
520 CertificateConfiguration,
521 r#"
522INSERT INTO public.certificate_configurations (
523 certificate_owner_name_y_pos,
524 certificate_owner_name_x_pos,
525 certificate_owner_name_font_size,
526 certificate_owner_name_text_color,
527 certificate_owner_name_text_anchor,
528 certificate_validate_url_y_pos,
529 certificate_validate_url_x_pos,
530 certificate_validate_url_font_size,
531 certificate_validate_url_text_color,
532 certificate_validate_url_text_anchor,
533 certificate_date_y_pos,
534 certificate_date_x_pos,
535 certificate_date_font_size,
536 certificate_date_text_color,
537 certificate_date_text_anchor,
538 certificate_locale,
539 paper_size,
540 background_svg_path,
541 background_svg_file_upload_id,
542 overlay_svg_path,
543 overlay_svg_file_upload_id,
544 render_certificate_grade,
545 certificate_grade_y_pos,
546 certificate_grade_x_pos,
547 certificate_grade_font_size,
548 certificate_grade_text_color,
549 certificate_grade_text_anchor
550 )
551VALUES (
552 $1,
553 $2,
554 $3,
555 $4,
556 $5,
557 $6,
558 $7,
559 $8,
560 $9,
561 $10,
562 $11,
563 $12,
564 $13,
565 $14,
566 $15,
567 $16,
568 $17,
569 $18,
570 $19,
571 $20,
572 $21,
573 $22,
574 $23,
575 $24,
576 $25,
577 $26,
578 $27
579 )
580RETURNING id,
581 created_at,
582 updated_at,
583 deleted_at,
584 certificate_owner_name_y_pos,
585 certificate_owner_name_x_pos,
586 certificate_owner_name_font_size,
587 certificate_owner_name_text_color,
588 certificate_owner_name_text_anchor as "certificate_owner_name_text_anchor: _",
589 certificate_validate_url_y_pos,
590 certificate_validate_url_x_pos,
591 certificate_validate_url_font_size,
592 certificate_validate_url_text_color,
593 certificate_validate_url_text_anchor as "certificate_validate_url_text_anchor: _",
594 certificate_date_y_pos,
595 certificate_date_x_pos,
596 certificate_date_font_size,
597 certificate_date_text_color,
598 certificate_date_text_anchor as "certificate_date_text_anchor: _",
599 certificate_locale,
600 paper_size as "paper_size: _",
601 background_svg_path,
602 background_svg_file_upload_id,
603 overlay_svg_path,
604 overlay_svg_file_upload_id,
605 render_certificate_grade,
606 certificate_grade_y_pos,
607 certificate_grade_x_pos,
608 certificate_grade_font_size,
609 certificate_grade_text_color,
610 certificate_grade_text_anchor as "certificate_grade_text_anchor: _"
611"#,
612 conf.certificate_owner_name_y_pos,
613 conf.certificate_owner_name_x_pos,
614 conf.certificate_owner_name_font_size,
615 conf.certificate_owner_name_text_color,
616 conf.certificate_owner_name_text_anchor as CertificateTextAnchor,
617 conf.certificate_validate_url_y_pos,
618 conf.certificate_validate_url_x_pos,
619 conf.certificate_validate_url_font_size,
620 conf.certificate_validate_url_text_color,
621 conf.certificate_validate_url_text_anchor as CertificateTextAnchor,
622 conf.certificate_date_y_pos,
623 conf.certificate_date_x_pos,
624 conf.certificate_date_font_size,
625 conf.certificate_date_text_color,
626 conf.certificate_date_text_anchor as CertificateTextAnchor,
627 conf.certificate_locale,
628 conf.paper_size as PaperSize,
629 conf.background_svg_path,
630 conf.background_svg_file_upload_id,
631 conf.overlay_svg_path,
632 conf.overlay_svg_file_upload_id,
633 conf.render_certificate_grade,
634 conf.certificate_grade_y_pos,
635 conf.certificate_grade_x_pos,
636 conf.certificate_grade_font_size,
637 conf.certificate_grade_text_color,
638 conf.certificate_grade_text_anchor as CertificateTextAnchor
639 )
640 .fetch_one(conn)
641 .await?;
642 Ok(configuration)
643}
644
645pub async fn update(
646 conn: &mut PgConnection,
647 id: Uuid,
648 conf: &DatabaseCertificateConfiguration,
649) -> ModelResult<()> {
650 let conf = conf.build();
651 sqlx::query!(
652 r#"
653UPDATE public.certificate_configurations
654SET certificate_owner_name_y_pos = $1,
655 certificate_owner_name_x_pos = $2,
656 certificate_owner_name_font_size = $3,
657 certificate_owner_name_text_color = $4,
658 certificate_owner_name_text_anchor = $5,
659 certificate_validate_url_y_pos = $6,
660 certificate_validate_url_x_pos = $7,
661 certificate_validate_url_font_size = $8,
662 certificate_validate_url_text_color = $9,
663 certificate_validate_url_text_anchor = $10,
664 certificate_date_y_pos = $11,
665 certificate_date_x_pos = $12,
666 certificate_date_font_size = $13,
667 certificate_date_text_color = $14,
668 certificate_date_text_anchor = $15,
669 certificate_locale = $16,
670 paper_size = $17,
671 background_svg_path = $18,
672 background_svg_file_upload_id = $19,
673 overlay_svg_path = $20,
674 overlay_svg_file_upload_id = $21,
675 render_certificate_grade = $22,
676 certificate_grade_y_pos = $23,
677 certificate_grade_x_pos = $24,
678 certificate_grade_font_size = $25,
679 certificate_grade_text_color = $26,
680 certificate_grade_text_anchor = $27
681WHERE id = $28
682"#,
683 conf.certificate_owner_name_y_pos,
684 conf.certificate_owner_name_x_pos,
685 conf.certificate_owner_name_font_size,
686 conf.certificate_owner_name_text_color,
687 conf.certificate_owner_name_text_anchor as CertificateTextAnchor,
688 conf.certificate_validate_url_y_pos,
689 conf.certificate_validate_url_x_pos,
690 conf.certificate_validate_url_font_size,
691 conf.certificate_validate_url_text_color,
692 conf.certificate_validate_url_text_anchor as CertificateTextAnchor,
693 conf.certificate_date_y_pos,
694 conf.certificate_date_x_pos,
695 conf.certificate_date_font_size,
696 conf.certificate_date_text_color,
697 conf.certificate_date_text_anchor as CertificateTextAnchor,
698 conf.certificate_locale,
699 conf.paper_size as PaperSize,
700 conf.background_svg_path,
701 conf.background_svg_file_upload_id,
702 conf.overlay_svg_path,
703 conf.overlay_svg_file_upload_id,
704 conf.render_certificate_grade,
705 conf.certificate_grade_y_pos,
706 conf.certificate_grade_x_pos,
707 conf.certificate_grade_font_size,
708 conf.certificate_grade_text_color,
709 conf.certificate_grade_text_anchor as CertificateTextAnchor,
710 id
711 )
712 .execute(conn)
713 .await?;
714 Ok(())
715}
716
717pub async fn delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
718 sqlx::query!(
719 "
720UPDATE certificate_configurations
721SET deleted_at = now()
722WHERE id = $1
723",
724 id
725 )
726 .execute(conn)
727 .await?;
728 Ok(())
729}