diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..46b858b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,569 @@
+# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/language-rules
+
+[*.{cs,vb}]
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
+
+dotnet_diagnostic.ide0001.severity = warning
+dotnet_diagnostic.ide0002.severity = warning
+
+# IDE0003 and IDE0009
+dotnet_diagnostic.sa0001.severity = none
+dotnet_diagnostic.ide0003.severity = warning
+dotnet_diagnostic.ide0009.severity = warning
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_property = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_event = false:warning
+
+dotnet_diagnostic.SA1010.severity = none
+
+dotnet_diagnostic.ide0004.severity = warning
+dotnet_diagnostic.ide0005.severity = warning
+
+# IDE0007 and IDE0008
+dotnet_diagnostic.ide0007.severity = warning
+dotnet_diagnostic.ide0008.severity = warning
+csharp_style_var_when_type_is_apparent = true:warning
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_elsewhere = false:silent
+
+# IDE0010
+dotnet_diagnostic.ide0010.severity = suggestion
+
+# IDE0011
+dotnet_diagnostic.ide0011.severity = warning
+csharp_prefer_braces = when_multiline:warning
+
+# IDE0016
+dotnet_diagnostic.ide0016.severity = warning
+csharp_style_throw_expression = true:warning
+
+# IDE0017
+dotnet_diagnostic.ide0017.severity = suggestion
+dotnet_style_object_initializer = true:suggestion
+
+# IDE0018
+dotnet_diagnostic.ide0018.severity = suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+# IDE0019
+dotnet_diagnostic.ide0019.severity = warning
+csharp_style_pattern_matching_over_as_with_null_check = true:warning
+
+# IDE0020 and IDE0038
+dotnet_diagnostic.ide0020.severity = warning
+dotnet_diagnostic.ide0038.severity = warning
+csharp_style_pattern_matching_over_is_with_cast_check = true:warning
+
+# IDE0021
+dotnet_diagnostic.ide0021.severity = warning
+csharp_style_expression_bodied_constructors = false:warning
+
+# IDE0022
+dotnet_diagnostic.ide0022.severity = suggestion
+csharp_style_expression_bodied_methods = false:suggestion
+
+# IDE0023 and IDE0024
+dotnet_diagnostic.ide0023.severity = suggestion
+dotnet_diagnostic.ide0024.severity = suggestion
+csharp_style_expression_bodied_operators = when_on_single_line:suggestion
+
+# IDE0025
+dotnet_diagnostic.ide0025.severity = warning
+csharp_style_expression_bodied_properties = when_on_single_line:warning
+
+# IDE0026
+dotnet_diagnostic.ide0026.severity = suggestion
+csharp_style_expression_bodied_indexers = when_on_single_line:suggestion
+
+# IDE0027
+dotnet_diagnostic.ide0027.severity = suggestion
+csharp_style_expression_bodied_accessors = when_on_single_line:suggestion
+
+# IDE0028
+dotnet_diagnostic.ide0028.severity = suggestion
+dotnet_style_collection_initializer = true:suggestion
+
+# IDE0029 and IDE0030
+dotnet_diagnostic.ide0029.severity = suggestion
+dotnet_diagnostic.ide0030.severity = suggestion
+dotnet_style_coalesce_expression = true:suggestion
+
+# IDE0031
+dotnet_diagnostic.ide0031.severity = suggestion
+dotnet_style_null_propagation = true:suggestion
+
+# IDE0032
+dotnet_diagnostic.ide0032.severity = warning
+dotnet_style_prefer_auto_properties = true:warning
+
+# IDE0033
+dotnet_diagnostic.ide0033.severity = warning
+dotnet_style_explicit_tuple_names = true:warning
+
+# IDE0034
+dotnet_diagnostic.ide0034.severity = warning
+csharp_prefer_simple_default_expression = true:warning
+
+# IDE0035
+dotnet_diagnostic.ide0035.severity = warning
+
+# IDE0036
+dotnet_diagnostic.ide0036.severity = warning
+csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async
+
+# IDE0037
+dotnet_diagnostic.ide0037.severity = warning
+dotnet_style_prefer_inferred_tuple_names = true:warning
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
+
+# IDE0039
+dotnet_diagnostic.ide0039.severity = suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+
+# IDE0040
+dotnet_diagnostic.ide0040.severity = warning
+dotnet_style_require_accessibility_modifiers = always:warning
+
+# IDE0041
+dotnet_diagnostic.ide0041.severity = warning
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
+
+# IDE0042
+dotnet_diagnostic.ide0042.severity = suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+
+# IDE0044
+dotnet_diagnostic.ide0044.severity = warning
+dotnet_style_readonly_field = true:warning
+
+# IDE0045
+dotnet_diagnostic.ide0045.severity = suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+
+# IDE0046
+dotnet_diagnostic.ide0046.severity = suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+
+# IDE0047 and IDE0048
+dotnet_diagnostic.ide0047.severity = warning
+dotnet_diagnostic.ide0048.severity = warning
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning
+
+# IDE0049
+dotnet_diagnostic.ide0049.severity = warning
+dotnet_style_predefined_type_for_locals_parameters_members = true:warning
+dotnet_style_predefined_type_for_member_access = true:warning
+
+# IDE0050-52
+dotnet_diagnostic.ide0050.severity = warning
+dotnet_diagnostic.ide0051.severity = warning
+dotnet_diagnostic.ide0052.severity = warning
+
+# IDE0053
+dotnet_diagnostic.ide0053.severity = suggestion
+csharp_style_expression_bodied_lambdas = true:suggestion
+
+# IDE0054 and IDE0074
+dotnet_diagnostic.ide0054.severity = suggestion
+dotnet_diagnostic.ide0074.severity = suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+
+# IDE0055
+dotnet_sort_system_directives_first = false
+dotnet_separate_import_directive_groups = false
+dotnet_style_namespace_match_folder = true:warning
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = false
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = no_change
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents_when_block = false
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_after_comma = true
+csharp_space_before_comma = false
+csharp_space_after_dot = false
+csharp_space_before_dot = false
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_around_declaration_statements = false
+csharp_space_before_open_square_brackets = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_square_brackets = false
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
+
+# IDE0056
+dotnet_diagnostic.ide0056.severity = warning
+csharp_style_prefer_index_operator = false:warning
+
+# IDE0057
+dotnet_diagnostic.ide0057.severity = warning
+csharp_style_prefer_range_operator = false:warning
+
+# IDE0058, IDE0059, IDE0060
+dotnet_diagnostic.ide0058.severity = none
+dotnet_diagnostic.ide0059.severity = none
+dotnet_diagnostic.ide0060.severity = none
+csharp_style_unused_value_expression_statement_preference = discard_variable:none
+csharp_style_unused_value_assignment_preference = discard_variable:none
+dotnet_code_quality_unused_parameters = all:none
+
+
+# IDE0061
+dotnet_diagnostic.ide0061.severity = suggestion
+csharp_style_expression_bodied_local_functions = false:suggestion
+
+# IDE0062
+dotnet_diagnostic.ide0062.severity = suggestion
+csharp_prefer_static_local_function = true:suggestion
+
+# IDE0063
+dotnet_diagnostic.ide0063.severity = warning
+csharp_prefer_simple_using_statement = true:warning
+
+# IDE0064
+dotnet_diagnostic.ide0064.severity = warning
+dotnet_diagnostic.ide0064.severity = none
+
+# IDE0065
+dotnet_diagnostic.ide0065.severity = warning
+csharp_using_directive_placement = outside_namespace:warning
+
+# IDE0066
+dotnet_diagnostic.ide0066.severity = warning
+csharp_style_prefer_switch_expression = true:warning
+
+# IDE0070
+dotnet_diagnostic.ide0070.severity = warning
+
+# IDE0071
+dotnet_diagnostic.ide0071.severity = none
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+
+# IDE0072
+dotnet_diagnostic.ide0072.severity = warning
+
+# IDE0073
+file_header_template = unset
+
+# IDE0075
+dotnet_diagnostic.ide0075.severity = suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+
+# IDE0078
+# dotnet_diagnostic.IDE0078.severity = warning
+# csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_pattern_matching = true:none
+
+# IDE0082
+dotnet_diagnostic.ide0082.severity = warning
+
+# IDE0083
+dotnet_diagnostic.ide0083.severity = warning
+csharp_style_prefer_not_pattern = true:warning
+
+# IDE0090
+dotnet_diagnostic.ide0090.severity = warning
+csharp_style_implicit_object_creation_when_type_is_apparent = false:warning
+
+# IDE0100
+dotnet_diagnostic.ide0100.severity = warning
+
+# IDE0110
+dotnet_diagnostic.ide0110.severity = warning
+
+# IDE0150
+dotnet_diagnostic.ide0150.severity = warning
+csharp_style_prefer_null_check_over_type_check = false:warning
+
+# IDE0160 and IDE0161
+dotnet_diagnostic.ide0161.severity = warning
+csharp_style_namespace_declarations = file_scoped:warning
+
+# IDE0170
+dotnet_diagnostic.ide0170.severity = none
+csharp_style_prefer_extended_property_pattern = true:none
+
+# IDE0180
+dotnet_diagnostic.ide0180.severity = suggestion
+csharp_style_prefer_tuple_swap = false:suggestion
+
+# IDE1005
+dotnet_diagnostic.ide1005.severity = suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+dotnet_diagnostic.ca1000.severity = none
+dotnet_diagnostic.ca1001.severity = warning
+dotnet_diagnostic.ca1002.severity = warning
+dotnet_diagnostic.ca1003.severity = none
+dotnet_diagnostic.ca1005.severity = none
+dotnet_diagnostic.ca1008.severity = none
+dotnet_diagnostic.ca1010.severity = warning
+dotnet_diagnostic.ca1012.severity = warning
+dotnet_diagnostic.ca1014.severity = none
+dotnet_diagnostic.ca1016.severity = none
+dotnet_diagnostic.ca1017.severity = none
+dotnet_diagnostic.ca1018.severity = warning
+dotnet_diagnostic.ca1019.severity = warning
+dotnet_diagnostic.ca1021.severity = warning
+dotnet_diagnostic.ca1024.severity = suggestion
+dotnet_diagnostic.ca1027.severity = none
+dotnet_diagnostic.ca1028.severity = warning
+dotnet_diagnostic.ca1030.severity = none
+dotnet_diagnostic.ca1031.severity = none
+dotnet_diagnostic.ca1032.severity = none
+dotnet_diagnostic.ca1033.severity = none
+dotnet_diagnostic.ca1034.severity = none
+dotnet_diagnostic.ca1036.severity = silent
+dotnet_diagnostic.ca1040.severity = none
+dotnet_diagnostic.ca1041.severity = suggestion
+dotnet_diagnostic.ca1043.severity = none
+dotnet_diagnostic.ca1044.severity = warning
+dotnet_diagnostic.ca1045.severity = warning
+dotnet_diagnostic.ca1046.severity = suggestion
+dotnet_diagnostic.ca1047.severity = warning
+dotnet_diagnostic.ca1050.severity = warning
+dotnet_diagnostic.ca1051.severity = warning
+dotnet_diagnostic.ca1052.severity = none
+dotnet_diagnostic.ca1053.severity = none
+dotnet_diagnostic.ca1054.severity = suggestion
+dotnet_diagnostic.ca1055.severity = suggestion
+dotnet_diagnostic.ca1056.severity = suggestion
+dotnet_diagnostic.ca1058.severity = warning
+dotnet_diagnostic.ca1060.severity = none
+dotnet_diagnostic.ca1061.severity = warning
+dotnet_diagnostic.ca1062.severity = none
+dotnet_diagnostic.ca1063.severity = none
+dotnet_diagnostic.ca1064.severity = warning
+dotnet_diagnostic.ca1065.severity = warning
+dotnet_diagnostic.ca1067.severity = warning
+dotnet_diagnostic.ca1068.severity = suggestion
+dotnet_diagnostic.ca1069.severity = warning
+dotnet_diagnostic.ca1079.severity = warning
+dotnet_diagnostic.ca1200.severity = none
+dotnet_diagnostic.ca1303.severity = none
+dotnet_diagnostic.ca1304.severity = none
+dotnet_diagnostic.ca1305.severity = none
+dotnet_diagnostic.ca1307.severity = warning
+dotnet_diagnostic.ca1308.severity = suggestion
+dotnet_diagnostic.ca1309.severity = suggestion
+dotnet_diagnostic.ca1310.severity = suggestion
+dotnet_diagnostic.ca1401.severity = warning
+dotnet_diagnostic.ca1416.severity = warning
+dotnet_diagnostic.ca1417.severity = warning
+dotnet_diagnostic.ca1418.severity = warning
+dotnet_diagnostic.ca1419.severity = warning
+dotnet_diagnostic.ca1501.severity = warning
+dotnet_diagnostic.ca1502.severity = warning
+dotnet_diagnostic.ca1505.severity = warning
+dotnet_diagnostic.ca1506.severity = warning
+dotnet_diagnostic.ca1507.severity = suggestion
+dotnet_diagnostic.ca1508.severity = warning
+# dotnet_diagnostic.CA1509.severity = none
+dotnet_diagnostic.ca1700.severity = none
+dotnet_diagnostic.ca1707.severity = warning
+dotnet_diagnostic.ca1708.severity = none
+dotnet_diagnostic.ca1710.severity = none
+dotnet_diagnostic.ca1711.severity = none
+dotnet_diagnostic.ca1712.severity = none
+dotnet_diagnostic.ca1713.severity = none
+dotnet_diagnostic.ca1714.severity = suggestion
+dotnet_diagnostic.ca1715.severity = warning
+dotnet_diagnostic.ca1716.severity = warning
+dotnet_diagnostic.ca1717.severity = none
+dotnet_diagnostic.ca1720.severity = warning
+dotnet_diagnostic.ca1721.severity = warning
+dotnet_diagnostic.ca1724.severity = warning
+dotnet_diagnostic.ca1725.severity = warning
+dotnet_diagnostic.ca1727.severity = none
+dotnet_diagnostic.ca1801.severity = warning
+dotnet_diagnostic.ca1802.severity = warning
+dotnet_diagnostic.ca1805.severity = none
+dotnet_diagnostic.ca1806.severity = none
+dotnet_diagnostic.ca1810.severity = none
+dotnet_diagnostic.ca1812.severity = none
+# dotnet_diagnostic.CA1812.severity = warning
+dotnet_diagnostic.ca1813.severity = warning
+dotnet_diagnostic.ca1814.severity = warning
+dotnet_diagnostic.ca1815.severity = suggestion
+dotnet_diagnostic.ca1816.severity = none
+dotnet_diagnostic.ca1819.severity = none
+dotnet_diagnostic.ca1820.severity = warning
+dotnet_diagnostic.ca1821.severity = warning
+dotnet_diagnostic.ca1822.severity = none
+dotnet_diagnostic.ca1823.severity = warning
+dotnet_diagnostic.ca1824.severity = none
+dotnet_diagnostic.ca1825.severity = warning
+dotnet_diagnostic.ca1826.severity = none
+dotnet_diagnostic.ca1827.severity = warning
+dotnet_diagnostic.ca1828.severity = warning
+dotnet_diagnostic.ca1829.severity = warning
+dotnet_diagnostic.ca1830.severity = suggestion
+dotnet_diagnostic.ca1831.severity = suggestion
+dotnet_diagnostic.ca1832.severity = suggestion
+dotnet_diagnostic.ca1833.severity = suggestion
+dotnet_diagnostic.ca1834.severity = suggestion
+dotnet_diagnostic.ca1835.severity = suggestion
+dotnet_diagnostic.ca1836.severity = warning
+dotnet_diagnostic.ca1837.severity = warning
+dotnet_diagnostic.ca1838.severity = warning
+dotnet_diagnostic.ca1841.severity = none
+dotnet_diagnostic.ca1842.severity = none
+dotnet_diagnostic.ca1843.severity = none
+dotnet_diagnostic.ca1844.severity = warning
+dotnet_diagnostic.ca1845.severity = suggestion
+dotnet_diagnostic.ca1846.severity = suggestion
+dotnet_diagnostic.ca1847.severity = suggestion
+dotnet_diagnostic.ca1848.severity = none
+dotnet_diagnostic.ca1849.severity = suggestion
+dotnet_diagnostic.ca1850.severity = suggestion
+dotnet_diagnostic.ca1851.severity = warning
+dotnet_diagnostic.ca1854.severity = suggestion
+dotnet_diagnostic.ca2000.severity = suggestion
+# dotnet_diagnostic.CA2000.severity = warning
+dotnet_diagnostic.ca2002.severity = none
+dotnet_diagnostic.ca2008.severity = none
+dotnet_diagnostic.ca2009.severity = warning
+dotnet_diagnostic.ca2011.severity = warning
+dotnet_diagnostic.ca2012.severity = warning
+dotnet_diagnostic.ca2013.severity = warning
+dotnet_diagnostic.ca2014.severity = warning
+dotnet_diagnostic.ca2015.severity = warning
+dotnet_diagnostic.ca2016.severity = suggestion
+dotnet_diagnostic.ca2017.severity = warning
+dotnet_diagnostic.ca2018.severity = warning
+dotnet_diagnostic.ca2100.severity = warning
+dotnet_diagnostic.ca2101.severity = none
+dotnet_diagnostic.ca2201.severity = suggestion
+# dotnet_diagnostic.CA2201.severity = warning
+dotnet_diagnostic.ca2207.severity = warning
+dotnet_diagnostic.ca2208.severity = warning
+dotnet_diagnostic.ca2211.severity = suggestion
+dotnet_diagnostic.ca2213.severity = warning
+dotnet_diagnostic.ca2214.severity = suggestion
+dotnet_diagnostic.ca2215.severity = warning
+dotnet_diagnostic.ca2216.severity = none
+dotnet_diagnostic.ca2217.severity = none
+dotnet_diagnostic.ca2218.severity = warning
+dotnet_diagnostic.ca2219.severity = warning
+dotnet_diagnostic.ca2224.severity = warning
+dotnet_diagnostic.ca2225.severity = none
+dotnet_diagnostic.ca2226.severity = suggestion
+dotnet_diagnostic.ca2227.severity = warning
+dotnet_diagnostic.ca2229.severity = none
+dotnet_diagnostic.ca2231.severity = suggestion
+dotnet_diagnostic.ca2234.severity = silent
+dotnet_diagnostic.ca2235.severity = none
+dotnet_diagnostic.ca2237.severity = none
+dotnet_diagnostic.ca2241.severity = warning
+dotnet_diagnostic.ca2242.severity = warning
+dotnet_diagnostic.ca2243.severity = warning
+dotnet_diagnostic.ca2244.severity = warning
+dotnet_diagnostic.ca2245.severity = warning
+dotnet_diagnostic.ca2246.severity = warning
+dotnet_diagnostic.ca2247.severity = warning
+dotnet_diagnostic.ca2248.severity = warning
+dotnet_diagnostic.ca2249.severity = warning
+dotnet_diagnostic.ca2250.severity = warning
+dotnet_diagnostic.ca2251.severity = warning
+dotnet_diagnostic.ca2252.severity = none
+dotnet_diagnostic.ca2253.severity = warning
+dotnet_diagnostic.ca2254.severity = none
+dotnet_diagnostic.ca2255.severity = none
+dotnet_diagnostic.ca2256.severity = none
+dotnet_diagnostic.ca2257.severity = none
+dotnet_diagnostic.ca2258.severity = none
+
+# IDE1006
+dotnet_diagnostic.ide1006.severity = warning
+
+# camel_case_style - Define the camelCase style
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+# pascal_case_style - Define the PascalCase style
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+# first_upper_style - The first character must start with an upper-case character
+dotnet_naming_style.first_upper_style.capitalization = first_word_upper
+# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
+dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
+dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
+# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
+dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
+dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
+# disallowed_style - Anything that has this style applied is marked as disallowed
+dotnet_naming_style.disallowed_style.capitalization = pascal_case
+dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
+dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
+dotnet_naming_style.internal_error_style.capitalization = pascal_case
+dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
+dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
+
+dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
+dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
+dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
+dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
+dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
+dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
+
+dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
+dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
+dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
+dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
+dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
+dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
+
+dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
+dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
+dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
+dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
+dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
+
+# Other
+
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+
+
+# Not verified
+
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+# IDE0230
+csharp_style_prefer_utf8_string_literals = true:suggestion
+
+# ReSharper
+resharper_csharp_empty_block_style = together_same_line
+
+csharp_wrap_arguments_style = chop_if_long
+csharp_wrap_chained_method_calls = chop_if_long
+
+# ReSharper properties
+resharper_csharp_wrap_after_declaration_lpar = true
+resharper_csharp_wrap_parameters_style = chop_if_long
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
deleted file mode 100644
index 2e503d0..0000000
--- a/.github/workflows/main.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Swagger to HTML
-
-on:
- push:
- branches:
- - swaggerhub
-
-jobs:
- generate-and-commit-html:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- node-version: '14'
-
- - name: Install Redoc CLI
- run: npm install -g redoc-cli
-
- - name: Generate HTML from Swagger YAML
- run: redoc-cli bundle swagger.yaml -o node-output/swagger.html
-
- - name: Commit and Push HTML
- run: |
- git config --local user.email "action@github.com"
- git config --local user.name "GitHub Action"
- git add node-output/swagger.html
- git commit -m "Generate HTML from Swagger YAML" || echo "No changes to commit"
- git push origin HEAD:swaggerhub
diff --git a/Directory.Packages.props b/Directory.Packages.props
index a9605f2..aa16be3 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,15 +4,24 @@
false
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
+
+
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/DoctorsHelp.Application.Contracts.csproj b/src/Application/DoctorsHelp.Application.Contracts/DoctorsHelp.Application.Contracts.csproj
index a613ac5..0efbdd7 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/DoctorsHelp.Application.Contracts.csproj
+++ b/src/Application/DoctorsHelp.Application.Contracts/DoctorsHelp.Application.Contracts.csproj
@@ -1,10 +1,8 @@
+
-
-
-
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/IAppointmentService.cs b/src/Application/DoctorsHelp.Application.Contracts/IAppointmentService.cs
index 6aacce2..2e2c83f 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/IAppointmentService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/IAppointmentService.cs
@@ -4,11 +4,11 @@ namespace DoctorsHelp.Application.Contracts;
public interface IAppointmentService
{
- Appointment Create(User patient, Schedule schedule);
+ Appointment Create(Guid patientId, Guid scheduleId);
- Appointment GetAppointment(int patientId);
+ Appointment? GetAppointment(Guid patientId);
- Appointment Update(int id, Dictionary data);
+ Appointment? Update(Guid id, Dictionary data);
- bool Delete(int id);
-}
\ No newline at end of file
+ bool Delete(Guid id);
+}
diff --git a/src/Application/DoctorsHelp.Application.Contracts/IEmployeeService.cs b/src/Application/DoctorsHelp.Application.Contracts/IEmployeeService.cs
index 1ea302c..f05b4c5 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/IEmployeeService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/IEmployeeService.cs
@@ -4,13 +4,11 @@ namespace DoctorsHelp.Application.Contracts;
public interface IEmployeeService
{
- Employee Create(User user, Specialization specialization, string graduate, string experience);
+ Employee Create(Guid userId, Guid specializationId, string graduate, string experience);
- Employee GetEmployee();
+ Employee? GetEmployee(Guid employeeId);
- Employee GetById(int id);
+ Employee? Update(Guid id, Dictionary data);
- Employee Update(int id, Dictionary data);
-
- bool Delete(int id);
+ bool Delete(Guid id);
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/IReviewService.cs b/src/Application/DoctorsHelp.Application.Contracts/IReviewService.cs
index a36b487..9c298b9 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/IReviewService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/IReviewService.cs
@@ -4,11 +4,11 @@ namespace DoctorsHelp.Application.Contracts;
public interface IReviewService
{
- Review Create(Appointment appointment, int grade, string comment);
+ Review Create(Guid appointmentId, int? grade, string comment);
- Review GetReview(int appointmentId);
+ Review? GetReview(Guid reviewId);
- Review Update(int id, Dictionary data);
+ Review? Update(Guid id, Dictionary data);
- bool Delete(int id);
+ bool Delete(Guid id);
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/IScheduleService.cs b/src/Application/DoctorsHelp.Application.Contracts/IScheduleService.cs
index 9bc72e0..37253dc 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/IScheduleService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/IScheduleService.cs
@@ -4,11 +4,11 @@ namespace DoctorsHelp.Application.Contracts;
public interface IScheduleService
{
- Review Create(Employee employee, DateTime dateStart, DateTime dateEnd);
+ Schedule Create(Guid employeeId, DateTime? dateStart, DateTime? dateEnd);
- Review GeSchedule(int employeeId);
+ Schedule? GetSchedule(Guid scheduleId);
- Review Update(int id, Dictionary data);
+ Schedule? Update(Guid id, Dictionary data);
- bool Delete(int id);
+ bool Delete(Guid id);
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/ISpecializationService.cs b/src/Application/DoctorsHelp.Application.Contracts/ISpecializationService.cs
index 9591000..04fc389 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/ISpecializationService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/ISpecializationService.cs
@@ -6,9 +6,9 @@ public interface ISpecializationService
{
Specialization Create(string name, string description);
- Specialization GetSpecialization(int id);
+ Specialization? GetSpecialization(Guid id);
- Specialization Update(int id, Dictionary data);
+ Specialization? Update(Guid id, Dictionary data);
- bool Delete(int id);
+ bool Delete(Guid id);
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/IUserService.cs b/src/Application/DoctorsHelp.Application.Contracts/IUserService.cs
index 999f393..8123b02 100644
--- a/src/Application/DoctorsHelp.Application.Contracts/IUserService.cs
+++ b/src/Application/DoctorsHelp.Application.Contracts/IUserService.cs
@@ -4,13 +4,11 @@ namespace DoctorsHelp.Application.Contracts;
public interface IUserService
{
- User Register(string name, string surname, string phone, string email, string password, DateTime birthdate);
+ User Register(string name, string surname, string phone, string email, string password, DateOnly? birthdate);
- User Login(string phone, string password);
+ User? GetUser(Guid id);
- User GetUser(int id);
+ User? UpdateUser(Guid id, Dictionary data);
- User Update(int id, Dictionary data);
-
- bool Delete(int id);
+ bool DeleteUser(Guid id);
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/AppointmentService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/AppointmentService.cs
new file mode 100644
index 0000000..8c65a42
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/AppointmentService.cs
@@ -0,0 +1,97 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class AppointmentService : IAppointmentService
+{
+ private readonly IAppointmentRepository _appointmentRepository;
+ private readonly IUserRepository _patientRepository;
+ private readonly IScheduleRepository _scheduleRepository;
+
+ public AppointmentService(IAppointmentRepository appointmentRepository, IUserRepository userRepository, IScheduleRepository scheduleRepository)
+ {
+ _appointmentRepository = appointmentRepository;
+ _patientRepository = userRepository;
+ _scheduleRepository = scheduleRepository;
+ }
+
+ public Appointment Create(Guid patientId, Guid scheduleId)
+ {
+ User? patient = UserConverter.UserModelToUser(_patientRepository.GetUser(patientId));
+ Schedule? schedule = ScheduleConverter.ScheduleModelToSchedule(_scheduleRepository.GetSchedule(scheduleId));
+
+ if (patient is null)
+ throw new Exception("Patient doesnt exist");
+ if (schedule is null)
+ throw new Exception("Schedule doesnt exist");
+
+ var appointment = new Appointment
+ {
+ Id = Guid.NewGuid(),
+ Patient = patient,
+ Schedule = schedule,
+ };
+ _appointmentRepository.AddAppointment(appointment);
+ return appointment;
+ }
+
+ public Appointment? GetAppointment(Guid patientId)
+ {
+ var appointmentModel = _appointmentRepository.GetAppointment(patientId);
+
+ if (appointmentModel is not null)
+ {
+ appointmentModel.Patient = _patientRepository.GetUser(appointmentModel.PatientId);
+ appointmentModel.Schedule = _scheduleRepository.GetSchedule(appointmentModel.ScheduleId);
+ }
+
+ return AppointmentConverter.AppointmentModelToAppointment(appointmentModel);
+ }
+
+ public Appointment? Update(Guid id, Dictionary data)
+ {
+ AppointmentModel? appointmentToUpdate = _appointmentRepository.GetAppointment(id);
+
+ if (appointmentToUpdate is null)
+ throw new Exception("No such appointment");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "patientId":
+ Guid patientId;
+ if (Guid.TryParse(entry.Value, out patientId))
+ appointmentToUpdate.PatientId = patientId;
+ break;
+ case "scheduleId":
+ Guid scheduleId;
+ if (Guid.TryParse(entry.Value, out scheduleId))
+ appointmentToUpdate.ScheduleId = scheduleId;
+ break;
+ case "status":
+ int status;
+ if (int.TryParse(entry.Value, out status))
+ appointmentToUpdate.Status = status;
+ break;
+ }
+ }
+
+ var appointment = AppointmentConverter.AppointmentModelToAppointment(appointmentToUpdate);
+
+ if (appointment is null)
+ return null;
+
+ _appointmentRepository.UpdateAppointment(appointment);
+
+ return AppointmentConverter.AppointmentModelToAppointment(appointmentToUpdate);
+ }
+
+ public bool Delete(Guid id)
+ {
+ return _appointmentRepository.Delete(new Appointment { Id = id, });
+ }
+}
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/EmployeeService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/EmployeeService.cs
new file mode 100644
index 0000000..7028669
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/EmployeeService.cs
@@ -0,0 +1,100 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class EmployeeService : IEmployeeService
+{
+ private readonly IEmployeeRepository _employeeRepository;
+ private readonly IUserRepository _userRepository;
+ private readonly ISpecializationRepository _specializationRepository;
+
+ public EmployeeService(IEmployeeRepository appointmentRepository, IUserRepository userRepository, ISpecializationRepository specializationRepository)
+ {
+ _employeeRepository = appointmentRepository;
+ _userRepository = userRepository;
+ _specializationRepository = specializationRepository;
+ }
+
+ public Employee Create(Guid userId, Guid specializationId, string graduate, string experience)
+ {
+ User? user = UserConverter.UserModelToUser(_userRepository.GetUser(userId));
+ Specialization? specialization = SpecializationConverter.SpecializationModelToSpecialization(_specializationRepository.GetSpecialization(specializationId));
+
+ if (user is null)
+ throw new Exception("user doesnt exist");
+ if (specialization is null)
+ throw new Exception("specialization doesnt exist");
+
+ var employee = new Employee
+ {
+ Id = Guid.NewGuid(),
+ User = user,
+ Specialization = specialization,
+ Graduate = graduate,
+ Experience = experience,
+ };
+ _employeeRepository.AddEmployee(employee);
+ return employee;
+ }
+
+ public Employee? GetEmployee(Guid employeeId)
+ {
+ EmployeeModel? employeeModel = _employeeRepository.GetEmployee(employeeId);
+
+ if (employeeModel is not null)
+ {
+ employeeModel.User = _userRepository.GetUser(employeeModel.UserId);
+ employeeModel.Specialization = _specializationRepository.GetSpecialization(employeeModel.SpecializationId);
+ }
+
+ return EmployeeConverter.EmployeeModelToEmployee(employeeModel);
+ }
+
+ public Employee? Update(Guid id, Dictionary data)
+ {
+ EmployeeModel? employeeToUpdate = _employeeRepository.GetEmployee(id);
+
+ if (employeeToUpdate is null)
+ throw new Exception("No such employee");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "UserId":
+ Guid userId;
+ if (Guid.TryParse(entry.Value, out userId))
+ employeeToUpdate.UserId = userId;
+ break;
+ case "SpecializationId":
+ Guid specializationId;
+ if (Guid.TryParse(entry.Value, out specializationId))
+ employeeToUpdate.SpecializationId = specializationId;
+ break;
+ case "Graduate":
+ employeeToUpdate.Graduate = entry.Value;
+ break;
+ case "Experience":
+ employeeToUpdate.Experience = entry.Value;
+ break;
+ }
+ }
+
+ var employee = EmployeeConverter.EmployeeModelToEmployee(employeeToUpdate);
+
+ if (employee is null)
+ return null;
+
+ _employeeRepository.UpdateEmployee(employee);
+
+ return EmployeeConverter.EmployeeModelToEmployee(employeeToUpdate);
+ }
+
+ public bool Delete(Guid id)
+ {
+ return _employeeRepository.Delete(new Employee { Id = id, });
+ }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/ReviewService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/ReviewService.cs
new file mode 100644
index 0000000..2f8cf4b
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/ReviewService.cs
@@ -0,0 +1,85 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class ReviewService : IReviewService
+{
+ private readonly IReviewRepository _reviewRepository;
+ private readonly IAppointmentRepository _appointmentRepository;
+
+ public ReviewService(IReviewRepository reviewRepository, IAppointmentRepository appointmentRepository)
+ {
+ _reviewRepository = reviewRepository;
+ _appointmentRepository = appointmentRepository;
+ }
+
+ public Review Create(Guid appointmentId, int? grade, string comment)
+ {
+ Appointment? appointment = AppointmentConverter.AppointmentModelToAppointment(_appointmentRepository.GetAppointment(appointmentId));
+
+ if (appointment is null)
+ throw new Exception("appointment doesnt exist");
+
+ var review = new Review
+ {
+ Id = Guid.NewGuid(),
+ Appointment = appointment,
+ Grade = grade,
+ Comment = comment,
+ };
+ _reviewRepository.AddReview(review);
+ return review;
+ }
+
+ public Review? GetReview(Guid reviewId)
+ {
+ var reviewModel = _reviewRepository.GetReview(reviewId);
+
+ if (reviewModel is not null)
+ reviewModel.Appointment = _appointmentRepository.GetAppointment(reviewModel.AppointmentId);
+
+ return ReviewConverter.ReviewModelToReview(reviewModel);
+ }
+
+ public Review? Update(Guid id, Dictionary data)
+ {
+ ReviewModel? reviewToUpdate = _reviewRepository.GetReview(id);
+
+ if (reviewToUpdate is null)
+ throw new Exception("No such review");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "appointmentId":
+ Guid appointmentId;
+ if (Guid.TryParse(entry.Value, out appointmentId))
+ reviewToUpdate.AppointmentId = appointmentId;
+ break;
+ case "rating":
+ int grade;
+ if (int.TryParse(entry.Value, out grade))
+ reviewToUpdate.Grade = grade;
+ break;
+ case "comment":
+ reviewToUpdate.Comment = entry.Value;
+ break;
+ }
+ }
+
+ var review = ReviewConverter.ReviewModelToReview(reviewToUpdate);
+
+ _reviewRepository.UpdateReview(review);
+
+ return ReviewConverter.ReviewModelToReview(reviewToUpdate);
+ }
+
+ public bool Delete(Guid id)
+ {
+ return _reviewRepository.Delete(new Review { Id = id });
+ }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/ScheduleService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/ScheduleService.cs
new file mode 100644
index 0000000..7a7e262
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/ScheduleService.cs
@@ -0,0 +1,86 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class ScheduleService : IScheduleService
+{
+ private readonly IScheduleRepository _scheduleRepository;
+ private readonly IEmployeeRepository _employeeRepository;
+
+ public ScheduleService(IScheduleRepository scheduleRepository, IEmployeeRepository employeeRepository)
+ {
+ _scheduleRepository = scheduleRepository;
+ _employeeRepository = employeeRepository;
+ }
+
+ public Schedule Create(Guid employeeId, DateTime? dateStart, DateTime? dateEnd)
+ {
+ Employee? employee = EmployeeConverter.EmployeeModelToEmployee(_employeeRepository.GetEmployee(employeeId));
+
+ if (employee is null)
+ throw new Exception("employee doesnt exist");
+
+ var schedule = new Schedule
+ {
+ Id = Guid.NewGuid(),
+ Employee = employee,
+ DateStart = dateStart,
+ DateEnd = dateEnd,
+ };
+ _scheduleRepository.AddSchedule(schedule);
+ return schedule;
+ }
+
+ public Schedule? GetSchedule(Guid scheduleId)
+ {
+ var scheduleModel = _scheduleRepository.GetSchedule(scheduleId);
+
+ if (scheduleModel is not null)
+ scheduleModel.Employee = _employeeRepository.GetEmployee(scheduleModel.EmployeeId);
+
+ return ScheduleConverter.ScheduleModelToSchedule(scheduleModel);
+ }
+
+ public Schedule? Update(Guid id, Dictionary data)
+ {
+ ScheduleModel? scheduleToUpdate = _scheduleRepository.GetSchedule(id);
+
+ if (scheduleToUpdate is null)
+ throw new Exception("No such schedule");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "employeeId":
+ Guid employeeId;
+ if (Guid.TryParse(entry.Value, out employeeId))
+ scheduleToUpdate.EmployeeId = employeeId;
+ break;
+ case "dateStart":
+ scheduleToUpdate.DateStart = new DateTime(Convert.ToInt32(entry.Value));
+ break;
+ case "dateEnd":
+ scheduleToUpdate.DateEnd = new DateTime(Convert.ToInt32(entry.Value));
+ break;
+ }
+ }
+
+ var schedule = ScheduleConverter.ScheduleModelToSchedule(scheduleToUpdate);
+
+ if (schedule is null)
+ return null;
+
+ _scheduleRepository.UpdateSchedule(schedule);
+
+ return ScheduleConverter.ScheduleModelToSchedule(scheduleToUpdate);
+ }
+
+ public bool Delete(Guid id)
+ {
+ return _scheduleRepository.Delete(new Schedule { Id = id, });
+ }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/SpecializationService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/SpecializationService.cs
new file mode 100644
index 0000000..97d6eb8
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/SpecializationService.cs
@@ -0,0 +1,70 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class SpecializationService : ISpecializationService
+{
+ private readonly ISpecializationRepository _specializationRepository;
+
+ public SpecializationService(ISpecializationRepository specializationRepository)
+ {
+ _specializationRepository = specializationRepository;
+ }
+
+ public Specialization Create(string name, string description)
+ {
+ var specialization = new Specialization
+ {
+ Id = Guid.NewGuid(),
+ Name = name,
+ Description = description,
+ };
+ _specializationRepository.AddSpecialization(specialization);
+ return specialization;
+ }
+
+ public Specialization? GetSpecialization(Guid id)
+ {
+ SpecializationModel? specializationModel = _specializationRepository.GetSpecialization(id);
+
+ return SpecializationConverter.SpecializationModelToSpecialization(specializationModel);
+ }
+
+ public Specialization? Update(Guid id, Dictionary data)
+ {
+ SpecializationModel? specializationToUpdate = _specializationRepository.GetSpecialization(id);
+
+ if (specializationToUpdate is null)
+ throw new Exception("No such specialization");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "name":
+ specializationToUpdate.Name = entry.Value;
+ break;
+ case "description":
+ specializationToUpdate.Description = entry.Value;
+ break;
+ }
+ }
+
+ var specialization = SpecializationConverter.SpecializationModelToSpecialization(specializationToUpdate);
+
+ if (specialization is null)
+ return null;
+
+ _specializationRepository.UpdateSpecialization(specialization);
+
+ return SpecializationConverter.SpecializationModelToSpecialization(specializationToUpdate);
+ }
+
+ public bool Delete(Guid id)
+ {
+ return _specializationRepository.Delete(new Specialization { Id = id });
+ }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Contracts/Services/UserService.cs b/src/Application/DoctorsHelp.Application.Contracts/Services/UserService.cs
new file mode 100644
index 0000000..885680f
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Contracts/Services/UserService.cs
@@ -0,0 +1,80 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Converters;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Application.Contracts.Services;
+
+public class UserService : IUserService
+{
+ private readonly IUserRepository _userRepository;
+
+ public UserService(IUserRepository userRepository)
+ {
+ _userRepository = userRepository;
+ }
+
+ public User Register(string name, string surname, string phone, string email, string password, DateOnly? birthdate)
+ {
+ var user = new User
+ {
+ Id = Guid.NewGuid(),
+ Name = name,
+ Surname = surname,
+ HashedPassword = password,
+ Phone = phone,
+ Email = email,
+ Birthdate = birthdate,
+ };
+ _userRepository.Add(user);
+ return user;
+ }
+
+ public User? GetUser(Guid id)
+ {
+ var userModel = _userRepository.GetUser(id);
+
+ return UserConverter.UserModelToUser(userModel);
+ }
+
+ public User? UpdateUser(Guid id, Dictionary data)
+ {
+ UserModel? userToUpdate = _userRepository.GetUser(id);
+
+ if (userToUpdate is null)
+ throw new Exception("No such user");
+
+ foreach (var entry in data)
+ {
+ switch (entry.Key)
+ {
+ case "name":
+ userToUpdate.Name = entry.Value;
+ break;
+ case "surname":
+ userToUpdate.Surname = entry.Value;
+ break;
+ case "phone":
+ userToUpdate.Phone = entry.Value;
+ break;
+ case "email":
+ userToUpdate.Email = entry.Value;
+ break;
+ }
+ }
+
+ var user = UserConverter.UserModelToUser(userToUpdate);
+
+ if (user is null)
+ return null;
+
+ _userRepository.UpdateUser(user);
+
+ return UserConverter.UserModelToUser(userToUpdate);
+ }
+
+ public bool DeleteUser(Guid id)
+ {
+ return _userRepository.Delete(new User { Id = id });
+ }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Models/Appointment.cs b/src/Application/DoctorsHelp.Application.Models/Appointment.cs
index 3f2a153..b43508d 100644
--- a/src/Application/DoctorsHelp.Application.Models/Appointment.cs
+++ b/src/Application/DoctorsHelp.Application.Models/Appointment.cs
@@ -1,16 +1,16 @@
namespace DoctorsHelp.Application.Models;
-public class Appointment
+public class Appointment : IEntity
{
- public int Id { get; set; }
+ public Guid? Id { get; set; }
public User? Patient { get; set; }
public Schedule? Schedule { get; set; }
- public DateTime CreatedAt { get; set; }
+ public DateTime? CreatedAt { get; set; }
- public DateTime UpdatedAt { get; set; }
+ public DateTime? UpdatedAt { get; set; }
- public int Status { get; set; }
+ public int? Status { get; set; }
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Models/DoctorsHelp.Application.Models.csproj b/src/Application/DoctorsHelp.Application.Models/DoctorsHelp.Application.Models.csproj
index 35e3d84..6b512ec 100644
--- a/src/Application/DoctorsHelp.Application.Models/DoctorsHelp.Application.Models.csproj
+++ b/src/Application/DoctorsHelp.Application.Models/DoctorsHelp.Application.Models.csproj
@@ -1,2 +1 @@
-
-
+
diff --git a/src/Application/DoctorsHelp.Application.Models/Employee.cs b/src/Application/DoctorsHelp.Application.Models/Employee.cs
index 66440a8..7a14f36 100644
--- a/src/Application/DoctorsHelp.Application.Models/Employee.cs
+++ b/src/Application/DoctorsHelp.Application.Models/Employee.cs
@@ -1,12 +1,12 @@
namespace DoctorsHelp.Application.Models;
-public class Employee
+public class Employee : IEntity
{
- public int Id { get; set; }
+ public Guid? Id { get; set; }
public User? User { get; set; }
- public int Specialization { get; set; }
+ public Specialization? Specialization { get; set; }
public string? Graduate { get; set; }
diff --git a/src/Application/DoctorsHelp.Application.Models/Intefaces/IEntity.cs b/src/Application/DoctorsHelp.Application.Models/Intefaces/IEntity.cs
new file mode 100644
index 0000000..ec68373
--- /dev/null
+++ b/src/Application/DoctorsHelp.Application.Models/Intefaces/IEntity.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Application.Models;
+
+public interface IEntity
+{
+ public Guid? Id { get; }
+}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Models/Review.cs b/src/Application/DoctorsHelp.Application.Models/Review.cs
index a3e6769..7b6e005 100644
--- a/src/Application/DoctorsHelp.Application.Models/Review.cs
+++ b/src/Application/DoctorsHelp.Application.Models/Review.cs
@@ -1,16 +1,16 @@
namespace DoctorsHelp.Application.Models;
-public class Review
+public class Review : IEntity
{
- public int Id { get; set; }
+ public Guid? Id { get; set; }
public Appointment? Appointment { get; set; }
- public int Grade { get; set; }
+ public int? Grade { get; set; }
public string? Comment { get; set; }
- public DateTime CreatedAt { get; set; }
+ public DateTime? CreatedAt { get; set; }
- public DateTime UpdatedAt { get; set; }
+ public DateTime? UpdatedAt { get; set; }
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Models/Schedule.cs b/src/Application/DoctorsHelp.Application.Models/Schedule.cs
index 2d04da3..00bd13c 100644
--- a/src/Application/DoctorsHelp.Application.Models/Schedule.cs
+++ b/src/Application/DoctorsHelp.Application.Models/Schedule.cs
@@ -1,14 +1,14 @@
namespace DoctorsHelp.Application.Models;
-public class Schedule
+public class Schedule : IEntity
{
- public int Id { get; set; }
+ public Guid? Id { get; set; }
public Employee? Employee { get; set; }
- public DateTime DateStart { get; set; }
+ public DateTime? DateStart { get; set; }
- public DateTime DateEnd { get; set; }
+ public DateTime? DateEnd { get; set; }
- public int Status { get; set; }
+ public int? Status { get; set; }
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application.Models/Specialization.cs b/src/Application/DoctorsHelp.Application.Models/Specialization.cs
index 335b580..e61d7ba 100644
--- a/src/Application/DoctorsHelp.Application.Models/Specialization.cs
+++ b/src/Application/DoctorsHelp.Application.Models/Specialization.cs
@@ -1,8 +1,8 @@
namespace DoctorsHelp.Application.Models;
-public class Specialization
+public class Specialization : IEntity
{
- public int Id { get; set; }
+ public Guid? Id { get; set; }
public string? Name { get; set; }
diff --git a/src/Application/DoctorsHelp.Application.Models/User.cs b/src/Application/DoctorsHelp.Application.Models/User.cs
index 2e5a3b2..b93a5ed 100644
--- a/src/Application/DoctorsHelp.Application.Models/User.cs
+++ b/src/Application/DoctorsHelp.Application.Models/User.cs
@@ -1,8 +1,8 @@
namespace DoctorsHelp.Application.Models;
-public class User
+public class User : IEntity
{
- public Guid Id { get; set; }
+ public Guid? Id { get; set; }
public string? Name { get; set; }
@@ -14,7 +14,7 @@ public class User
public string? HashedPassword { get; set; }
- public DateOnly Birthdate { get; set; }
+ public DateOnly? Birthdate { get; set; }
public string? Role { get; set; }
}
\ No newline at end of file
diff --git a/src/Application/DoctorsHelp.Application/Extensions/ServiceCollectionExtensions.cs b/src/Application/DoctorsHelp.Application/Extensions/ServiceCollectionExtensions.cs
index f0449dc..7cefcf8 100644
--- a/src/Application/DoctorsHelp.Application/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Application/DoctorsHelp.Application/Extensions/ServiceCollectionExtensions.cs
@@ -1,3 +1,5 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Contracts.Services;
using Microsoft.Extensions.DependencyInjection;
namespace DoctorsHelp.Application.Extensions;
@@ -6,7 +8,12 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection AddApplication(this IServiceCollection collection)
{
- // TODO: add services
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
return collection;
}
}
\ No newline at end of file
diff --git a/src/DoctorsHelp/DoctorsHelp.csproj b/src/DoctorsHelp/DoctorsHelp.csproj
index f201af4..7d12243 100644
--- a/src/DoctorsHelp/DoctorsHelp.csproj
+++ b/src/DoctorsHelp/DoctorsHelp.csproj
@@ -1,15 +1,17 @@
-
-
+
+
-
+
+
+
diff --git a/src/DoctorsHelp/Program.cs b/src/DoctorsHelp/Program.cs
index 7fe3860..9af0284 100644
--- a/src/DoctorsHelp/Program.cs
+++ b/src/DoctorsHelp/Program.cs
@@ -16,23 +16,23 @@
builder.Services.AddSingleton(sp => sp.GetRequiredService>().Value);
builder.Services.AddApplication();
-builder.Services.AddInfrastructurePersistence();
+
+builder.Services.AddInfrastructurePersistence(builder.Configuration);
builder.Services
.AddControllers()
.AddNewtonsoftJson()
.AddPresentationHttp();
-builder.Services.AddSwaggerGen().AddEndpointsApiExplorer();
-
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
builder.Host.AddPlatformSerilog(builder.Configuration);
builder.Services.AddUtcDateTimeProvider();
WebApplication app = builder.Build();
-app.UseRouting();
app.UseSwagger();
app.UseSwaggerUI();
-
+app.UseRouting();
app.MapControllers();
await app.RunAsync();
\ No newline at end of file
diff --git a/src/DoctorsHelp/Util/Profiles.cs b/src/DoctorsHelp/Util/Profiles.cs
new file mode 100644
index 0000000..79dfd46
--- /dev/null
+++ b/src/DoctorsHelp/Util/Profiles.cs
@@ -0,0 +1,8 @@
+namespace DoctorsHelp.Util;
+
+public enum Profiles
+{
+ Local,
+
+ Prod,
+}
\ No newline at end of file
diff --git a/src/DoctorsHelp/appsettings.Local.json b/src/DoctorsHelp/appsettings.Local.json
index a26180e..9d3ce72 100644
--- a/src/DoctorsHelp/appsettings.Local.json
+++ b/src/DoctorsHelp/appsettings.Local.json
@@ -2,13 +2,7 @@
"Infrastructure": {
"Persistence": {
"Postgres": {
- "Host": "localhost",
- "Port": 6432,
- "Database": "postgres",
- "Username": "postgres",
- "Password": "postgres",
- "SslMode": "Prefer",
- "Pooling": true
+ "ConnectionString": "Host=rc1b-i7lu7rt5vmg38nh0.mdb.yandexcloud.net;Port=6432;Database=oop;Username=g1phy;Password=fPr-KsP-h9W-q48;"
}
}
},
@@ -17,6 +11,18 @@
"Host": "localhost:9092"
}
},
+ "Kestrel": {
+ "Endpoints": {
+ "gRPC": {
+ "Url": "http://*:3071",
+ "Protocols": "Http2"
+ },
+ "http": {
+ "Url": "http://*:3070",
+ "Protocols": "Http1"
+ }
+ }
+ },
"Platform": {
"Environment": "Local"
},
diff --git a/src/DoctorsHelp/appsettings.json b/src/DoctorsHelp/appsettings.json
index 46b1ad6..181682c 100644
--- a/src/DoctorsHelp/appsettings.json
+++ b/src/DoctorsHelp/appsettings.json
@@ -3,20 +3,14 @@
"Infrastructure": {
"Persistence": {
"Postgres": {
- "Host": "",
- "Port": -1,
- "Database": "",
- "Username": "",
- "Password": "",
- "SslMode": "Prefer",
- "Pooling": true
+ "ConnectionString": "Host=rc1b-i7lu7rt5vmg38nh0.mdb.yandexcloud.net;Port=6432;Database=oop;Username=g1phy;Password=fPr-KsP-h9W-q48;"
}
- },
+ }
},
"Presentation": {
},
"Platform": {
- "Environment": "",
+ "Environment": ""
},
"Sentry": {
"Enabled": true,
@@ -30,8 +24,12 @@
"Kestrel": {
"Endpoints": {
"gRPC": {
- "Url": "http://*:8070",
+ "Url": "http://*:3071",
"Protocols": "Http2"
+ },
+ "http": {
+ "Url": "http://*:3070",
+ "Protocols": "Http1"
}
}
},
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Contexts/ApplicationDbContext.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Contexts/ApplicationDbContext.cs
new file mode 100644
index 0000000..1a7e9a8
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Contexts/ApplicationDbContext.cs
@@ -0,0 +1,30 @@
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Contexts;
+
+public class ApplicationDbContext : DbContext
+{
+ public ApplicationDbContext() { }
+
+ public ApplicationDbContext(DbContextOptions options) : base(options) { }
+
+ required public DbSet Users { get; set; }
+
+ required public DbSet Appointments { get; set; }
+
+ required public DbSet Employees { get; set; }
+
+ required public DbSet Reviews { get; set; }
+
+ required public DbSet Schedules { get; set; }
+
+ required public DbSet Specializations { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
+
+ // base.OnModelCreating(modelBuilder);
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/AppointmentConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/AppointmentConverter.cs
new file mode 100644
index 0000000..07970ac
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/AppointmentConverter.cs
@@ -0,0 +1,23 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class AppointmentConverter
+{
+ public static Appointment? AppointmentModelToAppointment(AppointmentModel? appointmentModel)
+ {
+ if (appointmentModel is null)
+ return null;
+
+ return new Appointment
+ {
+ Id = appointmentModel.Id,
+ Patient = UserConverter.UserModelToUser(appointmentModel.Patient),
+ Schedule = ScheduleConverter.ScheduleModelToSchedule(appointmentModel.Schedule),
+ CreatedAt = appointmentModel.CreatedAt,
+ UpdatedAt = appointmentModel.UpdatedAt,
+ Status = appointmentModel.Status,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/EmployeeConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/EmployeeConverter.cs
new file mode 100644
index 0000000..a5340c1
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/EmployeeConverter.cs
@@ -0,0 +1,22 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class EmployeeConverter
+{
+ public static Employee? EmployeeModelToEmployee(EmployeeModel? employeeModel)
+ {
+ if (employeeModel is null)
+ return null;
+
+ return new Employee
+ {
+ Id = employeeModel.Id,
+ User = UserConverter.UserModelToUser(employeeModel.User),
+ Specialization = SpecializationConverter.SpecializationModelToSpecialization(employeeModel.Specialization),
+ Graduate = employeeModel.Graduate,
+ Experience = employeeModel.Experience,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ReviewConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ReviewConverter.cs
new file mode 100644
index 0000000..d8eb167
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ReviewConverter.cs
@@ -0,0 +1,20 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class ReviewConverter
+{
+ public static Review ReviewModelToReview(ReviewModel? reviewModel)
+ {
+ return new Review
+ {
+ Id = reviewModel?.Id,
+ Appointment = AppointmentConverter.AppointmentModelToAppointment(reviewModel?.Appointment),
+ Grade = reviewModel?.Grade,
+ Comment = reviewModel?.Comment,
+ CreatedAt = reviewModel?.CreatedAt,
+ UpdatedAt = reviewModel?.UpdatedAt,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ScheduleConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ScheduleConverter.cs
new file mode 100644
index 0000000..791f904
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/ScheduleConverter.cs
@@ -0,0 +1,19 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class ScheduleConverter
+{
+ public static Schedule? ScheduleModelToSchedule(ScheduleModel? scheduleModel)
+ {
+ return new Schedule
+ {
+ Id = scheduleModel?.Id,
+ Employee = EmployeeConverter.EmployeeModelToEmployee(scheduleModel?.Employee),
+ DateStart = scheduleModel?.DateStart,
+ DateEnd = scheduleModel?.DateEnd,
+ Status = scheduleModel?.Status,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/SpecializationConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/SpecializationConverter.cs
new file mode 100644
index 0000000..13602d2
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/SpecializationConverter.cs
@@ -0,0 +1,20 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class SpecializationConverter
+{
+ public static Specialization? SpecializationModelToSpecialization(SpecializationModel? specializationModel)
+ {
+ if (specializationModel is null)
+ return null;
+
+ return new Specialization
+ {
+ Id = specializationModel.Id,
+ Name = specializationModel.Name,
+ Description = specializationModel.Description,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/UserConverter.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/UserConverter.cs
new file mode 100644
index 0000000..9b13393
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Converters/UserConverter.cs
@@ -0,0 +1,25 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Converters;
+
+public class UserConverter
+{
+ public static User? UserModelToUser(UserModel? userModel)
+ {
+ if (userModel is null)
+ return null;
+
+ return new User
+ {
+ Id = userModel.Id,
+ Name = userModel.Name,
+ Surname = userModel.Surname,
+ Phone = userModel.Phone,
+ Email = userModel.Email,
+ HashedPassword = userModel.HashedPassword,
+ Birthdate = userModel.Birthdate,
+ Role = userModel.Role,
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/DoctorsHelp.Infrastructure.Persistence.csproj b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/DoctorsHelp.Infrastructure.Persistence.csproj
index 2aec2b3..e3a3b03 100644
--- a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/DoctorsHelp.Infrastructure.Persistence.csproj
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/DoctorsHelp.Infrastructure.Persistence.csproj
@@ -9,4 +9,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Extensions/ServiceCollectionExtensions.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Extensions/ServiceCollectionExtensions.cs
index dbad899..af5a45b 100644
--- a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Extensions/ServiceCollectionExtensions.cs
@@ -1,25 +1,25 @@
-using DoctorsHelp.Application.Abstractions.Persistence;
-using DoctorsHelp.Infrastructure.Persistence.Migrations;
-using DoctorsHelp.Infrastructure.Persistence.Plugins;
-using Itmo.Dev.Platform.Postgres.Extensions;
-using Itmo.Dev.Platform.Postgres.Plugins;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using DoctorsHelp.Infrastructure.Persistence.Repositories;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace DoctorsHelp.Infrastructure.Persistence.Extensions;
public static class ServiceCollectionExtensions
{
- public static IServiceCollection AddInfrastructurePersistence(this IServiceCollection collection)
+ public static IServiceCollection AddInfrastructurePersistence(this IServiceCollection collection, IConfiguration configuration)
{
- collection.AddPlatformPostgres(builder => builder.BindConfiguration("Infrastructure:Persistence:Postgres"));
- collection.AddSingleton();
-
- collection.AddPlatformMigrations(typeof(IAssemblyMarker).Assembly);
- collection.AddHostedService();
-
- // TODO: add repositories
- collection.AddScoped();
+ collection.AddDbContext(options =>
+ options.UseNpgsql(configuration.GetSection("Infrastructure:Persistence:Postgres:ConnectionString").Value));
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
+ collection.AddScoped();
return collection;
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IAppointmentRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IAppointmentRepository.cs
new file mode 100644
index 0000000..8982c42
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IAppointmentRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface IAppointmentRepository
+{
+ void AddAppointment(Appointment appointment);
+
+ AppointmentModel? GetAppointment(Guid id);
+
+ void UpdateAppointment(Appointment appointment);
+
+ bool Delete(Appointment appointment);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IEmployeeRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IEmployeeRepository.cs
new file mode 100644
index 0000000..59ff70f
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IEmployeeRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface IEmployeeRepository
+{
+ void AddEmployee(Employee employee);
+
+ EmployeeModel? GetEmployee(Guid id);
+
+ void UpdateEmployee(Employee employee);
+
+ bool Delete(Employee employee);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IReviewRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IReviewRepository.cs
new file mode 100644
index 0000000..1310db0
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IReviewRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface IReviewRepository
+{
+ void AddReview(Review review);
+
+ ReviewModel? GetReview(Guid id);
+
+ void UpdateReview(Review review);
+
+ bool Delete(Review review);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IScheduleRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IScheduleRepository.cs
new file mode 100644
index 0000000..f8f51a5
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IScheduleRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface IScheduleRepository
+{
+ void AddSchedule(Schedule schedule);
+
+ ScheduleModel? GetSchedule(Guid id);
+
+ void UpdateSchedule(Schedule schedule);
+
+ bool Delete(Schedule schedule);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/ISpecializationRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/ISpecializationRepository.cs
new file mode 100644
index 0000000..e8ee539
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/ISpecializationRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface ISpecializationRepository
+{
+ void AddSpecialization(Specialization specialization);
+
+ SpecializationModel? GetSpecialization(Guid id);
+
+ void UpdateSpecialization(Specialization specialization);
+
+ bool Delete(Specialization specialization);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IUserRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IUserRepository.cs
new file mode 100644
index 0000000..106c1c4
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Interfaces/IUserRepository.cs
@@ -0,0 +1,15 @@
+using DoctorsHelp.Application.Models;
+using Infrastructure.Persistence.Models;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Interfaces;
+
+public interface IUserRepository
+{
+ void Add(User user);
+
+ UserModel? GetUser(Guid id);
+
+ void UpdateUser(User user);
+
+ bool Delete(User user);
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.Designer.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.Designer.cs
new file mode 100644
index 0000000..d6d67d1
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.Designer.cs
@@ -0,0 +1,247 @@
+//
+using System;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace DoctorsHelp.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20240411191337_Initial")]
+ partial class Initial
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.AppointmentModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PatientId")
+ .HasColumnType("uuid");
+
+ b.Property("ScheduleId")
+ .HasColumnType("uuid");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PatientId");
+
+ b.HasIndex("ScheduleId");
+
+ b.ToTable("Appointments");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.EmployeeModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Experience")
+ .HasColumnType("text");
+
+ b.Property("Graduate")
+ .HasColumnType("text");
+
+ b.Property("SpecializationId")
+ .HasColumnType("uuid");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpecializationId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Employees");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ReviewModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AppointmentId")
+ .HasColumnType("uuid");
+
+ b.Property("Comment")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Grade")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppointmentId");
+
+ b.ToTable("Reviews");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ScheduleModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("DateEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateStart")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("EmployeeId")
+ .HasColumnType("uuid");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EmployeeId");
+
+ b.ToTable("Schedules");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.SpecializationModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Specializations");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.UserModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Birthdate")
+ .HasColumnType("date");
+
+ b.Property("Email")
+ .HasColumnType("text");
+
+ b.Property("HashedPassword")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Phone")
+ .HasColumnType("text");
+
+ b.Property("Role")
+ .HasColumnType("text");
+
+ b.Property("Surname")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.AppointmentModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.UserModel", "Patient")
+ .WithMany()
+ .HasForeignKey("PatientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Infrastructure.Persistence.Models.ScheduleModel", "Schedule")
+ .WithMany()
+ .HasForeignKey("ScheduleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Patient");
+
+ b.Navigation("Schedule");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.EmployeeModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.SpecializationModel", "Specialization")
+ .WithMany()
+ .HasForeignKey("SpecializationId");
+
+ b.HasOne("Infrastructure.Persistence.Models.UserModel", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Specialization");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ReviewModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.AppointmentModel", "Appointment")
+ .WithMany()
+ .HasForeignKey("AppointmentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Appointment");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ScheduleModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.EmployeeModel", "Employee")
+ .WithMany()
+ .HasForeignKey("EmployeeId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Employee");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.cs
new file mode 100644
index 0000000..82fbad7
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/20240411191337_Initial.cs
@@ -0,0 +1,193 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace DoctorsHelp.Infrastructure.Persistence.Migrations;
+
+///
+public partial class Initial : Migration
+{
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Specializations",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: true),
+ Description = table.Column(type: "text", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Specializations", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Users",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: true),
+ Surname = table.Column(type: "text", nullable: true),
+ Phone = table.Column(type: "text", nullable: true),
+ Email = table.Column(type: "text", nullable: true),
+ HashedPassword = table.Column(type: "text", nullable: true),
+ Birthdate = table.Column(type: "date", nullable: true),
+ Role = table.Column(type: "text", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Users", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Employees",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "uuid", nullable: false),
+ SpecializationId = table.Column(type: "uuid", nullable: true),
+ Graduate = table.Column(type: "text", nullable: true),
+ Experience = table.Column(type: "text", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Employees", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Employees_Specializations_SpecializationId",
+ column: x => x.SpecializationId,
+ principalTable: "Specializations",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_Employees_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Schedules",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ EmployeeId = table.Column(type: "uuid", nullable: false),
+ DateStart = table.Column(type: "timestamp with time zone", nullable: true),
+ DateEnd = table.Column(type: "timestamp with time zone", nullable: true),
+ Status = table.Column(type: "integer", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Schedules", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Schedules_Employees_EmployeeId",
+ column: x => x.EmployeeId,
+ principalTable: "Employees",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Appointments",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ PatientId = table.Column(type: "uuid", nullable: false),
+ ScheduleId = table.Column(type: "uuid", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ Status = table.Column(type: "integer", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Appointments", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Appointments_Schedules_ScheduleId",
+ column: x => x.ScheduleId,
+ principalTable: "Schedules",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Appointments_Users_PatientId",
+ column: x => x.PatientId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Reviews",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ AppointmentId = table.Column(type: "uuid", nullable: false),
+ Grade = table.Column(type: "integer", nullable: true),
+ Comment = table.Column(type: "text", nullable: true),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Reviews", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Reviews_Appointments_AppointmentId",
+ column: x => x.AppointmentId,
+ principalTable: "Appointments",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Appointments_PatientId",
+ table: "Appointments",
+ column: "PatientId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Appointments_ScheduleId",
+ table: "Appointments",
+ column: "ScheduleId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Employees_SpecializationId",
+ table: "Employees",
+ column: "SpecializationId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Employees_UserId",
+ table: "Employees",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Reviews_AppointmentId",
+ table: "Reviews",
+ column: "AppointmentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Schedules_EmployeeId",
+ table: "Schedules",
+ column: "EmployeeId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Reviews");
+
+ migrationBuilder.DropTable(
+ name: "Appointments");
+
+ migrationBuilder.DropTable(
+ name: "Schedules");
+
+ migrationBuilder.DropTable(
+ name: "Employees");
+
+ migrationBuilder.DropTable(
+ name: "Specializations");
+
+ migrationBuilder.DropTable(
+ name: "Users");
+ }
+}
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs
new file mode 100644
index 0000000..4427002
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -0,0 +1,244 @@
+//
+using System;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace DoctorsHelp.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ partial class ApplicationDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.AppointmentModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PatientId")
+ .HasColumnType("uuid");
+
+ b.Property("ScheduleId")
+ .HasColumnType("uuid");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PatientId");
+
+ b.HasIndex("ScheduleId");
+
+ b.ToTable("Appointments");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.EmployeeModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Experience")
+ .HasColumnType("text");
+
+ b.Property("Graduate")
+ .HasColumnType("text");
+
+ b.Property("SpecializationId")
+ .HasColumnType("uuid");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpecializationId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Employees");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ReviewModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AppointmentId")
+ .HasColumnType("uuid");
+
+ b.Property("Comment")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Grade")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppointmentId");
+
+ b.ToTable("Reviews");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ScheduleModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("DateEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateStart")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("EmployeeId")
+ .HasColumnType("uuid");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EmployeeId");
+
+ b.ToTable("Schedules");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.SpecializationModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Specializations");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.UserModel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Birthdate")
+ .HasColumnType("date");
+
+ b.Property("Email")
+ .HasColumnType("text");
+
+ b.Property("HashedPassword")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Phone")
+ .HasColumnType("text");
+
+ b.Property("Role")
+ .HasColumnType("text");
+
+ b.Property("Surname")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.AppointmentModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.UserModel", "Patient")
+ .WithMany()
+ .HasForeignKey("PatientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Infrastructure.Persistence.Models.ScheduleModel", "Schedule")
+ .WithMany()
+ .HasForeignKey("ScheduleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Patient");
+
+ b.Navigation("Schedule");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.EmployeeModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.SpecializationModel", "Specialization")
+ .WithMany()
+ .HasForeignKey("SpecializationId");
+
+ b.HasOne("Infrastructure.Persistence.Models.UserModel", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Specialization");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ReviewModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.AppointmentModel", "Appointment")
+ .WithMany()
+ .HasForeignKey("AppointmentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Appointment");
+ });
+
+ modelBuilder.Entity("Infrastructure.Persistence.Models.ScheduleModel", b =>
+ {
+ b.HasOne("Infrastructure.Persistence.Models.EmployeeModel", "Employee")
+ .WithMany()
+ .HasForeignKey("EmployeeId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Employee");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/AppointmentModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/AppointmentModel.cs
new file mode 100644
index 0000000..faf9d11
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/AppointmentModel.cs
@@ -0,0 +1,22 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class AppointmentModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public Guid PatientId { get; set; }
+
+ public Guid ScheduleId { get; set; }
+
+ public DateTime? CreatedAt { get; set; }
+
+ public DateTime? UpdatedAt { get; set; }
+
+ public int? Status { get; set; }
+
+ public UserModel? Patient { get; set; }
+
+ public ScheduleModel? Schedule { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/EmployeeModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/EmployeeModel.cs
new file mode 100644
index 0000000..593b8a2
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/EmployeeModel.cs
@@ -0,0 +1,20 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class EmployeeModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public Guid UserId { get; set; }
+
+ public Guid SpecializationId { get; set; }
+
+ public string? Graduate { get; set; }
+
+ public string? Experience { get; set; }
+
+ public UserModel? User { get; set; }
+
+ public SpecializationModel? Specialization { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ReviewModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ReviewModel.cs
new file mode 100644
index 0000000..aee4dcb
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ReviewModel.cs
@@ -0,0 +1,20 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class ReviewModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public Guid AppointmentId { get; set; }
+
+ public int? Grade { get; set; }
+
+ public string? Comment { get; set; }
+
+ public DateTime? CreatedAt { get; set; }
+
+ public DateTime? UpdatedAt { get; set; }
+
+ public AppointmentModel? Appointment { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ScheduleModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ScheduleModel.cs
new file mode 100644
index 0000000..3408b18
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/ScheduleModel.cs
@@ -0,0 +1,18 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class ScheduleModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public Guid EmployeeId { get; set; }
+
+ public DateTime? DateStart { get; set; }
+
+ public DateTime? DateEnd { get; set; }
+
+ public int? Status { get; set; }
+
+ public EmployeeModel? Employee { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/SpecializationModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/SpecializationModel.cs
new file mode 100644
index 0000000..c488c97
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/SpecializationModel.cs
@@ -0,0 +1,12 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class SpecializationModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public string? Name { get; set; }
+
+ public string? Description { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/UserModel.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/UserModel.cs
new file mode 100644
index 0000000..785feda
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Models/UserModel.cs
@@ -0,0 +1,22 @@
+using DoctorsHelp.Application.Models;
+
+namespace Infrastructure.Persistence.Models;
+
+public class UserModel : IEntity
+{
+ public Guid? Id { get; set; }
+
+ public string? Name { get; set; }
+
+ public string? Surname { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? Email { get; set; }
+
+ public string? HashedPassword { get; set; }
+
+ public DateOnly? Birthdate { get; set; }
+
+ public string? Role { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/AppointmentRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/AppointmentRepository.cs
new file mode 100644
index 0000000..19ce9e3
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/AppointmentRepository.cs
@@ -0,0 +1,64 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class AppointmentRepository : RepositoryBase, IAppointmentRepository
+{
+ public AppointmentRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public AppointmentModel? GetAppointment(Guid id)
+ {
+ return GetEntry(new Appointment { Id = id })?.Entity;
+ }
+
+ public void UpdateAppointment(Appointment appointment)
+ {
+ Update(appointment);
+ }
+
+ public bool Delete(Appointment appointment)
+ {
+ Remove(appointment);
+ return true;
+ }
+
+ public void AddAppointment(Appointment appointment)
+ {
+ Add(appointment);
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Appointments;
+
+ protected override AppointmentModel MapFrom(Appointment entity)
+ {
+ return new AppointmentModel
+ {
+ Id = entity.Id,
+ PatientId = entity.Patient?.Id ?? Guid.Empty,
+ ScheduleId = entity.Schedule?.Id ?? Guid.Empty,
+ CreatedAt = entity.CreatedAt,
+ UpdatedAt = entity.UpdatedAt,
+ Status = entity.Status,
+ };
+ }
+
+ protected override bool Equal(Appointment entity, AppointmentModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(AppointmentModel model, Appointment entity)
+ {
+ model.PatientId = entity.Patient?.Id ?? Guid.Empty;
+ model.ScheduleId = entity.Schedule?.Id ?? Guid.Empty;
+ model.CreatedAt = entity.CreatedAt;
+ model.UpdatedAt = entity.UpdatedAt;
+ model.Status = entity.Status;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/EmployeeRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/EmployeeRepository.cs
new file mode 100644
index 0000000..8825f14
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/EmployeeRepository.cs
@@ -0,0 +1,62 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class EmployeeRepository : RepositoryBase, IEmployeeRepository
+{
+ public EmployeeRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public EmployeeModel? GetEmployee(Guid id)
+ {
+ return GetEntry(new Employee { Id = id })?.Entity;
+ }
+
+ public void UpdateEmployee(Employee employee)
+ {
+ Update(employee);
+ }
+
+ public bool Delete(Employee employee)
+ {
+ Remove(employee);
+ return true;
+ }
+
+ public void AddEmployee(Employee employee)
+ {
+ Add(employee);
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Employees;
+
+ protected override EmployeeModel MapFrom(Employee entity)
+ {
+ return new EmployeeModel
+ {
+ Id = entity.Id,
+ UserId = entity.User?.Id ?? Guid.Empty,
+ SpecializationId = entity.Specialization?.Id ?? Guid.Empty,
+ Graduate = entity.Graduate,
+ Experience = entity.Experience,
+ };
+ }
+
+ protected override bool Equal(Employee entity, EmployeeModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(EmployeeModel model, Employee entity)
+ {
+ model.UserId = entity.User?.Id ?? Guid.Empty;
+ model.SpecializationId = entity.Specialization?.Id ?? Guid.Empty;
+ model.Graduate = entity.Graduate;
+ model.Experience = entity.Experience;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/RepositoryBase.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/RepositoryBase.cs
new file mode 100644
index 0000000..331b9d2
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/RepositoryBase.cs
@@ -0,0 +1,72 @@
+using DoctorsHelp.Application.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public abstract class RepositoryBase
+ where TEntity : IEntity
+ where TModel : class, IEntity
+{
+ #pragma warning disable IDE0032
+ private readonly DbContext _context;
+
+ protected DbContext Context => _context;
+
+ protected RepositoryBase(DbContext context)
+ {
+ this._context = context;
+ }
+
+ protected abstract DbSet DbSet { get; }
+
+ public void Add(TEntity entity)
+ {
+ TModel model = MapFrom(entity);
+ DbSet.Add(model);
+ _context.SaveChanges();
+ }
+
+ public void AddRange(IEnumerable entities)
+ {
+ IEnumerable models = entities.Select(MapFrom);
+ DbSet.AddRange(models);
+ }
+
+ public void Update(TEntity entity)
+ {
+ EntityEntry? entry = GetEntry(entity);
+
+ if (entry is null)
+ return;
+
+ UpdateModel(entry.Entity, entity);
+ entry.State = EntityState.Modified;
+ _context.SaveChanges();
+ }
+
+ public void Remove(TEntity entity)
+ {
+ EntityEntry? entry = GetEntry(entity);
+
+ if (entry is null)
+ return;
+
+ entry.State = entry.State is EntityState.Added ? EntityState.Detached : EntityState.Deleted;
+ }
+
+ protected abstract TModel MapFrom(TEntity entity);
+
+ protected abstract bool Equal(TEntity entity, TModel model);
+
+ protected abstract void UpdateModel(TModel model, TEntity entity);
+
+ protected EntityEntry? GetEntry(TEntity entity)
+ {
+ TModel? existing = DbSet.FirstOrDefault(model => model.Id == entity.Id);
+
+ return existing is not null
+ ? _context.Entry(existing)
+ : null;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ReviewRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ReviewRepository.cs
new file mode 100644
index 0000000..bd27fa1
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ReviewRepository.cs
@@ -0,0 +1,64 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class ReviewRepository : RepositoryBase, IReviewRepository
+{
+ public ReviewRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public ReviewModel? GetReview(Guid id)
+ {
+ return GetEntry(new Review { Id = id })?.Entity;
+ }
+
+ public void UpdateReview(Review review)
+ {
+ Update(review);
+ }
+
+ public bool Delete(Review review)
+ {
+ Remove(review);
+ return true;
+ }
+
+ public void AddReview(Review review)
+ {
+ Add(review);
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Reviews;
+
+ protected override ReviewModel MapFrom(Review entity)
+ {
+ return new ReviewModel
+ {
+ Id = entity.Id,
+ AppointmentId = entity.Appointment?.Id ?? Guid.Empty,
+ Grade = entity.Grade,
+ Comment = entity.Comment,
+ CreatedAt = entity.CreatedAt,
+ UpdatedAt = entity.UpdatedAt,
+ };
+ }
+
+ protected override bool Equal(Review entity, ReviewModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(ReviewModel model, Review entity)
+ {
+ model.AppointmentId = entity.Appointment?.Id ?? Guid.Empty;
+ model.Grade = entity.Grade;
+ model.Comment = entity.Comment;
+ model.CreatedAt = entity.CreatedAt;
+ model.UpdatedAt = entity.UpdatedAt;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ScheduleRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ScheduleRepository.cs
new file mode 100644
index 0000000..38d6a74
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/ScheduleRepository.cs
@@ -0,0 +1,62 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class ScheduleRepository : RepositoryBase, IScheduleRepository
+{
+ public ScheduleRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public ScheduleModel? GetSchedule(Guid id)
+ {
+ return GetEntry(new Schedule { Id = id })?.Entity;
+ }
+
+ public void UpdateSchedule(Schedule schedule)
+ {
+ Update(schedule);
+ }
+
+ public bool Delete(Schedule schedule)
+ {
+ Remove(schedule);
+ return true;
+ }
+
+ public void AddSchedule(Schedule schedule)
+ {
+ Add(schedule);
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Schedules;
+
+ protected override ScheduleModel MapFrom(Schedule entity)
+ {
+ return new ScheduleModel
+ {
+ Id = entity.Id,
+ EmployeeId = entity.Employee?.Id ?? Guid.Empty,
+ DateStart = entity.DateStart,
+ DateEnd = entity.DateEnd,
+ Status = entity.Status,
+ };
+ }
+
+ protected override bool Equal(Schedule entity, ScheduleModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(ScheduleModel model, Schedule entity)
+ {
+ model.EmployeeId = entity.Employee?.Id ?? Guid.Empty;
+ model.DateStart = entity.DateStart;
+ model.DateEnd = entity.DateEnd;
+ model.Status = entity.Status;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/SpecializationRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/SpecializationRepository.cs
new file mode 100644
index 0000000..3388392
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/SpecializationRepository.cs
@@ -0,0 +1,59 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class SpecializationRepository : RepositoryBase, ISpecializationRepository
+{
+ public SpecializationRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public void UpdateSpecialization(Specialization specialization)
+ {
+ Update(specialization);
+ }
+
+ public SpecializationModel? GetSpecialization(Guid id)
+ {
+ SpecializationModel? entry = GetEntry(new Specialization { Id = id })?.Entity;
+ return entry;
+ }
+
+ public bool Delete(Specialization specialization)
+ {
+ Remove(specialization);
+ return true;
+ }
+
+ public void AddSpecialization(Specialization specialization)
+ {
+ Add(specialization);
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Specializations;
+
+ protected override SpecializationModel MapFrom(Specialization entity)
+ {
+ return new SpecializationModel
+ {
+ Id = entity.Id,
+ Name = entity.Name,
+ Description = entity.Description,
+ };
+ }
+
+ protected override bool Equal(Specialization entity, SpecializationModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(SpecializationModel model, Specialization entity)
+ {
+ model.Name = entity.Name;
+ model.Description = entity.Description;
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/UserRepository.cs b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/UserRepository.cs
new file mode 100644
index 0000000..0bfc42b
--- /dev/null
+++ b/src/Infrastructure/DoctorsHelp.Infrastructure.Persistence/Repositories/UserRepository.cs
@@ -0,0 +1,63 @@
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Infrastructure.Persistence.Contexts;
+using DoctorsHelp.Infrastructure.Persistence.Interfaces;
+using Infrastructure.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace DoctorsHelp.Infrastructure.Persistence.Repositories;
+
+public class UserRepository : RepositoryBase, IUserRepository
+{
+ public UserRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+
+ public UserModel? GetUser(Guid id)
+ {
+ return GetEntry(new User { Id = id })?.Entity;
+ }
+
+ public void UpdateUser(User user)
+ {
+ Update(user);
+ }
+
+ public bool Delete(User user)
+ {
+ Remove(user);
+ return true;
+ }
+
+ protected override DbSet DbSet => ((ApplicationDbContext)Context).Users;
+
+ protected override UserModel MapFrom(User entity)
+ {
+ return new UserModel
+ {
+ Id = entity.Id,
+ Name = entity.Name,
+ Surname = entity.Surname,
+ Phone = entity.Phone,
+ Email = entity.Email,
+ HashedPassword = entity.HashedPassword,
+ Birthdate = entity.Birthdate,
+ Role = entity.Role,
+ };
+ }
+
+ protected override bool Equal(User entity, UserModel model)
+ {
+ return entity.Id == model.Id;
+ }
+
+ protected override void UpdateModel(UserModel model, User entity)
+ {
+ model.Name = entity.Name;
+ model.Surname = entity.Surname;
+ model.Phone = entity.Phone;
+ model.Email = entity.Email;
+ model.HashedPassword = entity.HashedPassword;
+ model.Birthdate = entity.Birthdate;
+ model.Role = entity.Role;
+ }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/AppointmentController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/AppointmentController.cs
new file mode 100644
index 0000000..12aa80c
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/AppointmentController.cs
@@ -0,0 +1,72 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using DoctorsHelp.Presentation.Http.Responses;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+[ApiController]
+[Route("appointment")]
+public class AppointmentController : ControllerBase
+{
+ private readonly IAppointmentService _appointmentService;
+
+ public AppointmentController(IAppointmentService appointmentService)
+ {
+ _appointmentService = appointmentService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var appointment = _appointmentService.GetAppointment(id);
+ if (appointment == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(appointment);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] AppointmentPost data)
+ {
+ try
+ {
+ var createdAppointment = _appointmentService.Create(data.PatientId, data.ScheduleId);
+ return CreatedAtAction(nameof(Get), new { id = createdAppointment.Id }, createdAppointment);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while creating the appointment." + ex);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedAppointment = _appointmentService.Update(id, data);
+ return Ok(updatedAppointment);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _appointmentService.Delete(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/EmployeeController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/EmployeeController.cs
new file mode 100644
index 0000000..abe3959
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/EmployeeController.cs
@@ -0,0 +1,77 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+
+[ApiController]
+[Route("employee")]
+public class EmployeeController : ControllerBase
+{
+ private readonly IEmployeeService _employeeService;
+
+ public EmployeeController(IEmployeeService employeeService)
+ {
+ _employeeService = employeeService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var employee = _employeeService.GetEmployee(id);
+ if (employee == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(employee);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] EmployeePost data)
+ {
+ if (string.IsNullOrWhiteSpace(data.Graduate) || string.IsNullOrWhiteSpace(data.Experience))
+ {
+ return BadRequest("User, Specialization, Graduate, and Experience are required.");
+ }
+
+ try
+ {
+ var createdEmployee = _employeeService.Create(data.UserId, data.SpecializationId, data.Graduate, data.Experience);
+ return CreatedAtAction(nameof(Get), new { id = createdEmployee.Id }, createdEmployee);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while creating the employee. " + ex.Message);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedEmployee = _employeeService.Update(id, data);
+ return Ok(updatedEmployee);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _employeeService.Delete(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ReviewController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ReviewController.cs
new file mode 100644
index 0000000..d981ac3
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ReviewController.cs
@@ -0,0 +1,77 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+
+[ApiController]
+[Route("review")]
+public class ReviewController : ControllerBase
+{
+ private readonly IReviewService _reviewService;
+
+ public ReviewController(IReviewService reviewService)
+ {
+ _reviewService = reviewService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var review = _reviewService.GetReview(id);
+ if (review == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(review);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] ReviewPost data)
+ {
+ if (data.Grade < 1 || string.IsNullOrWhiteSpace(data.Comment))
+ {
+ return BadRequest("Appointment, Grade, and Comment are required.");
+ }
+
+ try
+ {
+ var createdReview = _reviewService.Create(data.AppointmentId, data.Grade, data.Comment);
+ return CreatedAtAction(nameof(Get), new { id = createdReview.Id }, createdReview);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while creating the review. " + ex.Message);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedReview = _reviewService.Update(id, data);
+ return Ok(updatedReview);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _reviewService.Delete(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ScheduleController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ScheduleController.cs
new file mode 100644
index 0000000..4c06b88
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/ScheduleController.cs
@@ -0,0 +1,82 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+
+[ApiController]
+[Route("schedule")]
+public class ScheduleController : ControllerBase
+{
+ private readonly IScheduleService _scheduleService;
+
+ public ScheduleController(IScheduleService scheduleService)
+ {
+ _scheduleService = scheduleService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var schedule = _scheduleService.GetSchedule(id);
+ if (schedule == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(schedule);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] SchedulePost data)
+ {
+ if (data.DateStart == default || data.DateEnd == default)
+ {
+ return BadRequest("Employee, DateStart, and DateEnd are required.");
+ }
+
+ if (data.DateStart >= data.DateEnd)
+ {
+ return BadRequest("DateStart must be before DateEnd.");
+ }
+
+ try
+ {
+ var createdSchedule = _scheduleService.Create(data.EmployeeId, data.DateStart, data.DateEnd);
+ return CreatedAtAction(nameof(Get), new { id = createdSchedule.Id }, createdSchedule);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while creating the schedule. " + ex.Message);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedSchedule = _scheduleService.Update(id, data);
+ return Ok(updatedSchedule);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _scheduleService.Delete(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/SpecializationController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/SpecializationController.cs
new file mode 100644
index 0000000..66bef0e
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/SpecializationController.cs
@@ -0,0 +1,75 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+
+[ApiController]
+[Route("specialization")]
+public class SpecializationController : ControllerBase
+{
+ private readonly ISpecializationService _specializationService;
+
+ public SpecializationController(ISpecializationService specializationService)
+ {
+ _specializationService = specializationService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var specialization = _specializationService.GetSpecialization(id);
+ if (specialization == null)
+ return BadRequest("No specialization found with the given id.");
+
+ return Ok(specialization);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] SpecializationPost data)
+ {
+ if (data.Name == null || data.Description == null)
+ {
+ return BadRequest("Name and Description are required.");
+ }
+
+ try
+ {
+ var createdSpecialization = _specializationService.Create(data.Name, data.Description);
+ return CreatedAtAction(nameof(Get), new { id = createdSpecialization.Id }, createdSpecialization);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while creating the specialization." + ex);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedSpecialization = _specializationService.Update(id, data);
+ return Ok(updatedSpecialization);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _specializationService.Delete(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/UserController.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/UserController.cs
new file mode 100644
index 0000000..97c6482
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Controllers/UserController.cs
@@ -0,0 +1,79 @@
+using DoctorsHelp.Application.Contracts;
+using DoctorsHelp.Application.Models;
+using DoctorsHelp.Presentation.Http.Requests;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DoctorsHelp.Presentation.Http.Controllers;
+
+[ApiController]
+[Route("user")]
+public class UserController : ControllerBase
+{
+ private readonly IUserService _userService;
+
+ public UserController(IUserService userService)
+ {
+ _userService = userService;
+ }
+
+ [HttpGet("{id}")]
+ public ActionResult Get(Guid id)
+ {
+ var user = _userService.GetUser(id);
+ if (user == null)
+ return NotFound();
+
+ return Ok(user);
+ }
+
+ [HttpPost]
+ public ActionResult Post([FromBody] UserPost data)
+ {
+ if (string.IsNullOrWhiteSpace(data.Name) ||
+ string.IsNullOrWhiteSpace(data.Surname) ||
+ string.IsNullOrWhiteSpace(data.Phone) ||
+ string.IsNullOrWhiteSpace(data.Email) ||
+ string.IsNullOrWhiteSpace(data.Password))
+ {
+ return BadRequest("All fields are required.");
+ }
+
+ try
+ {
+ var user = _userService.Register(data.Name, data.Surname, data.Phone, data.Email, data.Password, data.Birthdate);
+ return CreatedAtAction(nameof(Get), new { id = user.Id }, user);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, "An error occurred while registering the user. " + ex.Message);
+ }
+ }
+
+ [HttpPut("{id}")]
+ public ActionResult Update(Guid id, [FromBody] Dictionary data)
+ {
+ try
+ {
+ var updatedUser = _userService.UpdateUser(id, data);
+ return Ok(updatedUser);
+ }
+ catch (KeyNotFoundException)
+ {
+ return NotFound();
+ }
+ }
+
+ [HttpDelete("{id}")]
+ public IActionResult Delete(Guid id)
+ {
+ var result = _userService.DeleteUser(id);
+ if (result)
+ {
+ return NoContent();
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/DoctorsHelp.Presentation.Http.csproj b/src/Presentation/DoctorsHelp.Presentation.Http/DoctorsHelp.Presentation.Http.csproj
index 21d1366..b0f89eb 100644
--- a/src/Presentation/DoctorsHelp.Presentation.Http/DoctorsHelp.Presentation.Http.csproj
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/DoctorsHelp.Presentation.Http.csproj
@@ -5,7 +5,7 @@
-
+
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/AppointmentPost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/AppointmentPost.cs
new file mode 100644
index 0000000..62e5d57
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/AppointmentPost.cs
@@ -0,0 +1,8 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class AppointmentPost
+{
+ public Guid PatientId { get; set; }
+
+ public Guid ScheduleId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/EmployeePost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/EmployeePost.cs
new file mode 100644
index 0000000..f1d305d
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/EmployeePost.cs
@@ -0,0 +1,12 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class EmployeePost
+{
+ public Guid UserId { get; set; }
+
+ public Guid SpecializationId { get; set; }
+
+ public string? Graduate { get; set; }
+
+ public string? Experience { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/ReviewPost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/ReviewPost.cs
new file mode 100644
index 0000000..6dee4f2
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/ReviewPost.cs
@@ -0,0 +1,10 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class ReviewPost
+{
+ public Guid AppointmentId { get; set; }
+
+ public int Grade { get; set; }
+
+ public string? Comment { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SchedulePost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SchedulePost.cs
new file mode 100644
index 0000000..cd69cb5
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SchedulePost.cs
@@ -0,0 +1,10 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class SchedulePost
+{
+ public Guid EmployeeId { get; set; }
+
+ public DateTime? DateStart { get; set; }
+
+ public DateTime? DateEnd { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SpecializationPost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SpecializationPost.cs
new file mode 100644
index 0000000..92f5848
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/SpecializationPost.cs
@@ -0,0 +1,8 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class SpecializationPost
+{
+ public string? Name { get; set; }
+
+ public string? Description { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Requests/UserPost.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/UserPost.cs
new file mode 100644
index 0000000..8eeb26b
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Requests/UserPost.cs
@@ -0,0 +1,16 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class UserPost
+{
+ public string? Name { get; set; }
+
+ public string? Surname { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? Email { get; set; }
+
+ public string? Password { get; set; }
+
+ public DateOnly Birthdate { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/AppointmentPostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/AppointmentPostResponse.cs
new file mode 100644
index 0000000..1e64a72
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/AppointmentPostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Responses;
+
+public class AppointmentPostResponse
+{
+ public Guid AppointmentId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/EmployeePostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/EmployeePostResponse.cs
new file mode 100644
index 0000000..1b22282
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/EmployeePostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class EmployeePostResponse
+{
+ public Guid EmployeeId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/ReviewPostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/ReviewPostResponse.cs
new file mode 100644
index 0000000..a40f161
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/ReviewPostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class ReviewPostResponse
+{
+ public Guid ReviewId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SchedulePostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SchedulePostResponse.cs
new file mode 100644
index 0000000..6f7fd50
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SchedulePostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class SchedulePostResponse
+{
+ public Guid ReviewId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SpecializationPostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SpecializationPostResponse.cs
new file mode 100644
index 0000000..ad70f09
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/SpecializationPostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class SpecializationPostResponse
+{
+ public Guid SpecializationId { get; set; }
+}
\ No newline at end of file
diff --git a/src/Presentation/DoctorsHelp.Presentation.Http/Responses/UserPostResponse.cs b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/UserPostResponse.cs
new file mode 100644
index 0000000..63f8e60
--- /dev/null
+++ b/src/Presentation/DoctorsHelp.Presentation.Http/Responses/UserPostResponse.cs
@@ -0,0 +1,6 @@
+namespace DoctorsHelp.Presentation.Http.Requests;
+
+public class UserPostResponse
+{
+ public Guid UserId { get; set; }
+}
\ No newline at end of file