pbd/dua/policy.rs
1//! ### Background
2//! This module implements the `Fideslang` model and taxonomy in an effort to promote a standardized the approach of creating Data Usage Agreements.
3//!
4//! Credit is to be given to [fides](https://ethyca.github.io/fideslang/) and adheres to the fides licensing:
5//! + [license](https://github.com/ethyca/fides/blob/main/LICENSE)
6//! + [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
7//!
8//! You can use the [Privacy Taxonomy Explorer](https://ethyca.github.io/fideslang/explorer/) for a graphic representation of the Fides classification groups.
9//!
10//! ### Usage
11//! A DUP (Data Usage Policy) allows us to define standardized usage policies that can be easily understood by a user, while also being able to apply it programmatically during the application runtime.
12//! These "Opt-In" policies can then be added to the DUA (Data Usage Agreement) so that applications and processors (e.g.: microservices) can dynamically determine if and how they are permitted to utilize the data prior to processing it.
13//!
14//! ```rust
15//! extern crate pbd;
16//!
17//! use pbd::dua::policy::{Condition, DUP};
18//! use pbd::dua::data_category::DataCategoryFactory;
19//! use pbd::dua::data_subject::DataSubjectFactory;
20//! use pbd::dua::data_use::DataUseFactory;
21//!
22//! fn get_defined_policy() -> DUP {
23//! let category_factory = DataCategoryFactory::new();
24//! let subject_factory = DataSubjectFactory::new();
25//! let use_factory = DataUseFactory::new();
26//!
27//! let mut dup = DUP::new(
28//! "General Policy".to_string(),
29//! "This is a high-level policy.".to_string(),
30//! "1.0.1".to_string()
31//! );
32//!
33//! // associate some classifications to the policy
34//! dup.associate_category(category_factory.get_category_by_key("system.authentication".to_string()).unwrap());
35//! dup.associate_category(category_factory.get_category_by_key("user.contact.email".to_string()).unwrap());
36//! dup.associate_category(category_factory.get_category_by_key("user.contact.phone_number".to_string()).unwrap());
37//! dup.associate_subject(subject_factory.get_subject_by_key("customer".to_string()).unwrap());
38//! dup.associate_use(use_factory.get_use_by_key("essential.service.authentication".to_string()).unwrap());
39//!
40//! dup
41//! }
42//!
43//! fn get_processor_conditions() -> Vec<Condition> {
44//! let mut conditions: Vec<Condition> = Vec::new();
45//! let category_factory = DataCategoryFactory::new();
46//! let subject_factory = DataSubjectFactory::new();
47//! let use_factory = DataUseFactory::new();
48//!
49//! conditions.push(Condition::Category(category_factory.get_category_by_key("user.contact.email".to_string()).unwrap().get_key()));
50//! conditions.push(Condition::Subject(subject_factory.get_subject_by_key("customer".to_string()).unwrap().get_key()));
51//! conditions.push(Condition::Use(use_factory.get_use_by_key("marketing.advertising.profiling".to_string()).unwrap().get_key()));
52//!
53//! conditions
54//! }
55//!
56//! fn main() {
57//! // A policy that defines the acceptable conditions for using the data
58//! let mut policy = get_defined_policy();
59//!
60//! // A list of conditions that the processor has been configured to apply to data
61//! let conditions = get_processor_conditions();
62//!
63//! // Check to see if the processor is permitted to use the data based on its privacy configurations
64//! let conflicts = policy.match_conditions(conditions);
65//!
66//! match conflicts.len() > 0 {
67//! true => {
68//! for conflict in conflicts.iter() {
69//! println!("Blocked due to Condition key {}", conflict.to_string());
70//! }
71//! },
72//! false => println!("Allowed - Process the data."),
73//! }
74//! }
75//! ```
76use super::data_category::DataCategory;
77use super::data_subject::DataSubject;
78use super::data_use::DataUse;
79use derive_more::Display;
80use std::collections::BTreeMap;
81
82/// An Enum of any possible item keys that can be associated to a policy
83#[derive(Display, Clone)]
84pub enum Condition {
85 Category(String),
86 Subject(String),
87 Use(String),
88}
89
90/// Represents a Data Usage Policy (DUP)
91#[derive(Serialize, Deserialize, Debug, Clone)]
92pub struct DUP {
93 /// The common name of the Data Usage Policy, (e.g.: For Billing Purpose)
94 pub name: String,
95 /// A textual description of the Data Usage Policy
96 pub description: String,
97 /// The version of the policy, (e.g.: 1.0.0)
98 pub version: String,
99 // The lists of Data Categories associated with the policy
100 categories: BTreeMap<String, DataCategory>,
101 // The lists of Data Subjects associated with the policy
102 subjects: BTreeMap<String, DataSubject>,
103 // The lists of Data Uses associated with the policy
104 uses: BTreeMap<String, DataUse>,
105}
106
107impl DUP {
108 /// Constructs a new Data Usage Policy object
109 ///
110 /// # Arguments
111 ///
112 /// * nme: String - The textual name of the Data Usage Policy.</br>
113 /// * descr: String - A textual description of the Data Usage Policy.</br>
114 /// * ver: String - The version of the policy, (e.g.: 1.0.0).</br>
115 ///
116 /// #Example
117 ///
118 /// ```rust
119 /// extern crate pbd;
120 ///
121 /// use pbd::dua::policy::DUP;
122 ///
123 /// fn main() {
124 /// let dup = DUP::new(
125 /// "General Policy".to_string(),
126 /// "This is a high-level policy.".to_string(),
127 /// "1.0.1".to_string()
128 /// );
129 /// }
130 /// ```
131 pub fn new(nme: String, descr: String, ver: String) -> Self {
132 DUP {
133 name: nme,
134 description: descr,
135 version: ver,
136 categories: BTreeMap::new(),
137 subjects: BTreeMap::new(),
138 uses: BTreeMap::new(),
139 }
140 }
141
142 /// Associates a DataCategory object to the policy
143 /// __NOTE__: Call this function to associate a new DataCategory objects or replace pre-associated DataCategory objects
144 ///
145 /// # Arguments
146 ///
147 /// * category: DataCategory - The Data Category to associate.</br>
148 ///
149 /// #Example
150 ///
151 /// ```rust
152 /// extern crate pbd;
153 ///
154 /// use pbd::dua::policy::DUP;
155 /// use pbd::dua::data_category::DataCategory;
156 ///
157 /// fn main() {
158 /// let mut dup = DUP::new(
159 /// "General Policy".to_string(),
160 /// "This is a high-level policy.".to_string(),
161 /// "1.0.1".to_string()
162 /// );
163 ///
164 /// dup.associate_category(DataCategory::new(
165 /// "Authentication Data".to_string(),
166 /// "Data used to manage access to the system.".to_string(),
167 /// "system.authentication".to_string(),
168 /// "default_organization".to_string(),
169 /// Some("system".to_string()),
170 /// None,
171 /// false,
172 /// true,
173 /// ));
174 /// }
175 /// ```
176 pub fn associate_category(&mut self, category: DataCategory) {
177 self.categories.insert(category.get_key().clone(), category);
178 }
179
180 /// Associates a DataSubject object to the policy
181 /// __NOTE__: Call this function to associate a new DataSubject objects or replace pre-associated DataSubject objects
182 ///
183 /// # Arguments
184 ///
185 /// * subject: DataSubject - The Data Subject to associate.</br>
186 ///
187 /// #Example
188 ///
189 /// ```rust
190 /// extern crate pbd;
191 ///
192 /// use pbd::dua::policy::DUP;
193 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
194 ///
195 /// fn main() {
196 /// let mut dup = DUP::new(
197 /// "General Policy".to_string(),
198 /// "This is a high-level policy.".to_string(),
199 /// "1.0.1".to_string()
200 /// );
201 ///
202 /// let subject = DataSubject::new(
203 /// "Consultant".to_string(),
204 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
205 /// "consultant".to_string(),
206 /// "default_organization".to_string(),
207 /// Some(vec!["work".to_string(), "temporary".to_string()]),
208 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
209 /// false,
210 /// false,
211 /// true
212 /// );
213 ///
214 /// dup.associate_subject(subject);
215 /// }
216 /// ```
217 pub fn associate_subject(&mut self, subject: DataSubject) {
218 self.subjects.insert(subject.get_key().clone(), subject);
219 }
220
221 /// Associates a DataUse object to the policy
222 /// __NOTE__: Call this function to associate a new DataUse objects or replace pre-associated DataUse objects
223 ///
224 /// # Arguments
225 ///
226 /// * usage: DataUse - The Data Use to associate.</br>
227 ///
228 /// #Example
229 ///
230 /// ```rust
231 /// extern crate pbd;
232 ///
233 /// use pbd::dua::policy::DUP;
234 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
235 ///
236 /// fn main() {
237 /// let mut dup = DUP::new(
238 /// "General Policy".to_string(),
239 /// "This is a high-level policy.".to_string(),
240 /// "1.0.1".to_string()
241 /// );
242 ///
243 /// let datause = DataUse::new(
244 /// "Provide the capability".to_string(),
245 /// "Provide, give, or make available the product, service, application or system.".to_string(),
246 /// "provide".to_string(),
247 /// "default_organization".to_string(),
248 /// None,
249 /// Some(LegalBasis::LegitimateInterest),
250 /// Some(SpecialCategory::VitalInterests),
251 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
252 /// false,
253 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
254 /// None,
255 /// false,
256 /// true
257 /// );
258 ///
259 /// dup.associate_use(datause);
260 /// }
261 /// ```
262 pub fn associate_use(&mut self, usage: DataUse) {
263 self.uses.insert(usage.get_key().clone(), usage);
264 }
265
266 fn readable_description(&mut self, mut policy: String, line_feed: &str) -> String {
267 // Data Subjects
268 policy.push_str("Data will be collected from ");
269 match self.get_subjects().len() {
270 0 => {
271 policy.push_str("all types of users.");
272 }
273 _ => {
274 policy.push_str("the following types of users: ");
275 let count = self.get_subjects().len();
276 for (idx, subject) in self.get_subjects().iter().enumerate() {
277 policy.push_str(&subject.name);
278 let delimiter = match idx < count - 2 {
279 true => ", ",
280 false => match idx == count - 1 {
281 true => ".",
282 false => " and ",
283 },
284 };
285 policy.push_str(delimiter);
286 }
287 policy.push_str(line_feed);
288 }
289 }
290
291 // Data Categories
292 policy.push_str("The data being collected will be ");
293 match self.get_categories().len() {
294 0 => {
295 policy.push_str("include all types of data.");
296 }
297 _ => {
298 policy.push_str("limited to the following data: ");
299 let count = self.get_categories().len();
300 for (idx, category) in self.get_categories().iter().enumerate() {
301 policy.push_str(&category.name);
302 let delimiter = match idx < count - 2 {
303 true => ", ",
304 false => match idx == count - 1 {
305 true => ".",
306 false => " and ",
307 },
308 };
309 policy.push_str(delimiter);
310 }
311 policy.push_str(line_feed);
312 }
313 }
314
315 // Data Uses
316 policy.push_str("The data collected can be used for ");
317 match self.get_uses().len() {
318 0 => {
319 policy.push_str("various purposes.");
320 }
321 _ => {
322 policy.push_str("the following purposes: ");
323 let count = self.get_uses().len();
324 for (idx, usage) in self.get_uses().iter().enumerate() {
325 policy.push_str(&usage.name);
326 let delimiter = match idx < count - 2 {
327 true => ", ",
328 false => match idx == count - 1 {
329 true => ".",
330 false => " and ",
331 },
332 };
333 policy.push_str(delimiter);
334 }
335 policy.push_str(line_feed);
336 }
337 }
338
339 return policy;
340 }
341
342 /// Converts the policy to a human readable format as html
343 /// _NOTE:_ You can apply custom styling by referencing the `class` attribute of the elements.
344 ///
345 /// #Example
346 ///
347 /// ```rust
348 /// extern crate pbd;
349 ///
350 /// use pbd::dua::policy::DUP;
351 /// use pbd::dua::data_category::DataCategoryFactory;
352 /// use pbd::dua::data_subject::DataSubjectFactory;
353 /// use pbd::dua::data_use::DataUseFactory;
354 ///
355 /// fn main() {
356 /// let cfactory = DataCategoryFactory::new();
357 /// let sfactory = DataSubjectFactory::new();
358 /// let ufactory = DataUseFactory::new();
359 /// let mut dup = DUP::new(
360 /// "General Marketing Policy".to_string(),
361 /// "This policy explains the manner in which your data will be used for marketing purposes.".to_string(),
362 /// "1.0.0".to_string()
363 /// );
364 ///
365 /// dup.associate_category(
366 /// cfactory
367 /// .get_category_by_key("user.behavior.browsing_history".to_string())
368 /// .unwrap(),
369 /// );
370 /// dup.associate_category(
371 /// cfactory
372 /// .get_category_by_key("user.behavior.media_consumption".to_string())
373 /// .unwrap(),
374 /// );
375 /// dup.associate_subject(sfactory.get_subject_by_key("customer".to_string()).unwrap());
376 /// dup.associate_subject(sfactory.get_subject_by_key("prospect".to_string()).unwrap());
377 /// dup.associate_use(
378 /// ufactory
379 /// .get_use_by_key("marketing.advertising.profiling".to_string())
380 /// .unwrap(),
381 /// );
382 /// dup.associate_use(
383 /// ufactory
384 /// .get_use_by_key("marketing.advertising.serving".to_string())
385 /// .unwrap(),
386 /// );
387 /// dup.associate_use(
388 /// ufactory
389 /// .get_use_by_key("marketing.communications.email".to_string())
390 /// .unwrap(),
391 /// );
392 ///
393 /// print!("{}", dup.as_html());
394 ///
395 /// /* <div class='dup' name='General Policy'>General Policy</div></br>
396 /// * <div class='dup-verion' name='1.0.1'>(version: 1.0.1)</div></br></br>
397 /// * <div class='dup-description' name='General Policy Description'><b>This is a high-level policy.</b></br></br>
398 /// * <p>
399 /// * Data will be collected from the following types of users: Customer and Prospect.</br>
400 /// * The data being collected will be limited to the following data: Browsing History and Media Consumption.</br>
401 /// * The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.</br>
402 /// * </p></div>
403 /// */
404 /// }
405 /// ```
406 pub fn as_html(&mut self) -> String {
407 let line_feed = "</br>";
408 let mut policy = String::new();
409 policy.push_str("<div class='dup' name='");
410 policy.push_str(&self.name);
411 policy.push_str("'>");
412 policy.push_str(&self.name);
413 policy.push_str("</div>");
414 policy.push_str(line_feed);
415 policy.push_str("<div class='dup-verion' name='");
416 policy.push_str(&self.version);
417 policy.push_str("'>");
418 policy.push_str("(version: ");
419 policy.push_str(&self.version);
420 policy.push_str(")");
421 policy.push_str("</div>");
422 policy.push_str(line_feed);
423 policy.push_str(line_feed);
424 policy.push_str("<div class='dup-description' name='");
425 policy.push_str(&self.name);
426 policy.push_str(" Description'><b>");
427 policy.push_str(&self.description);
428 policy.push_str("</b>");
429 policy.push_str(line_feed);
430 policy.push_str(line_feed);
431 policy.push_str("<p>");
432
433 policy = self.readable_description(policy, line_feed);
434 policy.push_str("</p>");
435 policy.push_str("</div>");
436
437 policy
438 }
439
440 /// Converts the policy to a human readable format as text
441 ///
442 /// #Example
443 ///
444 /// ```rust
445 /// extern crate pbd;
446 ///
447 /// use pbd::dua::policy::DUP;
448 /// use pbd::dua::data_category::DataCategoryFactory;
449 /// use pbd::dua::data_subject::DataSubjectFactory;
450 /// use pbd::dua::data_use::DataUseFactory;
451 ///
452 /// fn main() {
453 /// let cfactory = DataCategoryFactory::new();
454 /// let sfactory = DataSubjectFactory::new();
455 /// let ufactory = DataUseFactory::new();
456 /// let mut dup = DUP::new(
457 /// "General Marketing Policy".to_string(),
458 /// "This policy explains the manner in which your data will be used for marketing purposes.".to_string(),
459 /// "1.0.0".to_string()
460 /// );
461 ///
462 /// dup.associate_category(
463 /// cfactory
464 /// .get_category_by_key("user.behavior.browsing_history".to_string())
465 /// .unwrap(),
466 /// );
467 /// dup.associate_category(
468 /// cfactory
469 /// .get_category_by_key("user.behavior.media_consumption".to_string())
470 /// .unwrap(),
471 /// );
472 /// dup.associate_subject(sfactory.get_subject_by_key("customer".to_string()).unwrap());
473 /// dup.associate_subject(sfactory.get_subject_by_key("prospect".to_string()).unwrap());
474 /// dup.associate_use(
475 /// ufactory
476 /// .get_use_by_key("marketing.advertising.profiling".to_string())
477 /// .unwrap(),
478 /// );
479 /// dup.associate_use(
480 /// ufactory
481 /// .get_use_by_key("marketing.advertising.serving".to_string())
482 /// .unwrap(),
483 /// );
484 /// dup.associate_use(
485 /// ufactory
486 /// .get_use_by_key("marketing.communications.email".to_string())
487 /// .unwrap(),
488 /// );
489 ///
490 /// print!("{}", dup.as_text());
491 ///
492 /// /* General Marketing Policy
493 /// * (version: 1.0.0)
494 /// *
495 /// * This policy explains the manner in which your data will be used for marketing purposes.
496 /// *
497 /// * Data will be collected from the following types of users: Customer and Prospect.
498 /// * The data being collected will be limited to the following data: Browsing History and Media Consumption.
499 /// * The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.
500 /// */
501 /// }
502 /// ```
503 pub fn as_text(&mut self) -> String {
504 let line_feed = "\r\n";
505 let mut policy = String::new();
506 policy.push_str(&self.name);
507 policy.push_str(line_feed);
508 policy.push_str("(version: ");
509 policy.push_str(&self.version);
510 policy.push_str(")");
511 policy.push_str(line_feed);
512 policy.push_str(line_feed);
513
514 policy.push_str(&self.description);
515 policy.push_str(line_feed);
516 policy.push_str(line_feed);
517
518 policy = self.readable_description(policy, line_feed);
519
520 policy
521 }
522
523 /// Disassociates the specified DataCategory object from the policy using the key
524 ///
525 /// # Arguments
526 ///
527 /// * key: String - The key of the Data Category to disassociate.</br>
528 ///
529 /// #Example
530 ///
531 /// ```rust
532 /// extern crate pbd;
533 ///
534 /// use pbd::dua::policy::DUP;
535 /// use pbd::dua::data_category::DataCategory;
536 ///
537 /// fn main() {
538 /// let mut dup = DUP::new(
539 /// "General Policy".to_string(),
540 /// "This is a high-level policy.".to_string(),
541 /// "1.0.1".to_string()
542 /// );
543 /// let cat = DataCategory::new(
544 /// "Authentication Data".to_string(),
545 /// "Data used to manage access to the system.".to_string(),
546 /// "system.authentication".to_string(),
547 /// "default_organization".to_string(),
548 /// Some("system".to_string()),
549 /// None,
550 /// false,
551 /// true,
552 /// );
553 ///
554 /// dup.associate_category(cat.clone());
555 ///
556 /// dup.disassociate_category(cat.get_key());
557 /// }
558 /// ```
559 pub fn disassociate_category(&mut self, key: String) {
560 self.categories.remove(&key);
561 }
562
563 /// Disassociates the specified DataSubject object from the policy using the key
564 ///
565 /// # Arguments
566 ///
567 /// * key: String - The key of the Data Subject to disassociate.</br>
568 ///
569 /// #Example
570 ///
571 /// ```rust
572 /// extern crate pbd;
573 ///
574 /// use pbd::dua::policy::DUP;
575 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
576 ///
577 /// fn main() {
578 /// let mut dup = DUP::new(
579 /// "General Policy".to_string(),
580 /// "This is a high-level policy.".to_string(),
581 /// "1.0.1".to_string()
582 /// );
583 ///
584 /// let subject = DataSubject::new(
585 /// "Consultant".to_string(),
586 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
587 /// "consultant".to_string(),
588 /// "default_organization".to_string(),
589 /// Some(vec!["work".to_string(), "temporary".to_string()]),
590 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
591 /// false,
592 /// false,
593 /// true
594 /// );
595 ///
596 /// dup.associate_subject(subject.clone());
597 ///
598 /// dup.disassociate_subject(subject.get_key());
599 /// }
600 /// ```
601 pub fn disassociate_subject(&mut self, key: String) {
602 self.subjects.remove(&key);
603 }
604
605 /// Disassociates the specified DataUse object from the policy using the key
606 ///
607 /// # Arguments
608 ///
609 /// * key: String - The key of the Data Use to disassociate.</br>
610 ///
611 /// #Example
612 ///
613 /// ```rust
614 /// extern crate pbd;
615 ///
616 /// use pbd::dua::policy::DUP;
617 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
618 ///
619 /// fn main() {
620 /// let mut dup = DUP::new(
621 /// "General Policy".to_string(),
622 /// "This is a high-level policy.".to_string(),
623 /// "1.0.1".to_string()
624 /// );
625 ///
626 /// let datause = DataUse::new(
627 /// "Provide the capability".to_string(),
628 /// "Provide, give, or make available the product, service, application or system.".to_string(),
629 /// "provide".to_string(),
630 /// "default_organization".to_string(),
631 /// None,
632 /// Some(LegalBasis::LegitimateInterest),
633 /// Some(SpecialCategory::VitalInterests),
634 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
635 /// false,
636 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
637 /// None,
638 /// false,
639 /// true
640 /// );
641 ///
642 /// dup.associate_use(datause.clone());
643 ///
644 /// dup.disassociate_use(datause.get_key());
645 /// }
646 /// ```
647 pub fn disassociate_use(&mut self, key: String) {
648 self.uses.remove(&key);
649 }
650
651 /// Constructs a DUP object from a serialized string
652 ///
653 /// # Arguments
654 ///
655 /// * serialized: &str - The string that represents the serialized object.</br>
656 ///
657 /// #Example
658 ///
659 /// ```rust
660 /// extern crate pbd;
661 ///
662 /// use pbd::dua::policy::DUP;
663 ///
664 /// fn main() {
665 /// let serialized = r#"{"name":"General Policy","description":"This is a high-level policy.","version":"1.0.1","categories":{"system.authentication":{"name":"Authentication Data","description":"Data used to manage access to the system.","fides_key":"system.authentication","organization_fides_key":"default_organization","parent_key":"system","tags":null,"is_default":true,"active":true}},"subjects":{"consultant":{"name":"Consultant","description":"An individual employed in a consultative/temporary capacity by the organization.","fides_key":"consultant","organization_fides_key":"default_organization","tags":null,"rights":null,"automated_decisions_or_profiling":false,"is_default":true,"active":true}},"uses":{"essential.service.authentication":{"name":"Essential Service Authentication","description":"Authenticate users to the product, service, application or system.","fides_key":"essential.service.authentication","organization_fides_key":"default_organization","parent_key":"essential.service","legal_basis":null,"special_category":null,"recipent":null,"legitimate_interest":false,"legitimate_interest_impact_assessment":null,"tags":null,"is_default":true,"active":true}}}"#;
666 /// let mut dup = DUP::from_serialized(&serialized);
667 ///
668 /// assert_eq!(dup.get_categories().len(), 1);
669 /// }
670 /// ```
671 pub fn from_serialized(serialized: &str) -> DUP {
672 serde_json::from_str(&serialized).unwrap()
673 }
674
675 /// Retrieves all the associated DataCategory objects
676 ///
677 /// #Example
678 ///
679 /// ```rust
680 /// extern crate pbd;
681 ///
682 /// use pbd::dua::policy::DUP;
683 /// use pbd::dua::data_category::DataCategory;
684 ///
685 /// fn main() {
686 /// let mut dup = DUP::new(
687 /// "General Policy".to_string(),
688 /// "This is a high-level policy.".to_string(),
689 /// "1.0.1".to_string()
690 /// );
691 ///
692 /// dup.associate_category(DataCategory::new(
693 /// "Authentication Data".to_string(),
694 /// "Data used to manage access to the system.".to_string(),
695 /// "system.authentication".to_string(),
696 /// "default_organization".to_string(),
697 /// Some("system".to_string()),
698 /// None,
699 /// false,
700 /// true,
701 /// ));
702 ///
703 /// assert_eq!(dup.get_categories().len(), 1);
704 /// }
705 /// ```
706 pub fn get_categories(&mut self) -> Vec<DataCategory> {
707 self.categories.clone().into_values().collect()
708 }
709
710 /// Retrieves all the associated DataSubject objects
711 ///
712 /// #Example
713 ///
714 /// ```rust
715 /// extern crate pbd;
716 ///
717 /// use pbd::dua::policy::DUP;
718 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
719 ///
720 /// fn main() {
721 /// let mut dup = DUP::new(
722 /// "General Policy".to_string(),
723 /// "This is a high-level policy.".to_string(),
724 /// "1.0.1".to_string()
725 /// );
726 ///
727 /// let subject = DataSubject::new(
728 /// "Consultant".to_string(),
729 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
730 /// "consultant".to_string(),
731 /// "default_organization".to_string(),
732 /// Some(vec!["work".to_string(), "temporary".to_string()]),
733 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
734 /// false,
735 /// false,
736 /// true
737 /// );
738 ///
739 /// dup.associate_subject(subject);
740 ///
741 /// assert_eq!(dup.get_subjects().len(), 1);
742 /// }
743 /// ```
744 pub fn get_subjects(&mut self) -> Vec<DataSubject> {
745 self.subjects.clone().into_values().collect()
746 }
747
748 /// Retrieves all the associated DataUse objects
749 ///
750 /// #Example
751 ///
752 /// ```rust
753 /// extern crate pbd;
754 ///
755 /// use pbd::dua::policy::DUP;
756 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
757 ///
758 /// fn main() {
759 /// let mut dup = DUP::new(
760 /// "General Policy".to_string(),
761 /// "This is a high-level policy.".to_string(),
762 /// "1.0.1".to_string()
763 /// );
764 ///
765 /// let datause = DataUse::new(
766 /// "Provide the capability".to_string(),
767 /// "Provide, give, or make available the product, service, application or system.".to_string(),
768 /// "provide".to_string(),
769 /// "default_organization".to_string(),
770 /// None,
771 /// Some(LegalBasis::LegitimateInterest),
772 /// Some(SpecialCategory::VitalInterests),
773 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
774 /// false,
775 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
776 /// None,
777 /// false,
778 /// true
779 /// );
780 ///
781 /// dup.associate_use(datause);
782 ///
783 /// assert_eq!(dup.get_uses().len(), 1);
784 /// }
785 /// ```
786 pub fn get_uses(&mut self) -> Vec<DataUse> {
787 self.uses.clone().into_values().collect()
788 }
789
790 /// Retrieves a reference to the specified DataCategory that is associated with the policy
791 ///
792 /// # Arguments
793 ///
794 /// * key: String - The key of the Data Category to retrieve.</br>
795 ///
796 /// #Example
797 ///
798 /// ```rust
799 /// extern crate pbd;
800 ///
801 /// use pbd::dua::policy::DUP;
802 /// use pbd::dua::data_category::DataCategory;
803 ///
804 /// fn main() {
805 /// let mut dup = DUP::new(
806 /// "General Policy".to_string(),
807 /// "This is a high-level policy.".to_string(),
808 /// "1.0.1".to_string()
809 /// );
810 ///
811 /// let cat = DataCategory::new(
812 /// "Authentication Data".to_string(),
813 /// "Data used to manage access to the system.".to_string(),
814 /// "system.authentication".to_string(),
815 /// "default_organization".to_string(),
816 /// Some("system".to_string()),
817 /// None,
818 /// false,
819 /// true,
820 /// );
821 ///
822 /// dup.associate_category(cat.clone());
823 ///
824 /// let retrieved_category = dup.get_category(cat.get_key()).unwrap();
825 /// println!("{}", retrieved_category.description);
826 /// }
827 /// ```
828 pub fn get_category(&mut self, key: String) -> Option<&DataCategory> {
829 self.categories.get(&key)
830 }
831
832 /// Retrieves a reference to the specified DataSubject that is associated with the policy
833 ///
834 /// # Arguments
835 ///
836 /// * key: String - The key of the Data Subject to retrieve.</br>
837 ///
838 /// #Example
839 ///
840 /// ```rust
841 /// extern crate pbd;
842 ///
843 /// use pbd::dua::policy::DUP;
844 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
845 ///
846 /// fn main() {
847 /// let mut dup = DUP::new(
848 /// "General Policy".to_string(),
849 /// "This is a high-level policy.".to_string(),
850 /// "1.0.1".to_string()
851 /// );
852 ///
853 /// let subject = DataSubject::new(
854 /// "Consultant".to_string(),
855 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
856 /// "consultant".to_string(),
857 /// "default_organization".to_string(),
858 /// Some(vec!["work".to_string(), "temporary".to_string()]),
859 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
860 /// false,
861 /// false,
862 /// true
863 /// );
864 ///
865 /// dup.associate_subject(subject.clone());
866 ///
867 /// let retrieved_subject = dup.get_subject(subject.get_key()).unwrap();
868 /// println!("{}", retrieved_subject.description);
869 /// }
870 /// ```
871 pub fn get_subject(&mut self, key: String) -> Option<&DataSubject> {
872 self.subjects.get(&key)
873 }
874
875 /// Retrieves a reference to the specified DataUse that is associated with the policy
876 ///
877 /// # Arguments
878 ///
879 /// * key: String - The key of the Data Use to retrieve.</br>
880 ///
881 /// #Example
882 ///
883 /// ```rust
884 /// extern crate pbd;
885 ///
886 /// use pbd::dua::policy::DUP;
887 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
888 ///
889 /// fn main() {
890 /// let mut dup = DUP::new(
891 /// "General Policy".to_string(),
892 /// "This is a high-level policy.".to_string(),
893 /// "1.0.1".to_string()
894 /// );
895 ///
896 /// let datause = DataUse::new(
897 /// "Provide the capability".to_string(),
898 /// "Provide, give, or make available the product, service, application or system.".to_string(),
899 /// "provide".to_string(),
900 /// "default_organization".to_string(),
901 /// None,
902 /// Some(LegalBasis::LegitimateInterest),
903 /// Some(SpecialCategory::VitalInterests),
904 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
905 /// false,
906 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
907 /// None,
908 /// false,
909 /// true
910 /// );
911 ///
912 /// dup.associate_use(datause.clone());
913 ///
914 /// let retrieved_use = dup.get_use(datause.get_key()).unwrap();
915 /// println!("{}", retrieved_use.description);
916 /// }
917 /// ```
918 pub fn get_use(&mut self, key: String) -> Option<&DataUse> {
919 self.uses.get(&key)
920 }
921
922 /// Determines if the specified DataCategory key is associated with the policy
923 ///
924 /// # Arguments
925 ///
926 /// * key: String - The key of the Data Category to check.</br>
927 ///
928 /// #Example
929 ///
930 /// ```rust
931 /// extern crate pbd;
932 ///
933 /// use pbd::dua::policy::DUP;
934 /// use pbd::dua::data_category::DataCategory;
935 ///
936 /// fn main() {
937 /// let mut dup = DUP::new(
938 /// "General Policy".to_string(),
939 /// "This is a high-level policy.".to_string(),
940 /// "1.0.1".to_string()
941 /// );
942 ///
943 /// let cat = DataCategory::new(
944 /// "Authentication Data".to_string(),
945 /// "Data used to manage access to the system.".to_string(),
946 /// "system.authentication".to_string(),
947 /// "default_organization".to_string(),
948 /// Some("system".to_string()),
949 /// None,
950 /// false,
951 /// true,
952 /// );
953 ///
954 /// dup.associate_category(cat.clone());
955 ///
956 /// assert_eq!(dup.has_category(cat.get_key()), true);
957 /// }
958 /// ```
959 pub fn has_category(&mut self, key: String) -> bool {
960 self.categories.contains_key(&key)
961 }
962
963 /// Determines if the specified DataSubejct key is associated with the policy
964 ///
965 /// # Arguments
966 ///
967 /// * key: String - The key of the Data Subject to check.</br>
968 ///
969 /// #Example
970 ///
971 /// ```rust
972 /// extern crate pbd;
973 ///
974 /// use pbd::dua::policy::DUP;
975 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
976 ///
977 /// fn main() {
978 /// let mut dup = DUP::new(
979 /// "General Policy".to_string(),
980 /// "This is a high-level policy.".to_string(),
981 /// "1.0.1".to_string()
982 /// );
983 ///
984 /// let subject = DataSubject::new(
985 /// "Consultant".to_string(),
986 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
987 /// "consultant".to_string(),
988 /// "default_organization".to_string(),
989 /// Some(vec!["work".to_string(), "temporary".to_string()]),
990 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
991 /// false,
992 /// false,
993 /// true
994 /// );
995 ///
996 /// dup.associate_subject(subject.clone());
997 ///
998 /// assert_eq!(dup.has_subject(subject.get_key()), true);
999 /// }
1000 /// ```
1001 pub fn has_subject(&mut self, key: String) -> bool {
1002 self.subjects.contains_key(&key)
1003 }
1004
1005 /// Determines if the specified DataUse key is associated with the policy
1006 ///
1007 /// # Arguments
1008 ///
1009 /// * key: String - The key of the Data Use to check.</br>
1010 ///
1011 /// #Example
1012 ///
1013 /// ```rust
1014 /// extern crate pbd;
1015 ///
1016 /// use pbd::dua::policy::DUP;
1017 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
1018 ///
1019 /// fn main() {
1020 /// let mut dup = DUP::new(
1021 /// "General Policy".to_string(),
1022 /// "This is a high-level policy.".to_string(),
1023 /// "1.0.1".to_string()
1024 /// );
1025 ///
1026 /// let datause = DataUse::new(
1027 /// "Provide the capability".to_string(),
1028 /// "Provide, give, or make available the product, service, application or system.".to_string(),
1029 /// "provide".to_string(),
1030 /// "default_organization".to_string(),
1031 /// None,
1032 /// Some(LegalBasis::LegitimateInterest),
1033 /// Some(SpecialCategory::VitalInterests),
1034 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
1035 /// false,
1036 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
1037 /// None,
1038 /// false,
1039 /// true
1040 /// );
1041 ///
1042 /// dup.associate_use(datause.clone());
1043 ///
1044 /// assert_eq!(dup.has_use(datause.get_key()), true);
1045 /// }
1046 /// ```
1047 pub fn has_use(&mut self, key: String) -> bool {
1048 self.uses.contains_key(&key)
1049 }
1050
1051 /// Determines if the specified Conditions can be met by the policy and returns a list of conditions that conflict wiht the policy.
1052 ///
1053 /// # Arguments
1054 ///
1055 /// * conditions: Vec<Condition> - The list of Conditions to check against the policy.</br>
1056 ///
1057 /// #Example
1058 ///
1059 /// ```rust
1060 /// extern crate pbd;
1061 ///
1062 /// use pbd::dua::policy::{Condition, DUP};
1063 /// use pbd::dua::data_category::DataCategory;
1064 /// use pbd::dua::data_subject::{DataRights, DataSubject, Right, Strategy};
1065 /// use pbd::dua::data_use::{DataUse, LegalBasis, SpecialCategory};
1066 ///
1067 /// fn main() {
1068 /// let mut dup = DUP::new(
1069 /// "General Policy".to_string(),
1070 /// "This is a high-level policy.".to_string(),
1071 /// "1.0.1".to_string()
1072 /// );
1073 /// let category = DataCategory::new(
1074 /// "Authentication Data".to_string(),
1075 /// "Data used to manage access to the system.".to_string(),
1076 /// "system.authentication".to_string(),
1077 /// "default_organization".to_string(),
1078 /// Some("system".to_string()),
1079 /// None,
1080 /// false,
1081 /// true,
1082 /// );
1083 /// let subject = DataSubject::new(
1084 /// "Consultant".to_string(),
1085 /// "An individual employed in a consultative/temporary capacity by the organization.".to_string(),
1086 /// "consultant".to_string(),
1087 /// "default_organization".to_string(),
1088 /// Some(vec!["work".to_string(), "temporary".to_string()]),
1089 /// Some(DataRights::new(Strategy::ALL, vec![Right::Informed, Right::Access])),
1090 /// false,
1091 /// false,
1092 /// true
1093 /// );
1094 /// let datause = DataUse::new(
1095 /// "Provide the capability".to_string(),
1096 /// "Provide, give, or make available the product, service, application or system.".to_string(),
1097 /// "provide".to_string(),
1098 /// "default_organization".to_string(),
1099 /// None,
1100 /// Some(LegalBasis::LegitimateInterest),
1101 /// Some(SpecialCategory::VitalInterests),
1102 /// Some(vec!("marketing team".to_string(), "dog shelter".to_string())),
1103 /// false,
1104 /// Some("https://example.org/legitimate_interest_assessment".to_string()),
1105 /// None,
1106 /// false,
1107 /// true
1108 /// );
1109 ///
1110 /// dup.associate_category(category.clone());
1111 /// dup.associate_use(datause.clone());
1112 ///
1113 /// let mut conditions: Vec<Condition> = Vec::new();
1114 /// conditions.push(Condition::Category(category.get_key()));
1115 /// conditions.push(Condition::Subject(subject.get_key()));
1116 /// conditions.push(Condition::Use(datause.get_key()));
1117 /// let conflicts = dup.match_conditions(conditions);
1118 ///
1119 /// assert_eq!(conflicts.len(), 1);
1120 /// assert_eq!(conflicts[0].to_string(), subject.get_key());
1121 /// }
1122 /// ```
1123 pub fn match_conditions(&mut self, conditions: Vec<Condition>) -> Vec<Condition> {
1124 let mut conflicts = Vec::new();
1125 for condition in conditions.into_iter() {
1126 match condition.clone() {
1127 Condition::Category(String) => {
1128 match self.has_category(condition.to_string()) {
1129 false => conflicts.push(condition),
1130 true => {}
1131 };
1132 }
1133 Condition::Subject(String) => {
1134 match self.has_subject(condition.to_string()) {
1135 false => conflicts.push(condition),
1136 true => {}
1137 };
1138 }
1139 Condition::Use(String) => {
1140 match self.has_use(condition.to_string()) {
1141 false => conflicts.push(condition),
1142 true => {}
1143 };
1144 }
1145 }
1146 }
1147
1148 conflicts
1149 }
1150
1151 /// Serialize a DUP object
1152 ///
1153 /// # Arguments
1154 ///
1155 /// * serialized: &str - The string that represents the serialized object.</br>
1156 ///
1157 /// #Example
1158 ///
1159 /// ```rust
1160 /// extern crate pbd;
1161 ///
1162 /// use pbd::dua::policy::{Condition, DUP};
1163 /// use pbd::dua::data_category::DataCategoryFactory;
1164 /// use pbd::dua::data_subject::DataSubjectFactory;
1165 /// use pbd::dua::data_use::DataUseFactory;
1166 ///
1167 /// fn main() {
1168 /// let mut dup = DUP::new(
1169 /// "General Policy".to_string(),
1170 /// "This is a high-level policy.".to_string(),
1171 /// "1.0.1".to_string()
1172 /// );
1173 /// let category_factory = DataCategoryFactory::new();
1174 /// let subject_factory = DataSubjectFactory::new();
1175 /// let use_factory = DataUseFactory::new();
1176 ///
1177 /// dup.associate_category(category_factory.get_category_by_key("system.authentication".to_string()).unwrap());
1178 /// dup.associate_subject(subject_factory.get_subject_by_key("consultant".to_string()).unwrap());
1179 /// dup.associate_use(use_factory.get_use_by_key("analytics.reporting".to_string()).unwrap());
1180 ///
1181 /// println!("{:?}", dup.serialize());
1182 /// }
1183 /// ```
1184 pub fn serialize(&mut self) -> String {
1185 serde_json::to_string(&self).unwrap()
1186 }
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191 use super::*;
1192 use crate::dua::data_category::DataCategoryFactory;
1193 use crate::dua::data_subject::DataSubjectFactory;
1194 use crate::dua::data_use::DataUseFactory;
1195 use std::fs::File;
1196 use std::io::prelude::*;
1197
1198 fn get_data_category() -> DataCategory {
1199 let factory = DataCategoryFactory::new();
1200 factory
1201 .get_category_by_key("system.authentication".to_string())
1202 .unwrap()
1203 }
1204
1205 fn get_data_subject() -> DataSubject {
1206 let factory = DataSubjectFactory::new();
1207 factory
1208 .get_subject_by_key("consultant".to_string())
1209 .unwrap()
1210 }
1211
1212 fn get_data_use() -> DataUse {
1213 let factory = DataUseFactory::new();
1214 factory
1215 .get_use_by_key("essential.service.authentication".to_string())
1216 .unwrap()
1217 }
1218
1219 fn get_dup() -> DUP {
1220 let dup = DUP::new(
1221 "General Policy".to_string(),
1222 "This is a high-level policy.".to_string(),
1223 "1.0.1".to_string(),
1224 );
1225 dup
1226 }
1227
1228 #[test]
1229 fn test_dup_associate_category_ok() {
1230 let mut dup = get_dup();
1231 dup.associate_category(get_data_category());
1232 assert_eq!(dup.get_categories().len(), 1);
1233 }
1234
1235 #[test]
1236 fn test_dup_associate_subject_ok() {
1237 let mut dup = get_dup();
1238 dup.associate_subject(get_data_subject());
1239 assert_eq!(dup.get_subjects().len(), 1);
1240 }
1241
1242 #[test]
1243 fn test_dup_as_html() {
1244 let cfactory = DataCategoryFactory::new();
1245 let sfactory = DataSubjectFactory::new();
1246 let ufactory = DataUseFactory::new();
1247 let mut dup = get_dup();
1248
1249 dup.associate_category(
1250 cfactory
1251 .get_category_by_key("user.behavior.browsing_history".to_string())
1252 .unwrap(),
1253 );
1254 dup.associate_category(
1255 cfactory
1256 .get_category_by_key("user.behavior.media_consumption".to_string())
1257 .unwrap(),
1258 );
1259 dup.associate_subject(sfactory.get_subject_by_key("customer".to_string()).unwrap());
1260 dup.associate_subject(sfactory.get_subject_by_key("prospect".to_string()).unwrap());
1261 dup.associate_use(
1262 ufactory
1263 .get_use_by_key("marketing.advertising.profiling".to_string())
1264 .unwrap(),
1265 );
1266 dup.associate_use(
1267 ufactory
1268 .get_use_by_key("marketing.advertising.serving".to_string())
1269 .unwrap(),
1270 );
1271 dup.associate_use(
1272 ufactory
1273 .get_use_by_key("marketing.communications.email".to_string())
1274 .unwrap(),
1275 );
1276
1277 print!("{}", dup.as_html());
1278 let mut file = File::create("./tests/output/policy.html").unwrap();
1279 file.write_all(dup.as_html().as_bytes()).unwrap();
1280 }
1281
1282 #[test]
1283 fn test_dup_as_text() {
1284 let cfactory = DataCategoryFactory::new();
1285 let sfactory = DataSubjectFactory::new();
1286 let ufactory = DataUseFactory::new();
1287 let mut dup = get_dup();
1288
1289 dup.associate_category(
1290 cfactory
1291 .get_category_by_key("user.behavior.browsing_history".to_string())
1292 .unwrap(),
1293 );
1294 dup.associate_category(
1295 cfactory
1296 .get_category_by_key("user.behavior.media_consumption".to_string())
1297 .unwrap(),
1298 );
1299 dup.associate_subject(sfactory.get_subject_by_key("customer".to_string()).unwrap());
1300 dup.associate_subject(sfactory.get_subject_by_key("prospect".to_string()).unwrap());
1301 dup.associate_use(
1302 ufactory
1303 .get_use_by_key("marketing.advertising.profiling".to_string())
1304 .unwrap(),
1305 );
1306 dup.associate_use(
1307 ufactory
1308 .get_use_by_key("marketing.advertising.serving".to_string())
1309 .unwrap(),
1310 );
1311 dup.associate_use(
1312 ufactory
1313 .get_use_by_key("marketing.communications.email".to_string())
1314 .unwrap(),
1315 );
1316
1317 print!("{}", dup.as_text());
1318 let mut file = File::create("./tests/output/policy.txt").unwrap();
1319 file.write_all(dup.as_text().as_bytes()).unwrap();
1320 }
1321
1322 #[test]
1323 fn test_dup_associate_use_ok() {
1324 let mut dup = get_dup();
1325 dup.associate_use(get_data_use());
1326 assert_eq!(dup.get_uses().len(), 1);
1327 }
1328
1329 #[test]
1330 fn test_dup_disassociate_category_ok() {
1331 let mut dup = get_dup();
1332 dup.associate_category(get_data_category());
1333 assert_eq!(dup.get_categories().len(), 1);
1334
1335 dup.disassociate_category(get_data_category().get_key());
1336 assert_eq!(dup.get_categories().len(), 0);
1337 }
1338
1339 #[test]
1340 fn test_dup_disassociate_subject_ok() {
1341 let mut dup = get_dup();
1342 dup.associate_subject(get_data_subject());
1343 assert_eq!(dup.get_subjects().len(), 1);
1344
1345 dup.disassociate_subject(get_data_subject().get_key());
1346 assert_eq!(dup.get_subjects().len(), 0);
1347 }
1348
1349 #[test]
1350 fn test_dup_disassociate_use_ok() {
1351 let mut dup = get_dup();
1352 dup.associate_use(get_data_use());
1353 assert_eq!(dup.get_uses().len(), 1);
1354
1355 dup.disassociate_use(get_data_use().get_key());
1356 assert_eq!(dup.get_uses().len(), 0);
1357 }
1358
1359 #[test]
1360 fn test_dup_get_category_ok() {
1361 let mut dup = get_dup();
1362 dup.associate_category(get_data_category());
1363
1364 let cat2 = dup.get_category(get_data_category().get_key()).unwrap();
1365 assert_eq!(cat2.description, get_data_category().description);
1366 }
1367
1368 #[test]
1369 fn test_dup_get_subject_ok() {
1370 let mut dup = get_dup();
1371 dup.associate_subject(get_data_subject());
1372
1373 let sub2 = dup.get_subject(get_data_subject().get_key()).unwrap();
1374 assert_eq!(sub2.description, get_data_subject().description);
1375 }
1376
1377 #[test]
1378 fn test_dup_get_use_ok() {
1379 let mut dup = get_dup();
1380 dup.associate_use(get_data_use());
1381
1382 let use2 = dup.get_use(get_data_use().get_key()).unwrap();
1383 assert_eq!(use2.description, get_data_use().description);
1384 }
1385
1386 #[test]
1387 fn test_dup_has_category_ok() {
1388 let mut dup = get_dup();
1389 dup.associate_category(get_data_category());
1390 assert_eq!(dup.has_category(get_data_category().get_key()), true);
1391 }
1392
1393 #[test]
1394 fn test_dup_has_subject_ok() {
1395 let mut dup = get_dup();
1396 dup.associate_subject(get_data_subject());
1397 assert_eq!(dup.has_subject(get_data_subject().get_key()), true);
1398 }
1399
1400 #[test]
1401 fn test_dup_has_use_ok() {
1402 let mut dup = get_dup();
1403 dup.associate_use(get_data_use());
1404 assert_eq!(dup.has_use(get_data_use().get_key()), true);
1405 }
1406
1407 #[test]
1408 fn test_dup_match_conditions_all_found() {
1409 let mut dup = get_dup();
1410 let mut conditions: Vec<Condition> = Vec::new();
1411 conditions.push(Condition::Category(get_data_category().get_key()));
1412 conditions.push(Condition::Subject(get_data_subject().get_key()));
1413 conditions.push(Condition::Use(get_data_use().get_key()));
1414 let conflicts = dup.match_conditions(conditions);
1415 assert_eq!(conflicts.len(), 3);
1416 }
1417
1418 #[test]
1419 fn test_dup_match_conditions_none_found() {
1420 let mut dup = get_dup();
1421 dup.associate_category(get_data_category());
1422 dup.associate_subject(get_data_subject());
1423 dup.associate_use(get_data_use());
1424
1425 let mut conditions: Vec<Condition> = Vec::new();
1426 conditions.push(Condition::Category(get_data_category().get_key()));
1427 conditions.push(Condition::Subject(get_data_subject().get_key()));
1428 conditions.push(Condition::Use(get_data_use().get_key()));
1429 let conflicts = dup.match_conditions(conditions);
1430 assert_eq!(conflicts.len(), 0);
1431 }
1432
1433 #[test]
1434 fn test_dup_match_conditions_some_found() {
1435 let mut dup = get_dup();
1436 dup.associate_category(get_data_category());
1437 dup.associate_use(get_data_use());
1438
1439 let mut conditions: Vec<Condition> = Vec::new();
1440 conditions.push(Condition::Category(get_data_category().get_key()));
1441 conditions.push(Condition::Subject(get_data_subject().get_key()));
1442 conditions.push(Condition::Use(get_data_use().get_key()));
1443 let conflicts = dup.match_conditions(conditions);
1444 assert_eq!(conflicts.len(), 1);
1445 assert_eq!(conflicts[0].to_string(), get_data_subject().get_key());
1446 }
1447
1448 #[test]
1449 fn test_dup_serialize_ok() {
1450 let serialized = r#"{"name":"General Policy","description":"This is a high-level policy.","version":"1.0.1","categories":{"system.authentication":{"name":"Authentication Data","description":"Data used to manage access to the system.","fides_key":"system.authentication","organization_fides_key":"default_organization","parent_key":"system","tags":null,"is_default":true,"active":true}},"subjects":{"consultant":{"name":"Consultant","description":"An individual employed in a consultative/temporary capacity by the organization.","fides_key":"consultant","organization_fides_key":"default_organization","tags":null,"rights":null,"automated_decisions_or_profiling":false,"is_default":true,"active":true}},"uses":{"essential.service.authentication":{"name":"Essential Service Authentication","description":"Authenticate users to the product, service, application or system.","fides_key":"essential.service.authentication","organization_fides_key":"default_organization","parent_key":"essential.service","legal_basis":null,"special_category":null,"recipent":null,"legitimate_interest":false,"legitimate_interest_impact_assessment":null,"tags":null,"is_default":true,"active":true}}}"#;
1451 let mut dup = get_dup();
1452
1453 dup.associate_category(get_data_category());
1454 dup.associate_subject(get_data_subject());
1455 dup.associate_use(get_data_use());
1456
1457 assert_eq!(dup.serialize(), serialized);
1458 }
1459}