diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml
index fc0194f..059e5da 100644
--- a/.github/workflows/api.yml
+++ b/.github/workflows/api.yml
@@ -10,7 +10,7 @@ on:
paths: ["apps/api/**"]
env:
- DOTNET_VERSION: "8.0.x"
+ DOTNET_VERSION: "9.0.x"
defaults:
run:
@@ -31,16 +31,16 @@ jobs:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: 📦 Install dependencies
- run: dotnet restore "Kijk.Api/Kijk.Api.csproj"
+ run: dotnet restore "src/Api/Api.csproj"
- name: 🧱 Build
- run: dotnet build "Kijk.Api/Kijk.Api.csproj" -c Release --no-restore
+ run: dotnet build "src/Api/Api.csproj" -c Release --no-restore
- name: 🧹 Format
- run: dotnet format --verify-no-changes --verbosity detailed --exclude 'Kijk.Api/Persistence/Migrations/'
+ run: dotnet format --verify-no-changes --verbosity detailed --exclude '**/Migrations/**'
- name: 🧪 Test
- run: dotnet test "Kijk.Api/Kijk.Api.csproj" --configuration Release --no-build
+ run: dotnet test "src/Api/Api.csproj" --configuration Release --no-build
- name: 🔍 Audit
run: |
diff --git a/apps/api/.editorconfig b/apps/api/.editorconfig
index e239d5b..7c1c11a 100644
--- a/apps/api/.editorconfig
+++ b/apps/api/.editorconfig
@@ -5,152 +5,391 @@ root = true
# All files
[*]
indent_style = space
+indent_size = 4
+tab_width = 4
+end_of_line = lf
+insert_final_newline = false
+max_line_length = 150
-# Microsoft .NET properties
-csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, async, unsafe, volatile, readonly, file, required:suggestion
-csharp_preserve_single_line_blocks = true
+# Xml files
+[*.xml]
+indent_size = 2
-# ReSharper properties
-resharper_blank_lines_before_single_line_comment = 1
-resharper_braces_redundant = false
-resharper_csharp_insert_final_newline = true
-resharper_csharp_keep_blank_lines_in_code = 1
-resharper_csharp_keep_blank_lines_in_declarations = 1
-resharper_csharp_max_line_length = 151
-resharper_csharp_wrap_after_declaration_lpar = true
-resharper_csharp_wrap_after_invocation_lpar = true
-resharper_csharp_wrap_parameters_style = chop_if_long
-resharper_keep_existing_declaration_parens_arrangement = false
-resharper_keep_existing_enum_arrangement = false
-resharper_keep_existing_invocation_parens_arrangement = false
-
-# XML project files
-[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+# Json files
+[*.json]
indent_size = 2
-# XML config files
-[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+# yaml files
+[*.{yml,yaml}]
indent_size = 2
-# Code files
-[*.{cs,csx,vb,vbx}]
-indent_size = 4
-insert_final_newline = true
-charset = utf-8-bom
-###############################
-# .NET Coding Conventions #
-###############################
+# Ignore paths
+[src/Api/Persistence/Migrations/*]
+generated_code = true
+
+#### .NET Coding Conventions ####
[*.{cs,vb}]
# Organize usings
+dotnet_separate_import_directive_groups = true
dotnet_sort_system_directives_first = true
-# this. preferences
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false:silent
dotnet_style_qualification_for_field = false:silent
-dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
-dotnet_style_qualification_for_event = false:silent
+dotnet_style_qualification_for_property = false:silent
+
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
+
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
-dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
-dotnet_style_readonly_field = true:suggestion
+
# Expression-level preferences
-dotnet_style_object_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
-dotnet_style_coalesce_expression = true:suggestion
-dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
-dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
-dotnet_style_prefer_auto_properties = true:silent
-dotnet_style_prefer_conditional_expression_over_assignment = true:silent
-dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
-# dotnet_diagnostic.CA1813.severity = suggestion
-dotnet_diagnostic.CA1802.severity = warning
-dotnet_diagnostic.CA1810.severity = warning
+# Field preferences
+dotnet_style_readonly_field = true:warning
-###############################
-# Naming Conventions #
-###############################
-# Style Definitions
-dotnet_naming_style.pascal_case_style.capitalization = pascal_case
-# Use PascalCase for constant fields
-dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
-dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
-dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
-dotnet_naming_symbols.constant_fields.applicable_kinds = field
-dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
-dotnet_naming_symbols.constant_fields.required_modifiers = const
-###############################
-# C# Coding Conventions #
-###############################
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all:suggestion
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+#### C# Coding Conventions ####
[*.cs]
+csharp_style_namespace_declarations = file_scoped
+dotnet_style_prefer_collection_expression = true:suggestion
# var preferences
-csharp_style_var_for_built_in_types = true:silent
-csharp_style_var_when_type_is_apparent = true:silent
-csharp_style_var_elsewhere = true:silent
+csharp_style_var_elsewhere = true
+csharp_style_var_for_built_in_types = true
+csharp_style_var_when_type_is_apparent = true
+
# Expression-bodied members
-csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:suggestion
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_expression_bodied_methods = true:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
-csharp_style_expression_bodied_indexers = true:silent
-csharp_style_expression_bodied_accessors = true:silent
+
# Pattern matching preferences
-csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+
# Null-checking preferences
-csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
+
# Modifier preferences
-csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion # A property with the same name was updated with a value public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, async, unsafe, volatile, readonly, file, required:suggestion in a section [*]
-# Expression-level preferences
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:silent
+
+# Code-block preferences
csharp_prefer_braces = true:silent
-csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_prefer_simple_using_statement = true:suggestion
+
+# Expression-level preferences
csharp_prefer_simple_default_expression = true:suggestion
-csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
-###############################
-# C# Formatting Rules #
-###############################
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:silent
+
+#### C# Formatting Rules ####
+
# New line preferences
-csharp_new_line_before_open_brace = all
-csharp_new_line_before_else = true
csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
csharp_new_line_before_finally = true
-csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
+
# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
-csharp_indent_labels = flush_left
+
# Space preferences
csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_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_declaration_parameter_list_parentheses = false
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_empty_parameter_list_parentheses = false
-csharp_space_between_method_call_name_and_opening_parenthesis = false
-csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_square_brackets = false
+
# Wrapping preferences
-csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
-###############################
-# VB Coding Conventions #
-###############################
-[*.vb]
-# Modifier preferences
-visual_basic_preferred_modifier_order = Partial, Default, Private, Protected, Public, Friend, NotOverridable, Overridable, MustOverride, Overloads, Overrides, MustInherit, NotInheritable, Static, Shared, Shadows, ReadOnly, WriteOnly, Dim, Const, WithEvents, Widening, Narrowing, Custom, Async:suggestion
+csharp_preserve_single_line_statements = true
+
+#### Naming styles ####
+# Naming rules
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion
+dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces
+dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase
+
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase
+
+dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods
+dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties
+dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.events_should_be_pascalcase.symbols = events
+dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables
+dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants
+dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion
+dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters
+dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields
+dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion
+dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields
+dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase
+
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase
+
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums
+dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase
+
+# Symbol specifications
+
+dotnet_naming_symbols.interfaces.applicable_kinds = interface
+dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interfaces.required_modifiers =
+
+dotnet_naming_symbols.enums.applicable_kinds = enum
+dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.enums.required_modifiers =
+
+dotnet_naming_symbols.events.applicable_kinds = event
+dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.events.required_modifiers =
+
+dotnet_naming_symbols.methods.applicable_kinds = method
+dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.methods.required_modifiers =
+
+dotnet_naming_symbols.properties.applicable_kinds = property
+dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.properties.required_modifiers =
+
+dotnet_naming_symbols.public_fields.applicable_kinds = field
+dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_fields.required_modifiers =
+
+dotnet_naming_symbols.private_fields.applicable_kinds = field
+dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_fields.required_modifiers =
+
+dotnet_naming_symbols.private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_fields.required_modifiers = static
+
+dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum
+dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types_and_namespaces.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+dotnet_naming_symbols.type_parameters.applicable_kinds = namespace
+dotnet_naming_symbols.type_parameters.applicable_accessibilities = *
+dotnet_naming_symbols.type_parameters.required_modifiers =
+
+dotnet_naming_symbols.private_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.local_variables.applicable_kinds = local
+dotnet_naming_symbols.local_variables.applicable_accessibilities = local
+dotnet_naming_symbols.local_variables.required_modifiers =
+
+dotnet_naming_symbols.local_constants.applicable_kinds = local
+dotnet_naming_symbols.local_constants.applicable_accessibilities = local
+dotnet_naming_symbols.local_constants.required_modifiers = const
+
+dotnet_naming_symbols.parameters.applicable_kinds = parameter
+dotnet_naming_symbols.parameters.applicable_accessibilities = *
+dotnet_naming_symbols.parameters.required_modifiers =
+
+dotnet_naming_symbols.public_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+dotnet_naming_symbols.local_functions.applicable_accessibilities = *
+dotnet_naming_symbols.local_functions.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascalcase.required_prefix =
+dotnet_naming_style.pascalcase.required_suffix =
+dotnet_naming_style.pascalcase.word_separator =
+dotnet_naming_style.pascalcase.capitalization = pascal_case
+
+dotnet_naming_style.ipascalcase.required_prefix = I
+dotnet_naming_style.ipascalcase.required_suffix =
+dotnet_naming_style.ipascalcase.word_separator =
+dotnet_naming_style.ipascalcase.capitalization = pascal_case
+
+dotnet_naming_style.tpascalcase.required_prefix = T
+dotnet_naming_style.tpascalcase.required_suffix =
+dotnet_naming_style.tpascalcase.word_separator =
+dotnet_naming_style.tpascalcase.capitalization = pascal_case
+
+dotnet_naming_style._camelcase.required_prefix = _
+dotnet_naming_style._camelcase.required_suffix =
+dotnet_naming_style._camelcase.word_separator =
+dotnet_naming_style._camelcase.capitalization = camel_case
+
+dotnet_naming_style.camelcase.required_prefix =
+dotnet_naming_style.camelcase.required_suffix =
+dotnet_naming_style.camelcase.word_separator =
+dotnet_naming_style.camelcase.capitalization = camel_case
+
+dotnet_naming_style.s_camelcase.required_prefix = s_
+dotnet_naming_style.s_camelcase.required_suffix =
+dotnet_naming_style.s_camelcase.word_separator =
+dotnet_naming_style.s_camelcase.capitalization = camel_case
+
+# c# rules
+dotnet_diagnostic.1591.severity = none
+dotnet_diagnostic.IDE0053.severity = false
+dotnet_diagnostic.IDE0055.severity = none
+dotnet_diagnostic.IDE0023.severity = none
+# dotnet rules
+dotnet_diagnostic.CA1304.severity = none
+dotnet_diagnostic.CA1305.severity = none
+dotnet_diagnostic.CA1311.severity = none
+dotnet_diagnostic.CA1000.severity = none
+dotnet_diagnostic.CA1862.severity = suggestion
+# Sonarlint rules
+dotnet_diagnostic.S1133.severity = none
+dotnet_diagnostic.S125.severity = warning
+dotnet_diagnostic.S1135.severity = none
+dotnet_diagnostic.S2094.severity = none
+dotnet_diagnostic.S2325.severity = suggestion
+dotnet_diagnostic.S4830.severity = none
+dotnet_diagnostic.S6667.severity = none
+dotnet_diagnostic.S6602.severity = error
+dotnet_diagnostic.S6603.severity = none
+dotnet_diagnostic.S6605.severity = none
+dotnet_diagnostic.S2139.severity = none
+dotnet_diagnostic.NU1901.severity = none
+dotnet_diagnostic.NU1902.severity = none
+dotnet_diagnostic.NU1903.severity = none
+dotnet_diagnostic.NU1904.severity = none
\ No newline at end of file
diff --git a/apps/api/Directory.Build.props b/apps/api/Directory.Build.props
new file mode 100644
index 0000000..fd4d1ab
--- /dev/null
+++ b/apps/api/Directory.Build.props
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ net9.0
+ preview
+ true
+ enable
+
+
+
+
+
+
+
+ true
+ true
+ true
+ latest
+ Recommended
+ $(NoWarn);1591;
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/api/Directory.Packages.props b/apps/api/Directory.Packages.props
new file mode 100644
index 0000000..ce1d140
--- /dev/null
+++ b/apps/api/Directory.Packages.props
@@ -0,0 +1,54 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Extensions/ApplicationExtensions.cs b/apps/api/Kijk.Api/Common/Extensions/ApplicationExtensions.cs
deleted file mode 100644
index 16a8c96..0000000
--- a/apps/api/Kijk.Api/Common/Extensions/ApplicationExtensions.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using HealthChecks.UI.Client;
-using Kijk.Api.Common.Models;
-using Kijk.Api.Endpoints;
-using Kijk.Api.Persistence;
-using Microsoft.AspNetCore.Diagnostics.HealthChecks;
-
-namespace Kijk.Api.Common.Extensions;
-
-public static class ApplicationExtensions
-{
- public static IApplicationBuilder UseCustomOpenApi(this IApplicationBuilder applicationBuilder)
- {
- applicationBuilder.UseSwagger(
- c =>
- {
- c.RouteTemplate = "api/swagger/{documentName}/swagger.json";
- });
- applicationBuilder.UseSwaggerUI(
- c =>
- {
- // c.UseRequestInterceptor(
- // "(req) => { req.headers['Authorization'] = 'Bearer ' + window?.swaggerUIRedirectOauth2?.auth?.token?.access_token; return req; }");
- c.DefaultModelsExpandDepth(0);
- c.DefaultModelExpandDepth(0);
- c.SwaggerEndpoint("v1/swagger.json", "Kijk Api v1.00");
- c.RoutePrefix = "api/swagger";
- });
- return applicationBuilder;
- }
-
- public static IApplicationBuilder ApplyInitialData(this IApplicationBuilder applicationBuilder)
- {
- using var scope = applicationBuilder.ApplicationServices.CreateScope();
- using var dbContext = scope.ServiceProvider.GetRequiredService();
-
- AppDbInitializer.InitDb(dbContext);
-
- return applicationBuilder;
- }
-
- public static IApplicationBuilder ApplyMigrations(this IApplicationBuilder applicationBuilder)
- {
- using var scope = applicationBuilder.ApplicationServices.CreateScope();
- using var dbContext = scope.ServiceProvider.GetRequiredService();
-
- dbContext.Database.MigrateAsync();
- Log.ForContext(typeof(AppDbInitializer)).Information("Database migrations applied");
-
- return applicationBuilder;
- }
-
- public static IApplicationBuilder MapApiEndpoints(this IApplicationBuilder applicationBuilder)
- {
- var app = (WebApplication)applicationBuilder;
- app.Map("/", () => Results.Redirect("api/swagger"));
-
- var apiGroup = app.MapGroup("/api")
- .RequireAuthorization(AppConstants.Policies.All)
- .WithOpenApi();
-
- apiGroup.RequirePerUserRateLimit();
-
- apiGroup.MapTransactionsEndpoints();
- apiGroup.MapUsersApi();
- apiGroup.MapCategoriesApi();
-
- return app;
- }
-
- public static IApplicationBuilder MapHealthCheck(this IApplicationBuilder applicationBuilder)
- {
- var app = (IEndpointRouteBuilder)applicationBuilder;
- app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse });
-
- return applicationBuilder;
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Extensions/AuthorizationHandlerExtension.cs b/apps/api/Kijk.Api/Common/Extensions/AuthorizationHandlerExtension.cs
deleted file mode 100644
index 45f0844..0000000
--- a/apps/api/Kijk.Api/Common/Extensions/AuthorizationHandlerExtension.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Kijk.Api.Common.Models;
-using Microsoft.AspNetCore.Authorization;
-
-namespace Kijk.Api.Common.Extensions;
-
-public static class AuthorizationHandlerExtensions
-{
- // Adds the current user requirement that will activate our authorization handler
- public static AuthorizationPolicyBuilder RequireCurrentUser(this AuthorizationPolicyBuilder builder)
- {
- return builder.RequireAuthenticatedUser().AddRequirements(new CheckCurrentUserRequirement());
- }
-}
-
-public class CheckCurrentUserRequirement : IAuthorizationRequirement
-{
-}
-
-// This authorization handler verifies that the user exists even if there's a valid token
-public class CheckCurrentUserAuthHandler(CurrentUser currentUser) : AuthorizationHandler
-{
- protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CheckCurrentUserRequirement requirement)
- {
- if (currentUser is { User.AuthId: not null } and { Principal: not null })
- {
- context.Succeed(requirement);
- }
-
- return Task.CompletedTask;
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Extensions/CurrentUserExtension.cs b/apps/api/Kijk.Api/Common/Extensions/CurrentUserExtension.cs
deleted file mode 100644
index 2da72ac..0000000
--- a/apps/api/Kijk.Api/Common/Extensions/CurrentUserExtension.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Security.Claims;
-using Kijk.Api.Common.Models;
-using Kijk.Api.Domain.Entities;
-using Kijk.Api.Persistence;
-using Microsoft.AspNetCore.Authentication;
-
-namespace Kijk.Api.Common.Extensions;
-
-public static class CurrentUserExtensions
-{
- public static IServiceCollection AddCurrentUser(this IServiceCollection services)
- {
- services.AddScoped();
- services.AddScoped();
- return services;
- }
-
- ///
- /// This class gets only called if is NOT null.
- ///
- private sealed class ClaimsTransformation(CurrentUser currentUser, AppDbContext dbContext) : IClaimsTransformation
- {
- // We're not going to transform anything. We're using this as a hook into authorization
- // to set the current user without adding custom middleware.
- public async Task TransformAsync(ClaimsPrincipal principal)
- {
- var sub = principal.FindFirstValue(ClaimTypes.NameIdentifier);
-
- if (sub != null)
- {
- var email = principal.FindFirstValue(ClaimTypes.Email);
- var userEntity = await dbContext.Users
- .AsNoTracking()
- .Where(x => x.AuthId == sub)
- .Select(x => SimpleAuthUser.Create(x))
- .FirstOrDefaultAsync();
-
- currentUser.Principal = principal;
- // TODO use more values from token
- currentUser.User = userEntity ?? new SimpleAuthUser(
- Guid.NewGuid(),
- sub,
- AppConstants.CreateUserIdentifier,
- email,
- true);
- }
-
- return await Task.FromResult(principal);
- }
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Extensions/EnumerableExtensions.cs b/apps/api/Kijk.Api/Common/Extensions/EnumerableExtensions.cs
deleted file mode 100644
index a3adfe7..0000000
--- a/apps/api/Kijk.Api/Common/Extensions/EnumerableExtensions.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace Kijk.Api.Common.Extensions;
-
-public static class EnumerableExtensions
-{
- public static IQueryable If(this IQueryable query, bool should, params Func, IQueryable>[] transforms)
- {
- return should
- ? transforms.Aggregate(
- query,
- (current, transform) => transform.Invoke(current))
- : query;
- }
-
- public static IEnumerable If(this IEnumerable query, bool should, params Func, IEnumerable>[] transforms)
- {
- return should
- ? transforms.Aggregate(
- query,
- (current, transform) => transform.Invoke(current))
- : query;
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Extensions/RateLimitExtension.cs b/apps/api/Kijk.Api/Common/Extensions/RateLimitExtension.cs
deleted file mode 100644
index cb3860b..0000000
--- a/apps/api/Kijk.Api/Common/Extensions/RateLimitExtension.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System.Security.Claims;
-using System.Threading.RateLimiting;
-
-using Kijk.Api.Common.Models;
-
-namespace Kijk.Api.Common.Extensions;
-
-public static class RateLimitExtensions
-{
-
- public static IServiceCollection AddRateLimitPolicy(this IServiceCollection services)
- {
- return services.AddRateLimiter(
- options =>
- {
- options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
-
- options.AddPolicy(
- AppConstants.Policies.RateLimit,
- context =>
- {
- var username = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
-
- // 100 Requests per 10sec per user
- return RateLimitPartition.GetTokenBucketLimiter(
- username,
- _ => new TokenBucketRateLimiterOptions
- {
- ReplenishmentPeriod = TimeSpan.FromSeconds(10),
- AutoReplenishment = true,
- TokenLimit = 100,
- TokensPerPeriod = 100,
- QueueLimit = 100
- });
- });
- });
- }
-
- public static IEndpointConventionBuilder RequirePerUserRateLimit(this IEndpointConventionBuilder builder)
- {
- return builder.RequireRateLimiting(AppConstants.Policies.RateLimit);
- }
-}
diff --git a/apps/api/Kijk.Api/Common/GlobalExceptionHandler.cs b/apps/api/Kijk.Api/Common/GlobalExceptionHandler.cs
deleted file mode 100644
index c39f6b7..0000000
--- a/apps/api/Kijk.Api/Common/GlobalExceptionHandler.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Net;
-using System.Text.Json;
-
-using Kijk.Api.Common.Models;
-
-using Microsoft.AspNetCore.Diagnostics;
-
-using Sentry;
-
-namespace Kijk.Api.Common;
-
-public class GlobalExceptionHandler : IExceptionHandler
-{
-
- public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
- {
- httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
- httpContext.Response.ContentType = "application/json";
-
- var exceptionHandlerFeature = httpContext.Features.Get();
- if (exceptionHandlerFeature is not null)
- {
- SentrySdk.CaptureException(exceptionHandlerFeature.Error);
- Log.ForContext(typeof(ExceptionHandlerMiddleware)).Error(
- "Something went wrong: {ContextFeatureError}",
- exceptionHandlerFeature.Error.Message);
-
- var error = AppError.Unexpected(
- AppErrorCodes.UnexpectedError,
- $"Ups, etwas ist schief gelaufen. {exceptionHandlerFeature.Error.Message}");
- var json = JsonSerializer.Serialize(ApiResponse.Error(error));
- await httpContext.Response.WriteAsync(json, cancellationToken: cancellationToken);
- }
-
- return true;
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Middleware/AuthResponseHandlerMiddleware.cs b/apps/api/Kijk.Api/Common/Middleware/AuthResponseHandlerMiddleware.cs
deleted file mode 100644
index 331f84a..0000000
--- a/apps/api/Kijk.Api/Common/Middleware/AuthResponseHandlerMiddleware.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System.Net;
-using System.Text.Json;
-using Kijk.Api.Common.Models;
-
-namespace Kijk.Api.Common.Middleware;
-
-public static class AuthResponseHandlerMiddleware
-{
- public static IApplicationBuilder UseAuthExceptionHandler(this IApplicationBuilder app)
- {
- app.Use(
- async (context, next) =>
- {
- await next();
-
- if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
- {
- context.Response.ContentType = "application/json";
- var resp = ApiResponseBuilder.Error(AppError.Basic(AppErrorCodes.AuthenticationError, "Token is not valid"));
- SentToSentry(resp);
- await context.Response.WriteAsync(JsonSerializer.Serialize(resp));
- }
-
- if (context.Response.StatusCode == (int)HttpStatusCode.Forbidden)
- {
- context.Response.ContentType = "application/json";
- var resp = ApiResponseBuilder.Error(AppError.Basic(AppErrorCodes.AuthorizationError, "Role is not sufficient"));
- SentToSentry(resp);
- await context.Response.WriteAsync(JsonSerializer.Serialize(resp));
- }
- });
- return app;
- }
-
- private static void SentToSentry(ApiResponse> resp)
- {
- SentrySdk.CaptureMessage(
- resp.Data?[0].Message ?? "AuthError: Token or role is not valid",
- opt =>
- {
- opt.SetExtra("Response", resp);
- opt.SetExtra("Code", resp.Data?[0].Code);
- });
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Models/ApiResponse.cs b/apps/api/Kijk.Api/Common/Models/ApiResponse.cs
deleted file mode 100644
index 50b36b8..0000000
--- a/apps/api/Kijk.Api/Common/Models/ApiResponse.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace Kijk.Api.Common.Models;
-
-public record ApiResponse
-{
- public T? Data { get; init; }
-
- public ResponseStatus Status { get; set; }
-
- public string? Message { get; set; }
-
- public static implicit operator ApiResponse(T data) => Success(data);
-
- public static ApiResponse Success(T data, string? message = default)
- {
- return new ApiResponse { Status = ResponseStatus.Success, Data = data, Message = message };
- }
-
- public static ApiResponse> Error(string errorMessage)
- {
- return new ApiResponse> { Status = ResponseStatus.Error, Message = errorMessage, Data = new List() };
- }
-
- public static ApiResponse> Error(List error, string? errorMessage = default)
- {
- return new ApiResponse> { Status = ResponseStatus.Error, Message = errorMessage, Data = error };
- }
-
- public static ApiResponse> Error(AppError appError, string? errorMessage = default)
- {
- return new ApiResponse> { Status = ResponseStatus.Error, Message = errorMessage, Data = new List { appError } };
- }
-}
diff --git a/apps/api/Kijk.Api/Common/Models/CurrentUser.cs b/apps/api/Kijk.Api/Common/Models/CurrentUser.cs
deleted file mode 100644
index 03e209b..0000000
--- a/apps/api/Kijk.Api/Common/Models/CurrentUser.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Security.Claims;
-using Kijk.Api.Domain.Entities;
-
-namespace Kijk.Api.Common.Models;
-
-public class CurrentUser
-{
- private const string PermissionsClaim = "permissions";
-
- public required ClaimsPrincipal Principal { get; set; }
-
- public required SimpleAuthUser User { get; set; }
-
- public Guid Id => this.User.Id;
-
- public string AuthId => this.User.AuthId ?? throw new ArgumentNullException(this.User.AuthId, "'AuthId' not found");
-
- public string Name => this.User.Name ?? throw new ArgumentNullException(this.User.Name, "'Name' not found");
-
- public string Email => this.User.Email ?? throw new ArgumentNullException(ClaimTypes.Upn, "'Upn/Email' not found");
-
- public List Permissions => Principal.FindAll(PermissionsClaim).Select(x => x.Value).ToList();
-
- public bool IsAdmin => this.Permissions.Contains(AppConstants.Roles.Admin);
-
- public bool IsUser => this.Permissions.Contains(AppConstants.Roles.Admin);
-}
diff --git a/apps/api/Kijk.Api/Dockerfile b/apps/api/Kijk.Api/Dockerfile
deleted file mode 100644
index 21b472b..0000000
--- a/apps/api/Kijk.Api/Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
-USER $APP_UID
-WORKDIR /app
-EXPOSE 8080
-EXPOSE 8081
-
-FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
-ARG BUILD_CONFIGURATION=Release
-WORKDIR /src
-COPY ["Kijk.Api/Kijk.Api.csproj", "Kijk.Api/"]
-RUN dotnet restore "Kijk.Api/Kijk.Api.csproj"
-COPY . .
-WORKDIR "/src/Kijk.Api"
-RUN dotnet build "Kijk.Api.csproj" -c "$BUILD_CONFIGURATION" -o /app/build
-
-FROM build AS publish
-ARG BUILD_CONFIGURATION=Release
-RUN dotnet publish "Kijk.Api.csproj" -c "$BUILD_CONFIGURATION" -o /app/publish /p:UseAppHost=false
-
-FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "Kijk.Api.dll"]
diff --git a/apps/api/Kijk.Api/Kijk.Api.csproj b/apps/api/Kijk.Api/Kijk.Api.csproj
deleted file mode 100644
index 1fe7373..0000000
--- a/apps/api/Kijk.Api/Kijk.Api.csproj
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
- aspnet-Kijk.Api-01C3D95B-517D-4E64-8BDD-4EADF1BF84FE
- Linux
-
- true
- $(NoWarn);1591
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
-
-
- appsettings.json
-
-
- .dockerignore
-
-
- appsettings.json
-
-
-
-
-
-
-
-
diff --git a/apps/api/Kijk.sln b/apps/api/Kijk.sln
index f29b182..11b0637 100644
--- a/apps/api/Kijk.sln
+++ b/apps/api/Kijk.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kijk.Api", "Kijk.Api\Kijk.Api.csproj", "{864226C8-F64E-450A-B026-783052D78AAB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "src\Api\Api.csproj", "{864226C8-F64E-450A-B026-783052D78AAB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{61A8A4BF-DF87-44EA-9C2F-6D432917846E}"
ProjectSection(SolutionItems) = preProject
@@ -14,8 +14,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
README.md = README.md
fly.toml = fly.toml
..\..\.github\workflows\api.yml = ..\..\.github\workflows\api.yml
+ Directory.Packages.props = Directory.Packages.props
+ Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{061A6C51-5834-45BC-A557-4FFE1CDF615D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,4 +31,7 @@ Global
{864226C8-F64E-450A-B026-783052D78AAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{864226C8-F64E-450A-B026-783052D78AAB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {864226C8-F64E-450A-B026-783052D78AAB} = {061A6C51-5834-45BC-A557-4FFE1CDF615D}
+ EndGlobalSection
EndGlobal
diff --git a/apps/api/global.json b/apps/api/global.json
index c65c9ea..a27a2b8 100644
--- a/apps/api/global.json
+++ b/apps/api/global.json
@@ -1,7 +1,7 @@
{
"sdk": {
- "version": "8.0.0",
- "rollForward": "latestMinor",
- "allowPrerelease": true
+ "version": "9.0.0",
+ "rollForward": "latestMajor",
+ "allowPrerelease": false
}
}
\ No newline at end of file
diff --git a/apps/api/package.json b/apps/api/package.json
index 8c8287a..e78a8f5 100644
--- a/apps/api/package.json
+++ b/apps/api/package.json
@@ -16,8 +16,7 @@
"scripts": {
"dev": "dotnet watch run --project Kijk.Api/Kijk.Api.csproj --launch-profile https",
"build": "dotnet build \"Kijk.Api/Kijk.Api.csproj\" -c Release",
- "lint": "dotnet format --verify-no-changes --verbosity detailed --exclude 'Kijk.Api/Persistence/Migrations/'",
- "lint:fix": "dotnet format --exclude 'Kijk.Api/Persistence/Migrations/'",
- "format": "dotnet format --verify-no-changes --verbosity detailed --exclude 'Kijk.Api/Persistence/Migrations/'"
+ "lint": "dotnet format --verify-no-changes --verbosity detailed --exclude '**/Migrations/'",
+ "lint:fix": "dotnet format --exclude '**/Migrations/'"
}
}
diff --git a/apps/api/src/Api/Api.csproj b/apps/api/src/Api/Api.csproj
new file mode 100644
index 0000000..ecadc2f
--- /dev/null
+++ b/apps/api/src/Api/Api.csproj
@@ -0,0 +1,72 @@
+
+
+
+ Kijk.Api
+
+ aspnet-Kijk.Api-01C3D95B-517D-4E64-8BDD-4EADF1BF84FE
+ Linux
+
+ ./
+ --file-name kijk
+ true
+ true
+ true
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+ appsettings.json
+
+
+ .dockerignore
+
+
+ appsettings.json
+
+
+
+
+
+
+
+
diff --git a/apps/api/src/Api/Common/Exceptions/NullException.cs b/apps/api/src/Api/Common/Exceptions/NullException.cs
new file mode 100644
index 0000000..5776273
--- /dev/null
+++ b/apps/api/src/Api/Common/Exceptions/NullException.cs
@@ -0,0 +1,7 @@
+namespace Kijk.Api.Common.Exceptions;
+
+///
+/// Exception thrown when a null value is passed to a method that does not accept it.
+///
+/// The exception message.
+public class NullException(string message) : Exception(message);
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Extensions/ApplicationExtensions.cs b/apps/api/src/Api/Common/Extensions/ApplicationExtensions.cs
new file mode 100644
index 0000000..0272e57
--- /dev/null
+++ b/apps/api/src/Api/Common/Extensions/ApplicationExtensions.cs
@@ -0,0 +1,84 @@
+using HealthChecks.UI.Client;
+
+using Kijk.Api.Common.Models;
+using Kijk.Api.Endpoints;
+
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+
+using Swashbuckle.AspNetCore.SwaggerUI;
+
+namespace Kijk.Api.Common.Extensions;
+
+public static class ApplicationExtensions
+{
+ public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder applicationBuilder)
+ {
+ applicationBuilder.UseSerilogRequestLogging(
+ options => options.GetLevel = new Func((ctx, _, ex) =>
+ {
+ if (ex == null && ctx.Response.StatusCode <= 499)
+ {
+ return LogEventLevel.Information;
+ }
+
+ if (ctx.Request.Path.StartsWithSegments("/api/health") && ex is OperationCanceledException)
+ {
+ // If the incoming HTTP request for a healthcheck is aborted, don't log the resultant OperationCanceledException
+ // as an error. beware that the ASP.NET DefaultHealthCheckService ensures that if the exception occurs
+ // within the healthcheck implementation (and the request wasn't aborted) a failed healthcheck is logged
+ // see https://github.com/dotnet/aspnetcore/blob/ce9e1ae5500c3f0c4b9bd682fd464b3493e48e61/src/HealthChecks/HealthChecks/src/DefaultHealthCheckService.cs#L121
+ return LogEventLevel.Information;
+ }
+
+ return LogEventLevel.Error;
+ }));
+
+ return applicationBuilder;
+ }
+
+ public static IApplicationBuilder UseOpenApi(this IApplicationBuilder applicationBuilder)
+ {
+ applicationBuilder.UseSwaggerUI(
+ c =>
+ {
+ c.SwaggerEndpoint("/api/openapi.json", "Kijk Api v1.0");
+ c.DefaultModelsExpandDepth(0);
+ c.DefaultModelExpandDepth(0);
+ c.DocExpansion(DocExpansion.None);
+ c.DocumentTitle = "SwaggerUI - Kijk Api";
+ c.RoutePrefix = "api/swagger";
+ });
+ return applicationBuilder;
+ }
+
+ public static void ApplyInitialData(this IApplicationBuilder _)
+ {
+ // using var scope = applicationBuilder.ApplicationServices.CreateScope();
+ // using var dbContext = scope.ServiceProvider.GetRequiredService();
+
+ // TODO move into sql generation script
+ // this breaks the auto generation of the openapi file
+ // AppDbInitializer.InitDb(dbContext);
+ }
+
+ public static WebApplication MapApiEndpoints(this WebApplication app)
+ {
+ var apiGroup = app.MapGroup("/api")
+ .RequireAuthorization(AppConstants.Policies.All)
+ .RequirePerUserRateLimit();
+
+ apiGroup.MapTransactionsEndpoints();
+ apiGroup.MapUsersApi();
+ apiGroup.MapCategoriesApi();
+
+ return app;
+ }
+
+ public static IApplicationBuilder MapHealthCheck(this IApplicationBuilder applicationBuilder)
+ {
+ var app = (IEndpointRouteBuilder)applicationBuilder;
+ app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse });
+
+ return applicationBuilder;
+ }
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Extensions/BearerAuthSchemeTransformer.cs b/apps/api/src/Api/Common/Extensions/BearerAuthSchemeTransformer.cs
new file mode 100644
index 0000000..baeac94
--- /dev/null
+++ b/apps/api/src/Api/Common/Extensions/BearerAuthSchemeTransformer.cs
@@ -0,0 +1,54 @@
+using Kijk.Api.Common.Exceptions;
+using Kijk.Api.Common.Options;
+
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.OpenApi;
+using Microsoft.OpenApi.Models;
+
+namespace Kijk.Api.Common.Extensions;
+
+///
+/// Schema transformer for the OpenApi document to add the Oauth2 (Bearer) authentication.
+///
+///
+///
+public sealed class BearerAuthSchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider, IConfiguration configuration)
+ : IOpenApiDocumentTransformer
+{
+ public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
+ {
+ var appSettings = configuration.GetSection(AuthOptions.SectionName).Get();
+
+ if (appSettings is null)
+ {
+ throw new NullException($"Keine AuthOptions gefunden, {appSettings}");
+ }
+
+ var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
+ if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
+ {
+ var requirements = new Dictionary
+ {
+ ["Bearer"] = new()
+ {
+ Type = SecuritySchemeType.Http,
+ Scheme = "bearer",
+ In = ParameterLocation.Header,
+ BearerFormat = "Json Web Token",
+ Description = "JWT Authorization header using the Bearer scheme."
+ }
+ };
+ document.Components ??= new OpenApiComponents();
+ document.Components.SecuritySchemes = requirements;
+ // Apply it as a requirement for all operations
+ foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
+ {
+ operation.Value.Security.Add(new OpenApiSecurityRequirement
+ {
+ [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] =
+ Array.Empty()
+ });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Extensions/EnumerableExtensions.cs b/apps/api/src/Api/Common/Extensions/EnumerableExtensions.cs
new file mode 100644
index 0000000..794d580
--- /dev/null
+++ b/apps/api/src/Api/Common/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,16 @@
+namespace Kijk.Api.Common.Extensions;
+
+public static class EnumerableExtensions
+{
+ public static IQueryable If(this IQueryable query, bool should, params Func, IQueryable>[] transforms) => should
+ ? transforms.Aggregate(
+ query,
+ (current, transform) => transform.Invoke(current))
+ : query;
+
+ public static IEnumerable If(this IEnumerable query, bool should, params Func, IEnumerable>[] transforms) => should
+ ? transforms.Aggregate(
+ query,
+ (current, transform) => transform.Invoke(current))
+ : query;
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Extensions/HostExtensions.cs b/apps/api/src/Api/Common/Extensions/HostExtensions.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Extensions/HostExtensions.cs
rename to apps/api/src/Api/Common/Extensions/HostExtensions.cs
index 07bf5ef..c2b688d 100644
--- a/apps/api/Kijk.Api/Common/Extensions/HostExtensions.cs
+++ b/apps/api/src/Api/Common/Extensions/HostExtensions.cs
@@ -23,4 +23,4 @@ public static WebApplicationBuilder AddLogging(this WebApplicationBuilder builde
return builder;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Extensions/OptionsExtension.cs b/apps/api/src/Api/Common/Extensions/OptionsExtension.cs
similarity index 59%
rename from apps/api/Kijk.Api/Common/Extensions/OptionsExtension.cs
rename to apps/api/src/Api/Common/Extensions/OptionsExtension.cs
index 696fe08..f1bcf06 100644
--- a/apps/api/Kijk.Api/Common/Extensions/OptionsExtension.cs
+++ b/apps/api/src/Api/Common/Extensions/OptionsExtension.cs
@@ -8,16 +8,10 @@ namespace Kijk.Api.Common.Extensions;
public static class OptionsExtensions
{
public static IServiceCollection ConfigureOptions(this IServiceCollection services, IConfiguration configuration)
- where TOptions : class, IConfigOptions
- {
- return services.Configure(configuration.GetSection(TOptions.SectionName));
- }
+ where TOptions : class, IConfigOptions => services.Configure(configuration.GetSection(TOptions.SectionName));
public static TOptions? GetConfigurationSection(this IHostApplicationBuilder builder)
- where TOptions : class, IConfigOptions
- {
- return builder.Configuration
- .GetSection(TOptions.SectionName)
- .Get();
- }
-}
+ where TOptions : class, IConfigOptions => builder.Configuration
+ .GetSection(TOptions.SectionName)
+ .Get();
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Extensions/RateLimitExtension.cs b/apps/api/src/Api/Common/Extensions/RateLimitExtension.cs
new file mode 100644
index 0000000..ca16456
--- /dev/null
+++ b/apps/api/src/Api/Common/Extensions/RateLimitExtension.cs
@@ -0,0 +1,38 @@
+using System.Security.Claims;
+using System.Threading.RateLimiting;
+
+using Kijk.Api.Common.Models;
+
+namespace Kijk.Api.Common.Extensions;
+
+public static class RateLimitExtensions
+{
+ public static IServiceCollection AddRateLimitPolicy(this IServiceCollection services) => services.AddRateLimiter(
+ options =>
+ {
+ options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
+
+ options.AddPolicy(AppConstants.Policies.RateLimit, context =>
+ {
+ var username = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
+
+ // 100 Requests per 10sec per user
+ return RateLimitPartition.GetTokenBucketLimiter(
+ username,
+ _ => new TokenBucketRateLimiterOptions
+ {
+ ReplenishmentPeriod = TimeSpan.FromSeconds(10),
+ AutoReplenishment = true,
+ TokenLimit = 100,
+ TokensPerPeriod = 100,
+ QueueLimit = 100
+ });
+ });
+ });
+
+ public static RouteGroupBuilder RequirePerUserRateLimit(this RouteGroupBuilder builder)
+ {
+ builder.RequireRateLimiting(AppConstants.Policies.RateLimit);
+ return builder;
+ }
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Extensions/RouteExtensions.cs b/apps/api/src/Api/Common/Extensions/RouteExtensions.cs
similarity index 66%
rename from apps/api/Kijk.Api/Common/Extensions/RouteExtensions.cs
rename to apps/api/src/Api/Common/Extensions/RouteExtensions.cs
index 67bb9d4..58f08cd 100644
--- a/apps/api/Kijk.Api/Common/Extensions/RouteExtensions.cs
+++ b/apps/api/src/Api/Common/Extensions/RouteExtensions.cs
@@ -1,4 +1,5 @@
using System.Net;
+
using Kijk.Api.Common.Filters;
namespace Kijk.Api.Common.Extensions;
@@ -11,9 +12,7 @@ public static class RouteExtensions
///
///
///
- public static RouteHandlerBuilder WithRequestValidation(this RouteHandlerBuilder builder) where TRequest : class
- {
- return builder.AddEndpointFilter>()
- .Produces((int)HttpStatusCode.BadRequest);
- }
-}
+ public static RouteHandlerBuilder WithRequestValidation(this RouteHandlerBuilder builder) where TRequest : class => builder
+ .AddEndpointFilter>()
+ .Produces((int)HttpStatusCode.BadRequest);
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Extensions/ServiceExtensions.cs b/apps/api/src/Api/Common/Extensions/ServiceExtensions.cs
similarity index 56%
rename from apps/api/Kijk.Api/Common/Extensions/ServiceExtensions.cs
rename to apps/api/src/Api/Common/Extensions/ServiceExtensions.cs
index 001254f..24c79aa 100644
--- a/apps/api/Kijk.Api/Common/Extensions/ServiceExtensions.cs
+++ b/apps/api/src/Api/Common/Extensions/ServiceExtensions.cs
@@ -1,10 +1,13 @@
using System.Globalization;
-using System.IO.Compression;
-using System.Reflection;
using System.Security.Claims;
using System.Text.Json.Serialization;
+
+using EntityFramework.Exceptions.PostgreSQL;
+
using Humanizer;
-using Kijk.Api.Common.Filters;
+
+using Kijk.Api.Common.Exceptions;
+using Kijk.Api.Common.Middleware;
using Kijk.Api.Common.Models;
using Kijk.Api.Common.Options;
using Kijk.Api.Modules.App;
@@ -13,12 +16,10 @@
using Kijk.Api.Modules.Users;
using Kijk.Api.Persistence;
using Kijk.Api.Persistence.Interceptors;
+
using Microsoft.AspNetCore.Authentication.JwtBearer;
-using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.ResponseCompression;
-using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.IdentityModel.Tokens;
-using Microsoft.OpenApi.Models;
namespace Kijk.Api.Common.Extensions;
@@ -51,94 +52,58 @@ public static IServiceCollection AddCorsPolicy(this IServiceCollection services,
throw new ArgumentNullException($"{allowedOrigins}", "Cors appsettings is null");
}
- services.AddCors(
- options =>
- {
- options.AddPolicy(
- AppConstants.Policies.Cors,
- builder =>
- {
- builder.WithOrigins(allowedOrigins)
- .AllowAnyMethod()
- .AllowAnyHeader();
- });
- });
+ services.AddCors(options => options.AddPolicy(
+ AppConstants.Policies.Cors, builder => builder.WithOrigins(allowedOrigins)
+ .AllowAnyMethod()
+ .AllowAnyHeader()));
return services;
}
public static IServiceCollection AddOpenApi(this IServiceCollection services, IConfiguration configuration)
{
- var authSettings = configuration.GetSection(AuthOptions.SectionName).Get();
+ var appSettings = configuration.GetSection(AuthOptions.SectionName).Get();
- if (authSettings is null)
+ if (appSettings is null)
{
- throw new Exception($"No auth settings found, {authSettings}");
+ throw new NullException($"Keine AzureAdSettings gefunden, {appSettings}");
}
- services.AddEndpointsApiExplorer();
- services.AddSwaggerGen(
- o =>
- {
- o.UseInlineDefinitionsForEnums();
- o.SwaggerDoc("v1", new() { Version = "v1", Title = "Kijk API", Description = "Kijk API to manage your houses" });
-
- o.AddSecurityDefinition(
- "bearerAuth",
- new OpenApiSecurityScheme
- {
- Type = SecuritySchemeType.Http,
- Scheme = "bearer",
- BearerFormat = "JWT",
- Description = "JWT Authorization header using the Bearer scheme."
- });
- o.AddSecurityRequirement(
- new OpenApiSecurityRequirement
- {
- {
- new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } },
- new string[] { }
- }
- });
-
- var xmlFilename = $"{typeof(Program).Assembly.GetName().Name}.xml";
- o.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
- });
+ services.AddOpenApi("openapi", opt => opt.AddDocumentTransformer((document, _, _) =>
+ {
+ document.Info = new() { Version = "v1", Title = "Kijk API", Description = "Kijk API to manage your houses", };
+ opt.AddDocumentTransformer();
+ return Task.CompletedTask;
+ }));
return services;
}
- public static IServiceCollection AddDatabase(this IServiceCollection services)
+ public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
{
- services.AddScoped();
+ services.AddSingleton();
- services.AddDbContext();
+ services.AddDbContextPool((sp, optionsBuilder) =>
+ {
+ var connectionString = configuration.GetConnectionString("DefaultConnection");
+ // TODO use MapEnum and use database enums
+ optionsBuilder.UseNpgsql(connectionString, opt => opt.EnableRetryOnFailure())
+ .UseExceptionProcessor()
+ .UseSnakeCaseNamingConvention()
+ .AddInterceptors(sp.GetServices());
+ });
return services;
}
public static IServiceCollection AddCompression(this IServiceCollection services)
{
- services.AddResponseCompression(
- options =>
- {
- options.EnableForHttps = true;
- options.Providers.Add();
- options.Providers.Add();
- options.MimeTypes = ResponseCompressionDefaults.MimeTypes;
- });
-
- services.Configure(
- options =>
- {
- options.Level = CompressionLevel.Optimal;
- });
-
- services.Configure(
- options =>
- {
- options.Level = CompressionLevel.SmallestSize;
- });
-
+ services.AddResponseCompression(options =>
+ {
+ options.EnableForHttps = true;
+ options.Providers.Add();
+ options.Providers.Add();
+ options.MimeTypes = ResponseCompressionDefaults.MimeTypes;
+ });
return services;
}
@@ -154,9 +119,7 @@ public static IServiceCollection AddControllerOptions(this IServiceCollection se
{
services.ConfigureHttpJsonOptions(options => options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()));
- services.AddControllers().AddJsonOptions(
- options =>
- options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
+ services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
return services;
}
@@ -166,7 +129,7 @@ public static IServiceCollection AddHealthCheck(this IServiceCollection services
var conString = configuration.GetConnectionString(ConnectionOptions.SectionName);
if (conString is null)
{
- throw new Exception($"No connection string found, {conString}");
+ throw new NullException($"No connection string found, {conString}");
}
services.AddHealthChecks().AddNpgSql(conString, tags: ["database", "postgresql"]);
@@ -180,6 +143,7 @@ public static IServiceCollection AddAuth(this IServiceCollection services, IConf
.AddJwtBearer(
x =>
{
+ // Authority is the URL of your clerk instance
x.Authority = configuration["Auth:Authority"];
x.TokenValidationParameters = new TokenValidationParameters()
{
@@ -187,7 +151,7 @@ public static IServiceCollection AddAuth(this IServiceCollection services, IConf
ValidateAudience = false,
NameClaimType = ClaimTypes.NameIdentifier
};
- x.Events = new JwtBearerEvents()
+ x.Events = new JwtBearerEvents
{
// Additional validation for AZP claim
OnTokenValidated = context =>
@@ -195,31 +159,27 @@ public static IServiceCollection AddAuth(this IServiceCollection services, IConf
var azp = context.Principal?.FindFirstValue("azp");
// AuthorizedParty is the base URL of your frontend.
- if (string.IsNullOrEmpty(azp) || !azp.Equals(configuration["Auth:AuthorizedParty"]))
+ if (string.IsNullOrEmpty(azp) || !azp.Equals(configuration["Auth:AuthorizedParty"], StringComparison.Ordinal))
+ {
context.Fail("AZP Claim is invalid or missing");
+ }
return Task.CompletedTask;
}
};
});
- // State that represents the current user from the request
- services.AddCurrentUser();
+ services.AddScoped();
+ services.AddTransient();
services.AddAuthorizationBuilder()
- .AddPolicy(AppConstants.Policies.All, policy => policy.RequireClaim("id").RequireCurrentUser().Build());
+ .AddPolicy(AppConstants.Policies.All, policy => policy.RequireClaim("id").RequireAuthenticatedUser().Build());
// .AddPolicy(AppConstants.Policies.User, policy => policy.RequireRole(AppConstants.Roles.User).RequireCurrentUser().Build())
// .AddPolicy(AppConstants.Policies.Admin, policy => policy.RequireRole(AppConstants.Roles.Admin).RequireCurrentUser().Build())
- // add current user handler
- services.AddScoped();
-
return services;
}
- public static IServiceCollection AddCache(this IServiceCollection services)
- {
- return services;
- }
-}
+ public static IServiceCollection AddCache(this IServiceCollection services) => services;
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Filters/ValidationFilter.cs b/apps/api/src/Api/Common/Filters/ValidationFilter.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Filters/ValidationFilter.cs
rename to apps/api/src/Api/Common/Filters/ValidationFilter.cs
index c1e9029..c9e6ea0 100644
--- a/apps/api/Kijk.Api/Common/Filters/ValidationFilter.cs
+++ b/apps/api/src/Api/Common/Filters/ValidationFilter.cs
@@ -19,4 +19,4 @@ public class ValidationFilter(IValidator validator) : IEndpointFilter wher
return await next.Invoke(context);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Middleware/AuthResponseHandlerMiddleware.cs b/apps/api/src/Api/Common/Middleware/AuthResponseHandlerMiddleware.cs
new file mode 100644
index 0000000..3e8fcc1
--- /dev/null
+++ b/apps/api/src/Api/Common/Middleware/AuthResponseHandlerMiddleware.cs
@@ -0,0 +1,42 @@
+using System.Net;
+using System.Text.Json;
+
+using Kijk.Api.Common.Models;
+
+namespace Kijk.Api.Common.Middleware;
+
+public static class AuthResponseHandlerMiddleware
+{
+ public static IApplicationBuilder UseAuthExceptionHandler(this IApplicationBuilder app)
+ {
+ app.Use(async (context, next) =>
+ {
+ await next();
+
+ if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
+ {
+ context.Response.ContentType = "application/json";
+ var resp = ApiResponseBuilder.Error(AppError.Basic(AppErrorCodes.AuthenticationError, "Token is not valid"));
+ SentToSentry(resp);
+ await context.Response.WriteAsync(JsonSerializer.Serialize(resp));
+ }
+
+ if (context.Response.StatusCode == (int)HttpStatusCode.Forbidden)
+ {
+ context.Response.ContentType = "application/json";
+ var resp = ApiResponseBuilder.Error(AppError.Basic(AppErrorCodes.AuthorizationError, "Role is not sufficient"));
+ SentToSentry(resp);
+ await context.Response.WriteAsync(JsonSerializer.Serialize(resp));
+ }
+ });
+ return app;
+ }
+
+ private static void SentToSentry(ApiResponse> resp) => SentrySdk.CaptureMessage(
+ resp.Data?[0].Message ?? "AuthError: Token or role is not valid",
+ opt =>
+ {
+ opt.SetExtra("Response", resp);
+ opt.SetExtra("Code", resp.Data?[0].Code);
+ });
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Middleware/CurrentUserMiddleware.cs b/apps/api/src/Api/Common/Middleware/CurrentUserMiddleware.cs
new file mode 100644
index 0000000..763c36d
--- /dev/null
+++ b/apps/api/src/Api/Common/Middleware/CurrentUserMiddleware.cs
@@ -0,0 +1,92 @@
+using System.Security.Claims;
+using System.Text.Json;
+
+using Kijk.Api.Common.Models;
+using Kijk.Api.Persistence;
+
+namespace Kijk.Api.Common.Middleware;
+
+public class CurrentUserMiddleware(AppDbContext dbContext, CurrentUser currentUser) : IMiddleware
+{
+ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
+ {
+ var (isSuccess, errorMessage) = await SetCurrentUser(context);
+ if (isSuccess)
+ {
+ await next(context);
+ }
+ else
+ {
+ await HandleError(context, errorMessage);
+ }
+ }
+
+ private async Task<(bool, string?)> SetCurrentUser(HttpContext context)
+ {
+ if (context.Request.Path == "/" || context.Request.Path == "/api/swagger" ||
+ (context.Request.Path.HasValue && context.Request.Path.Value.StartsWith("/api/openapi", StringComparison.OrdinalIgnoreCase)))
+ {
+ return (true, null);
+ }
+
+ var extAuthId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
+ if (extAuthId == null)
+ {
+ return (false, $"User for id '{extAuthId}' was not found");
+ }
+
+ var email = context.User.FindFirstValue(ClaimTypes.Email);
+ var userEntity = await GetUserFromDb(extAuthId);
+ currentUser.Principal = context.User;
+
+ if (context.Request.Path.ToString().Contains("sign-in") && userEntity is null)
+ {
+ // TODO use more values from token
+ currentUser.User = new SimpleAuthUser(
+ Guid.NewGuid(),
+ extAuthId,
+ Guid.Empty,
+ AppConstants.CreateUserIdentifier,
+ email,
+ true);
+ return (true, null);
+ }
+
+ if (userEntity is null)
+ {
+ return (false, $"User for id '{extAuthId}' was not found");
+ }
+
+ if (userEntity.HouseholdId == Guid.Empty)
+ {
+ return (false, "User has no household");
+ }
+
+ currentUser.User = userEntity;
+ return (true, null);
+ }
+
+ private Task GetUserFromDb(string sub) => dbContext.Users
+ .Include(x => x.UserHouseholds)
+ .Where(x => x.AuthId == sub)
+ .Select(x => SimpleAuthUser.Create(x))
+ .AsNoTracking()
+ .AsSplitQuery()
+ .FirstOrDefaultAsync();
+
+ private static async Task HandleError(HttpContext context, string? errorMessage)
+ {
+ context.Response.ContentType = "application/json";
+ var resp = ApiResponseBuilder.Error(AppError.Basic(AppErrorCodes.NotFoundError, errorMessage));
+ SentToSentry(resp);
+ await context.Response.WriteAsync(JsonSerializer.Serialize(resp));
+ }
+
+ private static void SentToSentry(ApiResponse> resp) => SentrySdk.CaptureMessage(
+ resp.Data?[0].Message ?? "AuthError: Token or role is not valid",
+ opt =>
+ {
+ opt.SetExtra("Response", resp);
+ opt.SetExtra("Code", resp.Data?[0].Code);
+ });
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Middleware/ExceptionHandlerMiddleware.cs b/apps/api/src/Api/Common/Middleware/ExceptionHandlerMiddleware.cs
new file mode 100644
index 0000000..5809172
--- /dev/null
+++ b/apps/api/src/Api/Common/Middleware/ExceptionHandlerMiddleware.cs
@@ -0,0 +1,37 @@
+using System.Net;
+using System.Text.Json;
+
+using Kijk.Api.Common.Models;
+
+using Microsoft.AspNetCore.Diagnostics;
+
+namespace Kijk.Api.Common.Middleware;
+
+public static class ExceptionHandlerMiddleware
+{
+ public static IApplicationBuilder UseGlobalExceptionHandler(this IApplicationBuilder app)
+ {
+ app.UseExceptionHandler(
+ appError => appError.Run(
+ async context =>
+ {
+ context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
+ context.Response.ContentType = "application/json";
+
+ var exceptionHandlerFeature = context.Features.Get();
+ if (exceptionHandlerFeature is not null)
+ {
+ Log.ForContext(typeof(ExceptionHandlerMiddleware)).Error(
+ "Something went wrong: {ContextFeatureError}",
+ exceptionHandlerFeature.Error.Message);
+
+ var error = AppError.Unexpected(
+ AppErrorCodes.UnexpectedError,
+ $"Ups, etwas ist schief gelaufen. {exceptionHandlerFeature.Error.Message}");
+ var json = JsonSerializer.Serialize(ApiResponse.Error(error));
+ await context.Response.WriteAsync(json);
+ }
+ }));
+ return app;
+ }
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs b/apps/api/src/Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs
similarity index 86%
rename from apps/api/Kijk.Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs
rename to apps/api/src/Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs
index b396226..4004038 100644
--- a/apps/api/Kijk.Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs
+++ b/apps/api/src/Api/Common/Middleware/ExtendRequestLoggingMiddleware.cs
@@ -1,6 +1,4 @@
-using Microsoft.Extensions.Primitives;
-
-using Serilog.Context;
+using Serilog.Context;
namespace Kijk.Api.Common.Middleware;
@@ -19,7 +17,7 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
private static string GetCorrelationId(HttpContext context)
{
- context.Request.Headers.TryGetValue(CorrelationIdHeaderName, out StringValues correlationId);
+ context.Request.Headers.TryGetValue(CorrelationIdHeaderName, out var correlationId);
return correlationId.FirstOrDefault() ?? context.TraceIdentifier;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Models/ApiResponse.cs b/apps/api/src/Api/Common/Models/ApiResponse.cs
new file mode 100644
index 0000000..2347666
--- /dev/null
+++ b/apps/api/src/Api/Common/Models/ApiResponse.cs
@@ -0,0 +1,28 @@
+namespace Kijk.Api.Common.Models;
+
+public record ApiResponse
+{
+ public T? Data { get; init; }
+
+ public ResponseStatus Status { get; set; }
+
+ public string? Message { get; set; }
+
+ public static implicit operator ApiResponse(T data) => Success(data);
+
+ public static ApiResponse Success(T data, string? message = default) =>
+ new() { Status = ResponseStatus.Success, Data = data, Message = message };
+
+ public static ApiResponse> Error(string errorMessage) =>
+ new() { Status = ResponseStatus.Error, Message = errorMessage, Data = [] };
+
+ public static ApiResponse> Error(List error, string? errorMessage = default) =>
+ new() { Status = ResponseStatus.Error, Message = errorMessage, Data = error };
+
+ public static ApiResponse> Error(AppError appError, string? errorMessage = default) => new()
+ {
+ Status = ResponseStatus.Error,
+ Message = errorMessage,
+ Data = [appError]
+ };
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/ApiResponseBuilder.cs b/apps/api/src/Api/Common/Models/ApiResponseBuilder.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Models/ApiResponseBuilder.cs
rename to apps/api/src/Api/Common/Models/ApiResponseBuilder.cs
index f8875a2..ca313e1 100644
--- a/apps/api/Kijk.Api/Common/Models/ApiResponseBuilder.cs
+++ b/apps/api/src/Api/Common/Models/ApiResponseBuilder.cs
@@ -12,4 +12,4 @@ public static ApiResponse Success(T data, string? message = default) =>
public static ApiResponse> Error(AppError error) => ApiResponse>.Error(error);
public static ApiResponse> Error(List errors) => ApiResponse>.Error(errors);
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/AppConstants.cs b/apps/api/src/Api/Common/Models/AppConstants.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Models/AppConstants.cs
rename to apps/api/src/Api/Common/Models/AppConstants.cs
index 017225d..935b252 100644
--- a/apps/api/Kijk.Api/Common/Models/AppConstants.cs
+++ b/apps/api/src/Api/Common/Models/AppConstants.cs
@@ -45,4 +45,4 @@ public static class DefaultValues
public const string CategoryName = "Uncategorized";
public const string AccountName = "Main";
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/AppError.cs b/apps/api/src/Api/Common/Models/AppError.cs
similarity index 83%
rename from apps/api/Kijk.Api/Common/Models/AppError.cs
rename to apps/api/src/Api/Common/Models/AppError.cs
index e050476..b9d5434 100644
--- a/apps/api/Kijk.Api/Common/Models/AppError.cs
+++ b/apps/api/src/Api/Common/Models/AppError.cs
@@ -34,10 +34,7 @@ private AppError(string code, string message, ErrorType type)
/// The error description.
public static AppError Basic(
string code = AppErrorCodes.DefaultError,
- string description = "An error has occurred.")
- {
- return new AppError(code, $"Error, {description}", ErrorType.Basic);
- }
+ string? description = "An error has occurred.") => new(code, $"Error, {description}", ErrorType.Basic);
///
/// Creates an of type from a code and description.
@@ -46,10 +43,7 @@ public static AppError Basic(
/// The error description.
public static AppError Unexpected(
string code = AppErrorCodes.UnexpectedError,
- string description = "An unexpected error has occurred.")
- {
- return new AppError(code, $"An 'unexpected' error, {description}", ErrorType.Unexpected);
- }
+ string description = "An unexpected error has occurred.") => new(code, $"An 'unexpected' error, {description}", ErrorType.Unexpected);
///
/// Creates an of type from a code and description.
@@ -58,10 +52,7 @@ public static AppError Unexpected(
/// The error description.
public static AppError Validation(
string code = AppErrorCodes.ValidationError,
- string description = "A 'validation' error has occurred.")
- {
- return new AppError(code, description, ErrorType.Validation);
- }
+ string description = "A 'validation' error has occurred.") => new(code, description, ErrorType.Validation);
///
/// Creates an of type from a code and description.
@@ -70,10 +61,7 @@ public static AppError Validation(
/// The error description.
public static AppError NotFound(
string code = AppErrorCodes.NotFoundError,
- string description = "A 'Not Found' error has occurred.")
- {
- return new AppError(code, $"'Not found' error, {description}", ErrorType.NotFound);
- }
+ string description = "A 'Not Found' error has occurred.") => new(code, $"'Not found' error, {description}", ErrorType.NotFound);
///
/// Creates an with the given numeric ,
@@ -85,8 +73,5 @@ public static AppError NotFound(
public static AppError Custom(
ErrorType type,
string code,
- string description)
- {
- return new AppError(code, description, type);
- }
-}
+ string description) => new(code, description, type);
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/AppErrorCodes.cs b/apps/api/src/Api/Common/Models/AppErrorCodes.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Models/AppErrorCodes.cs
rename to apps/api/src/Api/Common/Models/AppErrorCodes.cs
index 63555ae..afcd727 100644
--- a/apps/api/Kijk.Api/Common/Models/AppErrorCodes.cs
+++ b/apps/api/src/Api/Common/Models/AppErrorCodes.cs
@@ -23,4 +23,4 @@ public readonly record struct AppErrorCodes
public const string AuthenticationError = "E0005";
public const string AuthorizationError = "E0006";
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/AppResult.cs b/apps/api/src/Api/Common/Models/AppResult.cs
similarity index 63%
rename from apps/api/Kijk.Api/Common/Models/AppResult.cs
rename to apps/api/src/Api/Common/Models/AppResult.cs
index 364a080..5363b83 100644
--- a/apps/api/Kijk.Api/Common/Models/AppResult.cs
+++ b/apps/api/src/Api/Common/Models/AppResult.cs
@@ -1,9 +1,11 @@
-using Kijk.Api.Common.Utils;
+using System.Diagnostics.CodeAnalysis;
+
+using Kijk.Api.Common.Utils;
namespace Kijk.Api.Common.Models;
///
-/// A discriminated union of value or a, error.
+/// A discriminated union of value or a, error.
///
public readonly record struct AppResult
{
@@ -12,7 +14,6 @@ public readonly record struct AppResult
"First error cannot be retrieved from a successful Result.");
private readonly List? _errors = null;
- private readonly TValue? _value = default;
///
/// Gets a value indicating whether the state is success.
@@ -27,17 +28,18 @@ public readonly record struct AppResult
///
/// Gets the list of errors. If the state is not error, the list will be empty.
///
- public List Errors => IsError ? _errors! : new List();
+ public List Errors => IsError ? _errors! : [];
///
- /// Gets the value.
+ /// Gets the value.
///
- public TValue Value => _value!;
+ [field: AllowNull, MaybeNull]
+ public TValue Value { get; } = default!;
///
/// Gets the first error.
///
- public AppError FirstAppError => !IsError ? NoFirstAppError : _errors!.First();
+ public AppError FirstAppError => !IsError ? NoFirstAppError : _errors![0];
private AppResult(List errors)
{
@@ -47,7 +49,7 @@ private AppResult(List errors)
private AppResult(TValue value)
{
- _value = value;
+ Value = value;
IsSuccess = true;
}
@@ -66,38 +68,36 @@ private AppResult(TValue value)
///
/// Creates an from an error.
///
- public static implicit operator AppResult(AppError appError) => new(new List { appError });
+ public static implicit operator AppResult(AppError appError)
+ {
+ return new([appError]);
+ }
///
/// Creates an from a list of errors.
///
- public static implicit operator AppResult(List errors) => new(errors);
-
- public TResult Match(Func onValue, Func, TResult> onError)
+ public static implicit operator AppResult(List errors)
{
- return IsError ? onError(Errors) : onValue(Value);
+ return new(errors);
}
- public async Task MatchAsync(Func> onValue, Func, Task> onError)
- {
- return IsError ? await onError(Errors) : await onValue(Value);
- }
-
- public IResult ToResponse(string? successMessage = default, SuccessType successType = SuccessType.Ok)
- {
- return this.Match(
- obj =>
- {
- var response = ApiResponse.Success(obj, successMessage);
- var statusCode = ResponseUtils.ToStatusCode(successType);
- return ResponseUtils.CreateTypedResult(response, statusCode);
- },
- errors =>
- {
- var firstError = errors.First();
- var response = ApiResponse.Error(errors);
- var statusCode = ResponseUtils.ToStatusCode(firstError.Type);
- return ResponseUtils.CreateTypedResult(response, statusCode);
- });
- }
-}
+ public TResult Match(Func onValue, Func, TResult> onError) => IsError ? onError(Errors) : onValue(Value);
+
+ public async Task MatchAsync(Func> onValue, Func, Task> onError) =>
+ IsError ? await onError(Errors) : await onValue(Value);
+
+ public IResult ToResponse(string? successMessage = default, SuccessType successType = SuccessType.Ok) => this.Match(
+ obj =>
+ {
+ var response = ApiResponse.Success(obj, successMessage);
+ var statusCode = ResponseUtils.ToStatusCode(successType);
+ return ResponseUtils.CreateTypedResult(response, statusCode);
+ },
+ errors =>
+ {
+ var firstError = errors[0];
+ var response = ApiResponse.Error(errors);
+ var statusCode = ResponseUtils.ToStatusCode(firstError.Type);
+ return ResponseUtils.CreateTypedResult(response, statusCode);
+ });
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Common/Models/CurrentUser.cs b/apps/api/src/Api/Common/Models/CurrentUser.cs
new file mode 100644
index 0000000..310cfd4
--- /dev/null
+++ b/apps/api/src/Api/Common/Models/CurrentUser.cs
@@ -0,0 +1,30 @@
+using System.Security.Claims;
+
+using Kijk.Api.Common.Exceptions;
+
+namespace Kijk.Api.Common.Models;
+
+public class CurrentUser
+{
+ private const string PermissionsClaim = "permissions";
+
+ public required ClaimsPrincipal Principal { get; set; }
+
+ public required SimpleAuthUser User { get; set; }
+
+ public Guid Id => this.User.Id;
+
+ public string AuthId => this.User.AuthId ?? throw new NullException("'AuthId' not found");
+
+ public string Name => this.User.Name ?? throw new NullException("'Name' not found");
+
+ public string Email => this.User.Email ?? throw new NullException("'Upn/Email' not found");
+
+ public IEnumerable Permissions => Principal.FindAll(PermissionsClaim).Select(x => x.Value);
+
+ public bool IsAdmin => this.Permissions.Contains(AppConstants.Roles.Admin);
+
+ public bool IsUser => this.Permissions.Contains(AppConstants.Roles.Admin);
+
+ public Guid ActiveHouseholdId => this.User.HouseholdId;
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/Dtos.cs b/apps/api/src/Api/Common/Models/Dtos.cs
similarity index 75%
rename from apps/api/Kijk.Api/Common/Models/Dtos.cs
rename to apps/api/src/Api/Common/Models/Dtos.cs
index a9e3850..6e7d450 100644
--- a/apps/api/Kijk.Api/Common/Models/Dtos.cs
+++ b/apps/api/src/Api/Common/Models/Dtos.cs
@@ -47,8 +47,16 @@ public static CategoryDto Create(Category category) =>
new(category.Id, category.Name, category.Color, category.Type, category.CreatorType);
}
-public record SimpleAuthUser(Guid Id, string AuthId, string Name, string? Email, bool? FirstTime = false)
+public record SimpleAuthUser(Guid Id, string AuthId, Guid HouseholdId, string Name, string? Email, bool? FirstTime = false)
{
public static SimpleAuthUser Create(User user) =>
- new(user.Id, user.AuthId, user.Name, user.Email, user.FirstTime);
+ new(user.Id, user.AuthId, user.GetActiveHouseHoldId(), user.Name, user.Email, user.FirstTime);
}
+
+public record EnergyConsumptionDto(Guid Id, string Name, string? Description, decimal Value, EnergyConsumptionType Type, DateTime CreatedAt)
+{
+ public static EnergyConsumptionDto Create(EnergyConsumption energyConsumption) =>
+ new(
+ energyConsumption.Id, energyConsumption.Name, energyConsumption.Description, energyConsumption.Value, energyConsumption.Type,
+ energyConsumption.CreatedAt);
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/Enums.cs b/apps/api/src/Api/Common/Models/Enums.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Models/Enums.cs
rename to apps/api/src/Api/Common/Models/Enums.cs
index d5aab36..e136453 100644
--- a/apps/api/Kijk.Api/Common/Models/Enums.cs
+++ b/apps/api/src/Api/Common/Models/Enums.cs
@@ -84,4 +84,4 @@ public enum BudgetStatus
Active,
Completed,
Pending
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/ResponseStatus.cs b/apps/api/src/Api/Common/Models/ResponseStatus.cs
similarity index 98%
rename from apps/api/Kijk.Api/Common/Models/ResponseStatus.cs
rename to apps/api/src/Api/Common/Models/ResponseStatus.cs
index 15ee505..93f8a92 100644
--- a/apps/api/Kijk.Api/Common/Models/ResponseStatus.cs
+++ b/apps/api/src/Api/Common/Models/ResponseStatus.cs
@@ -7,4 +7,4 @@ public enum ResponseStatus
{
Success,
Error
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Models/ResultTypes.cs b/apps/api/src/Api/Common/Models/ResultTypes.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Models/ResultTypes.cs
rename to apps/api/src/Api/Common/Models/ResultTypes.cs
index 8e1eca7..1a18f06 100644
--- a/apps/api/Kijk.Api/Common/Models/ResultTypes.cs
+++ b/apps/api/src/Api/Common/Models/ResultTypes.cs
@@ -28,4 +28,4 @@ public enum SuccessType
{
Ok,
Created
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Options/AuthOptions.cs b/apps/api/src/Api/Common/Options/AuthOptions.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Options/AuthOptions.cs
rename to apps/api/src/Api/Common/Options/AuthOptions.cs
index adc5764..8e9d32d 100644
--- a/apps/api/Kijk.Api/Common/Options/AuthOptions.cs
+++ b/apps/api/src/Api/Common/Options/AuthOptions.cs
@@ -10,4 +10,4 @@ public class AuthOptions : IConfigOptions
public string Authority { get; set; } = default!;
public string AuthorizedParty { get; set; } = default!;
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Options/ConnectionOptions.cs b/apps/api/src/Api/Common/Options/ConnectionOptions.cs
similarity index 99%
rename from apps/api/Kijk.Api/Common/Options/ConnectionOptions.cs
rename to apps/api/src/Api/Common/Options/ConnectionOptions.cs
index 95c3157..e2fcd7b 100644
--- a/apps/api/Kijk.Api/Common/Options/ConnectionOptions.cs
+++ b/apps/api/src/Api/Common/Options/ConnectionOptions.cs
@@ -6,4 +6,4 @@
public class ConnectionOptions : IConfigOptions
{
public static string SectionName => "DefaultConnection";
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Options/IConfigOption.cs b/apps/api/src/Api/Common/Options/IConfigOption.cs
similarity index 98%
rename from apps/api/Kijk.Api/Common/Options/IConfigOption.cs
rename to apps/api/src/Api/Common/Options/IConfigOption.cs
index 5372503..9196990 100644
--- a/apps/api/Kijk.Api/Common/Options/IConfigOption.cs
+++ b/apps/api/src/Api/Common/Options/IConfigOption.cs
@@ -6,4 +6,4 @@
public interface IConfigOptions
{
static abstract string SectionName { get; }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Utils/LoggerUtils.cs b/apps/api/src/Api/Common/Utils/LoggerUtils.cs
similarity index 76%
rename from apps/api/Kijk.Api/Common/Utils/LoggerUtils.cs
rename to apps/api/src/Api/Common/Utils/LoggerUtils.cs
index 6bf2c49..0d12923 100644
--- a/apps/api/Kijk.Api/Common/Utils/LoggerUtils.cs
+++ b/apps/api/src/Api/Common/Utils/LoggerUtils.cs
@@ -5,12 +5,9 @@ namespace Kijk.Api.Common.Utils;
public static class LoggerUtils
{
- public static ReloadableLogger CreateRootLogger()
- {
- return new LoggerConfiguration()
+ public static ReloadableLogger CreateRootLogger() => new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console(theme: AnsiConsoleTheme.Code)
.CreateBootstrapLogger();
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Common/Utils/ResponseUtils.cs b/apps/api/src/Api/Common/Utils/ResponseUtils.cs
similarity index 85%
rename from apps/api/Kijk.Api/Common/Utils/ResponseUtils.cs
rename to apps/api/src/Api/Common/Utils/ResponseUtils.cs
index 7cf2472..3396b68 100644
--- a/apps/api/Kijk.Api/Common/Utils/ResponseUtils.cs
+++ b/apps/api/src/Api/Common/Utils/ResponseUtils.cs
@@ -26,8 +26,5 @@ public static int ToStatusCode(ErrorType errorType)
return statusCode;
}
- public static IResult CreateTypedResult(ApiResponse response, int statusCode)
- {
- return TypedResults.Json(response, contentType: "application/json", statusCode: statusCode);
- }
-}
+ public static IResult CreateTypedResult(ApiResponse response, int statusCode) => TypedResults.Json(response, contentType: "application/json", statusCode: statusCode);
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Dockerfile b/apps/api/src/Api/Dockerfile
new file mode 100644
index 0000000..9bbb7d9
--- /dev/null
+++ b/apps/api/src/Api/Dockerfile
@@ -0,0 +1,23 @@
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
+USER $APP_UID
+WORKDIR /app
+EXPOSE 8080
+EXPOSE 8081
+
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["Api/Api.csproj", "Api/"]
+RUN dotnet restore "Api/Api.csproj"
+COPY . .
+WORKDIR "/src/Kijk.Api"
+RUN dotnet build "Api.csproj" -c "$BUILD_CONFIGURATION" -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "Api.csproj" -c "$BUILD_CONFIGURATION" -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Api.dll"]
diff --git a/apps/api/Kijk.Api/Domain/BaseEntity.cs b/apps/api/src/Api/Domain/BaseEntity.cs
similarity index 99%
rename from apps/api/Kijk.Api/Domain/BaseEntity.cs
rename to apps/api/src/Api/Domain/BaseEntity.cs
index d639b96..6fe76f5 100644
--- a/apps/api/Kijk.Api/Domain/BaseEntity.cs
+++ b/apps/api/src/Api/Domain/BaseEntity.cs
@@ -9,4 +9,4 @@ public abstract class BaseEntity
public DateTime? UpdatedAt { get; set; }
public DateTime? DeletedAt { get; set; }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/Account.cs b/apps/api/src/Api/Domain/Entities/Account.cs
similarity index 99%
rename from apps/api/Kijk.Api/Domain/Entities/Account.cs
rename to apps/api/src/Api/Domain/Entities/Account.cs
index b77d921..09affad 100644
--- a/apps/api/Kijk.Api/Domain/Entities/Account.cs
+++ b/apps/api/src/Api/Domain/Entities/Account.cs
@@ -35,4 +35,4 @@ public static Account Create(string name, Guid userId, Guid householdId, Account
HouseholdId = householdId,
UserId = userId
};
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/Budget.cs b/apps/api/src/Api/Domain/Entities/Budget.cs
similarity index 94%
rename from apps/api/Kijk.Api/Domain/Entities/Budget.cs
rename to apps/api/src/Api/Domain/Entities/Budget.cs
index d81b06a..9a59385 100644
--- a/apps/api/Kijk.Api/Domain/Entities/Budget.cs
+++ b/apps/api/src/Api/Domain/Entities/Budget.cs
@@ -31,9 +31,7 @@ public static Budget Create(
Guid householdId,
Guid userId,
Category category,
- DateOnly? endDate = default)
- {
- return new()
+ DateOnly? endDate = default) => new()
{
Id = Guid.NewGuid(),
Name = name,
@@ -47,5 +45,4 @@ public static Budget Create(
UserId = userId,
Category = category
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/Category.cs b/apps/api/src/Api/Domain/Entities/Category.cs
similarity index 99%
rename from apps/api/Kijk.Api/Domain/Entities/Category.cs
rename to apps/api/src/Api/Domain/Entities/Category.cs
index d683d8b..5d656f8 100644
--- a/apps/api/Kijk.Api/Domain/Entities/Category.cs
+++ b/apps/api/src/Api/Domain/Entities/Category.cs
@@ -34,4 +34,4 @@ public static Category Create(
Type = type,
Users = user is null ? [] : [user]
};
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/EnergyConsumption.cs b/apps/api/src/Api/Domain/Entities/EnergyConsumption.cs
similarity index 75%
rename from apps/api/Kijk.Api/Domain/Entities/EnergyConsumption.cs
rename to apps/api/src/Api/Domain/Entities/EnergyConsumption.cs
index 7aebd42..56dce70 100644
--- a/apps/api/Kijk.Api/Domain/Entities/EnergyConsumption.cs
+++ b/apps/api/src/Api/Domain/Entities/EnergyConsumption.cs
@@ -9,6 +9,11 @@ public sealed class EnergyConsumption : BaseEntity
public required decimal Value { get; set; }
public required EnergyConsumptionType Type { get; set; }
+ ///
+ /// Represents the date of the energy consumption.
+ ///
+ public required DateTime Date { get; set; }
+
public Guid HouseholdId { get; set; }
public static EnergyConsumption Create(
@@ -16,16 +21,15 @@ public static EnergyConsumption Create(
EnergyConsumptionType type,
decimal value,
Guid householdId,
- string? description = default)
- {
- return new()
+ DateTime date,
+ string? description = default) => new()
{
Id = Guid.NewGuid(),
Name = name,
Description = description,
Type = type,
Value = value,
+ Date = date,
HouseholdId = householdId
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/EnergyConsumptionLimit.cs b/apps/api/src/Api/Domain/Entities/EnergyConsumptionLimit.cs
similarity index 94%
rename from apps/api/Kijk.Api/Domain/Entities/EnergyConsumptionLimit.cs
rename to apps/api/src/Api/Domain/Entities/EnergyConsumptionLimit.cs
index a4b048d..7059fa5 100644
--- a/apps/api/Kijk.Api/Domain/Entities/EnergyConsumptionLimit.cs
+++ b/apps/api/src/Api/Domain/Entities/EnergyConsumptionLimit.cs
@@ -26,9 +26,7 @@ public static EnergyConsumptionLimit Create(
DateTime lastOccurrence,
User createdBy,
Guid householdId,
- string? description = default)
- {
- return new()
+ string? description = default) => new()
{
Id = Guid.NewGuid(),
Name = name,
@@ -41,6 +39,5 @@ public static EnergyConsumptionLimit Create(
CreatedBy = createdBy,
HouseholdId = householdId
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/Household.cs b/apps/api/src/Api/Domain/Entities/Household.cs
similarity index 99%
rename from apps/api/Kijk.Api/Domain/Entities/Household.cs
rename to apps/api/src/Api/Domain/Entities/Household.cs
index 0ae06c1..4d185bf 100644
--- a/apps/api/Kijk.Api/Domain/Entities/Household.cs
+++ b/apps/api/src/Api/Domain/Entities/Household.cs
@@ -22,4 +22,4 @@ public static Household Create(string name, bool isActive, string? description =
Description = description,
IsActive = isActive
};
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/RecurringTransactions.cs b/apps/api/src/Api/Domain/Entities/RecurringTransactions.cs
similarity index 95%
rename from apps/api/Kijk.Api/Domain/Entities/RecurringTransactions.cs
rename to apps/api/src/Api/Domain/Entities/RecurringTransactions.cs
index 22a1ef1..0d06250 100644
--- a/apps/api/Kijk.Api/Domain/Entities/RecurringTransactions.cs
+++ b/apps/api/src/Api/Domain/Entities/RecurringTransactions.cs
@@ -42,9 +42,7 @@ public static RecurringTransactions Create(
Account account,
Guid householdId,
Frequency frequency,
- DateOnly? endDate = default)
- {
- return new()
+ DateOnly? endDate = default) => new()
{
Id = Guid.NewGuid(),
Name = name,
@@ -57,5 +55,4 @@ public static RecurringTransactions Create(
Frequency = frequency,
HouseholdId = householdId
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/Transaction.cs b/apps/api/src/Api/Domain/Entities/Transaction.cs
similarity index 94%
rename from apps/api/Kijk.Api/Domain/Entities/Transaction.cs
rename to apps/api/src/Api/Domain/Entities/Transaction.cs
index 530f9a6..7ef3364 100644
--- a/apps/api/Kijk.Api/Domain/Entities/Transaction.cs
+++ b/apps/api/src/Api/Domain/Entities/Transaction.cs
@@ -25,9 +25,7 @@ public static Transaction Create(
TransactionType type,
DateTime executedAt,
Account account,
- Category category)
- {
- return new()
+ Category category) => new()
{
Id = Guid.NewGuid(),
Name = name,
@@ -38,5 +36,4 @@ public static Transaction Create(
Account = account,
Category = category
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/User.cs b/apps/api/src/Api/Domain/Entities/User.cs
similarity index 79%
rename from apps/api/Kijk.Api/Domain/Entities/User.cs
rename to apps/api/src/Api/Domain/Entities/User.cs
index 688999b..d13ad51 100644
--- a/apps/api/Kijk.Api/Domain/Entities/User.cs
+++ b/apps/api/src/Api/Domain/Entities/User.cs
@@ -19,6 +19,12 @@ public sealed class User : BaseEntity
public List Categories { get; set; } = [];
+ ///
+ /// It should never be empty as it is set when the user is created.
+ ///
+ ///
+ public Guid GetActiveHouseHoldId() => UserHouseholds.Find(x => x.IsDefault)?.HouseholdId ?? Guid.Empty;
+
public User SetDefaultCategories(bool? useDefaultCategories, List defaultCategories)
{
if (useDefaultCategories == true)
@@ -38,16 +44,13 @@ public static User Create(
string name,
string? email,
List? categories = null,
- bool firstTime = false)
- {
- return new User
+ bool firstTime = false) => new()
{
Id = Guid.NewGuid(),
AuthId = authId,
Name = name,
Email = email,
FirstTime = firstTime,
- Categories = categories ?? [],
+ Categories = categories ?? []
};
- }
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Domain/Entities/UserHousehold.cs b/apps/api/src/Api/Domain/Entities/UserHousehold.cs
similarity index 99%
rename from apps/api/Kijk.Api/Domain/Entities/UserHousehold.cs
rename to apps/api/src/Api/Domain/Entities/UserHousehold.cs
index cd90332..7f87264 100644
--- a/apps/api/Kijk.Api/Domain/Entities/UserHousehold.cs
+++ b/apps/api/src/Api/Domain/Entities/UserHousehold.cs
@@ -25,4 +25,4 @@ public static UserHousehold Create(User user, Household household, Role role, bo
Role = role,
IsDefault = isDefault,
};
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Endpoints/CategoriesEndpoint.cs b/apps/api/src/Api/Endpoints/CategoriesEndpoint.cs
similarity index 99%
rename from apps/api/Kijk.Api/Endpoints/CategoriesEndpoint.cs
rename to apps/api/src/Api/Endpoints/CategoriesEndpoint.cs
index 5892d48..9fa6821 100644
--- a/apps/api/Kijk.Api/Endpoints/CategoriesEndpoint.cs
+++ b/apps/api/src/Api/Endpoints/CategoriesEndpoint.cs
@@ -22,4 +22,4 @@ public static IEndpointRouteBuilder MapCategoriesApi(this IEndpointRouteBuilder
return endpointRouteBuilder;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Endpoints/EnergyConsumptionsEndpoint.cs b/apps/api/src/Api/Endpoints/EnergyConsumptionsEndpoint.cs
new file mode 100644
index 0000000..2106543
--- /dev/null
+++ b/apps/api/src/Api/Endpoints/EnergyConsumptionsEndpoint.cs
@@ -0,0 +1,14 @@
+namespace Kijk.Api.Endpoints;
+
+public static class EnergyConsumptionsEndpoint
+{
+ public static IEndpointRouteBuilder MaEnergyConsumptionsEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
+ {
+ var group = endpointRouteBuilder.MapGroup("/energy-consumptions")
+ .WithTags("EnergyConsumptions");
+
+
+
+ return endpointRouteBuilder;
+ }
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Endpoints/TransactionsEndpoint.cs b/apps/api/src/Api/Endpoints/TransactionsEndpoint.cs
similarity index 99%
rename from apps/api/Kijk.Api/Endpoints/TransactionsEndpoint.cs
rename to apps/api/src/Api/Endpoints/TransactionsEndpoint.cs
index 7c9f61d..95c78e6 100644
--- a/apps/api/Kijk.Api/Endpoints/TransactionsEndpoint.cs
+++ b/apps/api/src/Api/Endpoints/TransactionsEndpoint.cs
@@ -18,4 +18,4 @@ public static IEndpointRouteBuilder MapTransactionsEndpoints(this IEndpointRoute
return endpointRouteBuilder;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Endpoints/UsersEndpoint.cs b/apps/api/src/Api/Endpoints/UsersEndpoint.cs
similarity index 99%
rename from apps/api/Kijk.Api/Endpoints/UsersEndpoint.cs
rename to apps/api/src/Api/Endpoints/UsersEndpoint.cs
index c2b545e..fd36228 100644
--- a/apps/api/Kijk.Api/Endpoints/UsersEndpoint.cs
+++ b/apps/api/src/Api/Endpoints/UsersEndpoint.cs
@@ -16,4 +16,4 @@ public static IEndpointRouteBuilder MapUsersApi(this IEndpointRouteBuilder endpo
return endpointRouteBuilder;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/GlobalUsings.cs b/apps/api/src/Api/GlobalUsings.cs
similarity index 81%
rename from apps/api/Kijk.Api/GlobalUsings.cs
rename to apps/api/src/Api/GlobalUsings.cs
index ad4cc3a..c666723 100644
--- a/apps/api/Kijk.Api/GlobalUsings.cs
+++ b/apps/api/src/Api/GlobalUsings.cs
@@ -6,4 +6,4 @@
global using Serilog;
global using Serilog.Events;
-global using ILogger = Serilog.ILogger;
+global using ILogger = Serilog.ILogger;
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/App/AppModule.cs b/apps/api/src/Api/Modules/App/AppModule.cs
similarity index 67%
rename from apps/api/Kijk.Api/Modules/App/AppModule.cs
rename to apps/api/src/Api/Modules/App/AppModule.cs
index 850ffa6..92ecd84 100644
--- a/apps/api/Kijk.Api/Modules/App/AppModule.cs
+++ b/apps/api/src/Api/Modules/App/AppModule.cs
@@ -2,8 +2,5 @@
public static class AppModule
{
- public static IServiceCollection RegisterAppModule(this IServiceCollection services)
- {
- return services;
- }
-}
+ public static IServiceCollection RegisterAppModule(this IServiceCollection services) => services;
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/CategoriesModule.cs b/apps/api/src/Api/Modules/Categories/CategoriesModule.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Categories/CategoriesModule.cs
rename to apps/api/src/Api/Modules/Categories/CategoriesModule.cs
index 0a2e913..0349e65 100644
--- a/apps/api/Kijk.Api/Modules/Categories/CategoriesModule.cs
+++ b/apps/api/src/Api/Modules/Categories/CategoriesModule.cs
@@ -8,4 +8,4 @@ public static IServiceCollection AddCategoriesModule(this IServiceCollection ser
return services;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/CreateCategory.Validator.cs b/apps/api/src/Api/Modules/Categories/CreateCategory.Validator.cs
similarity index 89%
rename from apps/api/Kijk.Api/Modules/Categories/CreateCategory.Validator.cs
rename to apps/api/src/Api/Modules/Categories/CreateCategory.Validator.cs
index 158dcb3..d319c59 100644
--- a/apps/api/Kijk.Api/Modules/Categories/CreateCategory.Validator.cs
+++ b/apps/api/src/Api/Modules/Categories/CreateCategory.Validator.cs
@@ -1,6 +1,6 @@
-// using Kijk.Api.Common.Models;
+// using Api.Common.Models;
//
-// namespace Kijk.Api.Modules.Categories;
+// namespace Api.Modules.Categories;
//
// public class CreateCategoryValidator : AbstractValidator
// {
@@ -14,4 +14,4 @@
// .NotEmpty().WithErrorCode(AppErrorCodes.ValidationError).WithMessage("'Color' must be set")
// .Must(x => x.StartsWith("#")).WithErrorCode(AppErrorCodes.ValidationError).WithMessage("'Color' must start with a '#'");
// }
-// }
+// }
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/CreateCategory.cs b/apps/api/src/Api/Modules/Categories/CreateCategory.cs
similarity index 95%
rename from apps/api/Kijk.Api/Modules/Categories/CreateCategory.cs
rename to apps/api/src/Api/Modules/Categories/CreateCategory.cs
index 443239a..f512d28 100644
--- a/apps/api/Kijk.Api/Modules/Categories/CreateCategory.cs
+++ b/apps/api/src/Api/Modules/Categories/CreateCategory.cs
@@ -1,5 +1,4 @@
-using Kijk.Api.Common.Extensions;
-using Kijk.Api.Common.Models;
+using Kijk.Api.Common.Models;
using Kijk.Api.Domain.Entities;
using Kijk.Api.Persistence;
@@ -17,7 +16,7 @@ public CreateCategoryValidator()
RuleFor(x => x.Color)
.NotEmpty().WithErrorCode(AppErrorCodes.ValidationError).WithMessage("'Color' must be set")
- .Must(x => x.StartsWith("#")).WithErrorCode(AppErrorCodes.ValidationError).WithMessage("'Color' must start with a '#'");
+ .Must(x => x.StartsWith('#')).WithErrorCode(AppErrorCodes.ValidationError).WithMessage("'Color' must start with a '#'");
}
}
@@ -78,7 +77,7 @@ private static async Task Handle(
return TypedResults.NotFound(ApiResponseBuilder.Error($"User with id '{currentUser.Id}' was not found"));
}
- if (user.Categories.Any(c => string.Equals(c.Name, createCategoryRequest.Name, StringComparison.CurrentCultureIgnoreCase)))
+ if (user.Categories.Any(c => string.Equals(c.Name, createCategoryRequest.Name, StringComparison.OrdinalIgnoreCase)))
{
return TypedResults.Conflict(ApiResponseBuilder.Error($"A category with the name '{createCategoryRequest.Name}' already exists"));
}
@@ -96,4 +95,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/DeleteCategory.cs b/apps/api/src/Api/Modules/Categories/DeleteCategory.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Categories/DeleteCategory.cs
rename to apps/api/src/Api/Modules/Categories/DeleteCategory.cs
index 85d39a2..60cc029 100644
--- a/apps/api/Kijk.Api/Modules/Categories/DeleteCategory.cs
+++ b/apps/api/src/Api/Modules/Categories/DeleteCategory.cs
@@ -74,4 +74,4 @@ private static async Task Handle(Guid id, AppDbContext dbContext, Curre
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/GetAllCategories.cs b/apps/api/src/Api/Modules/Categories/GetAllCategories.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Categories/GetAllCategories.cs
rename to apps/api/src/Api/Modules/Categories/GetAllCategories.cs
index 8035f33..7b4570d 100644
--- a/apps/api/Kijk.Api/Modules/Categories/GetAllCategories.cs
+++ b/apps/api/src/Api/Modules/Categories/GetAllCategories.cs
@@ -52,4 +52,4 @@ private static async Task Handle(AppDbContext dbContext, CurrentUser cu
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Categories/UpdateCategory.cs b/apps/api/src/Api/Modules/Categories/UpdateCategory.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Categories/UpdateCategory.cs
rename to apps/api/src/Api/Modules/Categories/UpdateCategory.cs
index 6bc6138..2b5a8d9 100644
--- a/apps/api/Kijk.Api/Modules/Categories/UpdateCategory.cs
+++ b/apps/api/src/Api/Modules/Categories/UpdateCategory.cs
@@ -75,4 +75,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Modules/EnergyConsumptions/EnergyConsumptionsModule.cs b/apps/api/src/Api/Modules/EnergyConsumptions/EnergyConsumptionsModule.cs
new file mode 100644
index 0000000..2313db6
--- /dev/null
+++ b/apps/api/src/Api/Modules/EnergyConsumptions/EnergyConsumptionsModule.cs
@@ -0,0 +1,9 @@
+namespace Kijk.Api.Modules.EnergyConsumptions;
+
+public static class EnergyConsumptionsModule
+{
+ public static IServiceCollection AddEnergyConsumptionsModule(this IServiceCollection services) =>
+ // services.AddScoped, CreateTransactionsValidator>();
+
+ services;
+}
\ No newline at end of file
diff --git a/apps/api/src/Api/Modules/EnergyConsumptions/GetByEnergyConsumptions.cs b/apps/api/src/Api/Modules/EnergyConsumptions/GetByEnergyConsumptions.cs
new file mode 100644
index 0000000..7b6c62a
--- /dev/null
+++ b/apps/api/src/Api/Modules/EnergyConsumptions/GetByEnergyConsumptions.cs
@@ -0,0 +1,72 @@
+using System.Globalization;
+
+using Kijk.Api.Common.Extensions;
+using Kijk.Api.Common.Models;
+using Kijk.Api.Persistence;
+
+using Microsoft.AspNetCore.Mvc;
+
+namespace Kijk.Api.Modules.EnergyConsumptions;
+
+public static class GetByEnergyConsumptions
+{
+ private static readonly ILogger Logger = Log.ForContext(typeof(GetByEnergyConsumptions));
+
+ public static RouteGroupBuilder MapGetByEnergyConsumptions(this RouteGroupBuilder groupBuilder)
+ {
+ groupBuilder.MapGet("/", HandleAsync)
+ .Produces>>()
+ .Produces>>(StatusCodes.Status400BadRequest)
+ .Produces>>(StatusCodes.Status404NotFound);
+
+ return groupBuilder;
+ }
+
+ ///
+ /// Retrieves all energy consumptions for the current user by year, month and type.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static async Task HandleAsync(
+ [FromQuery(Name = "year")] int? year,
+ [FromQuery(Name = "month")] string? month,
+ [FromQuery(Name = "type")] string? type,
+ AppDbContext dbContext,
+ CurrentUser currentUser,
+ CancellationToken cancellationToken)
+ {
+ try
+ {
+ var monthInt = month is not null ? DateTime.ParseExact(month, "MMMM", CultureInfo.InvariantCulture).Month : -1;
+
+ var typeExists = Enum.TryParse(type, true, out var realType);
+
+ var response = await dbContext.EnergyConsumptions
+ .AsNoTracking()
+ .Where(x => x.HouseholdId == currentUser.ActiveHouseholdId)
+ .If(year != null, q => q.Where(x => x.Date.Year == year))
+ .If(monthInt != -1, q => q.Where(x => x.Date.Month == monthInt))
+ .If(typeExists, q => q.Where(x => x.Type == realType))
+ .Select(
+ x => new EnergyConsumptionDto(
+ x.Id,
+ x.Name,
+ x.Description,
+ x.Value,
+ x.Type, x.CreatedAt))
+ .ToListAsync(cancellationToken);
+
+ return TypedResults.Ok(ApiResponseBuilder.Success(response));
+ }
+ catch (Exception e)
+ {
+ Logger.Warning(e, "Error: {Error}", e.Message);
+ return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/CreateTransaction.cs b/apps/api/src/Api/Modules/Transactions/CreateTransaction.cs
similarity index 97%
rename from apps/api/Kijk.Api/Modules/Transactions/CreateTransaction.cs
rename to apps/api/src/Api/Modules/Transactions/CreateTransaction.cs
index 3d65315..7c7a977 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/CreateTransaction.cs
+++ b/apps/api/src/Api/Modules/Transactions/CreateTransaction.cs
@@ -69,7 +69,7 @@ private static async Task Handle(
var accountId = createTransactionRequest.AccountId;
if (accountId == null || accountId == Guid.Empty)
{
- accountId = user.Accounts.FirstOrDefault(x => x.Name == AppConstants.DefaultValues.AccountName)?.Id;
+ accountId = user.Accounts.Find(x => x.Name == AppConstants.DefaultValues.AccountName)?.Id;
}
var account = await dbContext.Accounts
@@ -141,4 +141,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/DeleteTransaction.cs b/apps/api/src/Api/Modules/Transactions/DeleteTransaction.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Transactions/DeleteTransaction.cs
rename to apps/api/src/Api/Modules/Transactions/DeleteTransaction.cs
index 704a47b..3d849e1 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/DeleteTransaction.cs
+++ b/apps/api/src/Api/Modules/Transactions/DeleteTransaction.cs
@@ -50,4 +50,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/GetByIdTransaction.cs b/apps/api/src/Api/Modules/Transactions/GetByIdTransaction.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Transactions/GetByIdTransaction.cs
rename to apps/api/src/Api/Modules/Transactions/GetByIdTransaction.cs
index 054595a..ab920da 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/GetByIdTransaction.cs
+++ b/apps/api/src/Api/Modules/Transactions/GetByIdTransaction.cs
@@ -53,4 +53,4 @@ private static async Task Handle(Guid id, AppDbContext dbContext, Cance
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/GetByTransactions.cs b/apps/api/src/Api/Modules/Transactions/GetByTransactions.cs
similarity index 93%
rename from apps/api/Kijk.Api/Modules/Transactions/GetByTransactions.cs
rename to apps/api/src/Api/Modules/Transactions/GetByTransactions.cs
index 770be8a..a5ac820 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/GetByTransactions.cs
+++ b/apps/api/src/Api/Modules/Transactions/GetByTransactions.cs
@@ -1,7 +1,9 @@
using System.Globalization;
+
using Kijk.Api.Common.Extensions;
using Kijk.Api.Common.Models;
using Kijk.Api.Persistence;
+
using Microsoft.AspNetCore.Mvc;
namespace Kijk.Api.Modules.Transactions;
@@ -12,7 +14,7 @@ public static class GetByTransactions
public static RouteGroupBuilder MapGetByTransactions(this RouteGroupBuilder groupBuilder)
{
- groupBuilder.MapGet("/", Handle)
+ groupBuilder.MapGet("/", HandleAsync)
.Produces>>()
.Produces>>(StatusCodes.Status400BadRequest)
.Produces>>(StatusCodes.Status404NotFound);
@@ -21,7 +23,7 @@ public static RouteGroupBuilder MapGetByTransactions(this RouteGroupBuilder grou
}
///
- /// Retrieves all transactions for the current user by year and month.
+ /// Retrieves all transactions for the current user by year and month.
///
///
///
@@ -29,7 +31,7 @@ public static RouteGroupBuilder MapGetByTransactions(this RouteGroupBuilder grou
///
///
///
- private static async Task Handle(
+ private static async Task HandleAsync(
[FromQuery(Name = "year")] int? year,
[FromQuery(Name = "month")] string? month,
AppDbContext dbContext,
@@ -69,4 +71,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/GetYearsFromTransactions.cs b/apps/api/src/Api/Modules/Transactions/GetYearsFromTransactions.cs
similarity index 83%
rename from apps/api/Kijk.Api/Modules/Transactions/GetYearsFromTransactions.cs
rename to apps/api/src/Api/Modules/Transactions/GetYearsFromTransactions.cs
index a5d03ac..a3e1359 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/GetYearsFromTransactions.cs
+++ b/apps/api/src/Api/Modules/Transactions/GetYearsFromTransactions.cs
@@ -3,7 +3,7 @@
namespace Kijk.Api.Modules.Transactions;
-file record YearDto(List Years);
+sealed file record YearsResponse(List Years);
public static class GetYearsFromTransactions
{
@@ -22,16 +22,11 @@ public static RouteGroupBuilder MapGetYearsFromTransactions(this RouteGroupBuild
///
/// Retrieves all years that have transactions and all years in between.
///
- ///
///
///
///
///
- private static async Task Handle(
- HttpRequest request,
- AppDbContext dbContext,
- CurrentUser currentUser,
- CancellationToken cancellationToken)
+ private static async Task Handle(AppDbContext dbContext, CurrentUser currentUser, CancellationToken cancellationToken)
{
try
{
@@ -52,12 +47,12 @@ private static async Task Handle(
List years = [];
var currentYear = DateTime.UtcNow.Year;
var minDate = yearsWithTransactions.Count > 0 ? yearsWithTransactions.Min() : currentYear;
- for (int i = minDate; i <= currentYear; i++)
+ for (var i = minDate; i <= currentYear; i++)
{
years.Add(i);
}
- var response = new YearDto(years.OrderByDescending(x => x).ToList());
+ var response = new YearsResponse([.. years.OrderByDescending(x => x)]);
return TypedResults.Ok(ApiResponseBuilder.Success(response));
}
catch (Exception e)
@@ -66,4 +61,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/TransactionsModule.cs b/apps/api/src/Api/Modules/Transactions/TransactionsModule.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Transactions/TransactionsModule.cs
rename to apps/api/src/Api/Modules/Transactions/TransactionsModule.cs
index 2416d96..9df9cf3 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/TransactionsModule.cs
+++ b/apps/api/src/Api/Modules/Transactions/TransactionsModule.cs
@@ -8,4 +8,4 @@ public static IServiceCollection AddTransactionsModule(this IServiceCollection s
return services;
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Transactions/UpdateTransaction.cs b/apps/api/src/Api/Modules/Transactions/UpdateTransaction.cs
similarity index 99%
rename from apps/api/Kijk.Api/Modules/Transactions/UpdateTransaction.cs
rename to apps/api/src/Api/Modules/Transactions/UpdateTransaction.cs
index bf5ec4d..d8f704e 100644
--- a/apps/api/Kijk.Api/Modules/Transactions/UpdateTransaction.cs
+++ b/apps/api/src/Api/Modules/Transactions/UpdateTransaction.cs
@@ -86,4 +86,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Users/GetMeUser.cs b/apps/api/src/Api/Modules/Users/GetMeUser.cs
similarity index 98%
rename from apps/api/Kijk.Api/Modules/Users/GetMeUser.cs
rename to apps/api/src/Api/Modules/Users/GetMeUser.cs
index 433b053..735ccc6 100644
--- a/apps/api/Kijk.Api/Modules/Users/GetMeUser.cs
+++ b/apps/api/src/Api/Modules/Users/GetMeUser.cs
@@ -3,7 +3,7 @@
namespace Kijk.Api.Modules.Users;
-file record GetMeUserResponse(
+sealed file record GetMeUserResponse(
Guid Id,
string? AuthId,
string? Name,
@@ -69,4 +69,4 @@ private static async Task Handle(AppDbContext dbContext, CurrentUser cu
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Users/SignInUser.cs b/apps/api/src/Api/Modules/Users/SignInUser.cs
similarity index 98%
rename from apps/api/Kijk.Api/Modules/Users/SignInUser.cs
rename to apps/api/src/Api/Modules/Users/SignInUser.cs
index 03a4992..1edff45 100644
--- a/apps/api/Kijk.Api/Modules/Users/SignInUser.cs
+++ b/apps/api/src/Api/Modules/Users/SignInUser.cs
@@ -1,11 +1,12 @@
using System.Security.Cryptography;
+
using Kijk.Api.Common.Models;
using Kijk.Api.Domain.Entities;
using Kijk.Api.Persistence;
namespace Kijk.Api.Modules.Users;
-file record SignInUserResponse(
+sealed file record SignInUserResponse(
Guid Id,
string? AuthId,
string? Name,
@@ -96,4 +97,4 @@ private static async Task Handle(AppDbContext dbContext, CurrentUser cu
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Users/UpdateUser.cs b/apps/api/src/Api/Modules/Users/UpdateUser.cs
similarity index 98%
rename from apps/api/Kijk.Api/Modules/Users/UpdateUser.cs
rename to apps/api/src/Api/Modules/Users/UpdateUser.cs
index 58bfdf0..cdd4ff3 100644
--- a/apps/api/Kijk.Api/Modules/Users/UpdateUser.cs
+++ b/apps/api/src/Api/Modules/Users/UpdateUser.cs
@@ -5,7 +5,7 @@ namespace Kijk.Api.Modules.Users;
public record UpdateUserRequest(string? UserName, bool? UseDefaultCategories);
-file record UserUpdateResponse(
+sealed file record UserUpdateResponse(
Guid Id,
string? AuthId,
string? Name,
@@ -82,4 +82,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Users/UsersModule.cs b/apps/api/src/Api/Modules/Users/UsersModule.cs
similarity index 69%
rename from apps/api/Kijk.Api/Modules/Users/UsersModule.cs
rename to apps/api/src/Api/Modules/Users/UsersModule.cs
index 79b8e62..b8d5310 100644
--- a/apps/api/Kijk.Api/Modules/Users/UsersModule.cs
+++ b/apps/api/src/Api/Modules/Users/UsersModule.cs
@@ -2,8 +2,5 @@
public static class UsersModule
{
- public static IServiceCollection AddUsersModule(this IServiceCollection services)
- {
- return services;
- }
-}
+ public static IServiceCollection AddUsersModule(this IServiceCollection services) => services;
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Modules/Users/WelcomeUser.cs b/apps/api/src/Api/Modules/Users/WelcomeUser.cs
similarity index 98%
rename from apps/api/Kijk.Api/Modules/Users/WelcomeUser.cs
rename to apps/api/src/Api/Modules/Users/WelcomeUser.cs
index ded8c6d..1e4326f 100644
--- a/apps/api/Kijk.Api/Modules/Users/WelcomeUser.cs
+++ b/apps/api/src/Api/Modules/Users/WelcomeUser.cs
@@ -5,7 +5,7 @@ namespace Kijk.Api.Modules.Users;
public record WelcomeUserRequest(string? UserName, bool? UseDefaultCategories);
-file record WelcomeUserResponse(
+sealed file record WelcomeUserResponse(
Guid Id,
string? AuthId,
string? Name,
@@ -85,4 +85,4 @@ private static async Task Handle(
return TypedResults.BadRequest(ApiResponseBuilder.Error(e.Message));
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/AppDbContext.cs b/apps/api/src/Api/Persistence/AppDbContext.cs
similarity index 63%
rename from apps/api/Kijk.Api/Persistence/AppDbContext.cs
rename to apps/api/src/Api/Persistence/AppDbContext.cs
index 2236a85..4f9d7da 100644
--- a/apps/api/Kijk.Api/Persistence/AppDbContext.cs
+++ b/apps/api/src/Api/Persistence/AppDbContext.cs
@@ -1,11 +1,8 @@
-using EntityFramework.Exceptions.PostgreSQL;
-using Kijk.Api.Common.Options;
-using Kijk.Api.Domain.Entities;
-using Microsoft.EntityFrameworkCore.Diagnostics;
+using Kijk.Api.Domain.Entities;
namespace Kijk.Api.Persistence;
-public class AppDbContext(IConfiguration configuration, IServiceProvider serviceProvider) : DbContext
+public class AppDbContext(DbContextOptions options) : DbContext(options)
{
public DbSet Households => Set();
public DbSet UserHouseholds => Set();
@@ -24,20 +21,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
}
- protected override void OnConfiguring(DbContextOptionsBuilder options)
- {
- options.UseNpgsql(configuration.GetConnectionString(ConnectionOptions.SectionName))
- .UseExceptionProcessor()
- .UseSnakeCaseNamingConvention()
- .AddInterceptors(serviceProvider.GetServices());
- }
-
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties()
- .HaveConversion(typeof(UtcDateTimeConverter));
+ .HaveConversion();
base.ConfigureConventions(configurationBuilder);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/AppDbInitializer.cs b/apps/api/src/Api/Persistence/AppDbInitializer.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/AppDbInitializer.cs
rename to apps/api/src/Api/Persistence/AppDbInitializer.cs
index 431e844..49440df 100644
--- a/apps/api/Kijk.Api/Persistence/AppDbInitializer.cs
+++ b/apps/api/src/Api/Persistence/AppDbInitializer.cs
@@ -53,4 +53,4 @@ public static void InitDb(AppDbContext dbContext)
throw;
}
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/AccountConfig.cs b/apps/api/src/Api/Persistence/Configs/AccountConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/AccountConfig.cs
rename to apps/api/src/Api/Persistence/Configs/AccountConfig.cs
index 7b4f3e7..274a44a 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/AccountConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/AccountConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -24,4 +25,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.AccountId)
.OnDelete(DeleteBehavior.Cascade);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/BudgetConfig.cs b/apps/api/src/Api/Persistence/Configs/BudgetConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/BudgetConfig.cs
rename to apps/api/src/Api/Persistence/Configs/BudgetConfig.cs
index eb1fe0f..59a06cf 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/BudgetConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/BudgetConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -16,4 +17,4 @@ public void Configure(EntityTypeBuilder builder)
builder.Property(x => x.Visibility).HasConversion();
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/CategoryConfig.cs b/apps/api/src/Api/Persistence/Configs/CategoryConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/CategoryConfig.cs
rename to apps/api/src/Api/Persistence/Configs/CategoryConfig.cs
index bda1dc4..37d97f6 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/CategoryConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/CategoryConfig.cs
@@ -17,6 +17,5 @@ public void Configure(EntityTypeBuilder builder)
builder.Property(x => x.Color).HasDefaultValue(AppConstants.Colors.Default);
builder.Property(x => x.Type).HasConversion();
builder.Property(x => x.CreatorType).HasConversion();
-
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionConfig.cs b/apps/api/src/Api/Persistence/Configs/EnergyConsumptionConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionConfig.cs
rename to apps/api/src/Api/Persistence/Configs/EnergyConsumptionConfig.cs
index 086db03..a67c1a4 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/EnergyConsumptionConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -15,4 +16,4 @@ public void Configure(EntityTypeBuilder builder)
builder.Property(x => x.Type).HasConversion();
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs b/apps/api/src/Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs
rename to apps/api/src/Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs
index 2bb1ea8..430311d 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/EnergyConsumptionLimitConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -19,4 +20,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.CreatedById)
.OnDelete(DeleteBehavior.Restrict);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/HouseholdConfig.cs b/apps/api/src/Api/Persistence/Configs/HouseholdConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/HouseholdConfig.cs
rename to apps/api/src/Api/Persistence/Configs/HouseholdConfig.cs
index 5ab342e..af96ac9 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/HouseholdConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/HouseholdConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -28,4 +29,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.HouseholdId)
.OnDelete(DeleteBehavior.Cascade);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/RecurringTransactionConfig.cs b/apps/api/src/Api/Persistence/Configs/RecurringTransactionConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/RecurringTransactionConfig.cs
rename to apps/api/src/Api/Persistence/Configs/RecurringTransactionConfig.cs
index fdba495..2347c14 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/RecurringTransactionConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/RecurringTransactionConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -19,4 +20,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.RecurringTransactionId)
.OnDelete(DeleteBehavior.Restrict);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/TransactionConfig.cs b/apps/api/src/Api/Persistence/Configs/TransactionConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/TransactionConfig.cs
rename to apps/api/src/Api/Persistence/Configs/TransactionConfig.cs
index 936d0a2..c9422a5 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/TransactionConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/TransactionConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -20,4 +21,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.CategoryId)
.OnDelete(DeleteBehavior.Restrict);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/UserConfig.cs b/apps/api/src/Api/Persistence/Configs/UserConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/UserConfig.cs
rename to apps/api/src/Api/Persistence/Configs/UserConfig.cs
index 2e681ee..3ac4ecb 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/UserConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/UserConfig.cs
@@ -32,4 +32,4 @@ public void Configure(EntityTypeBuilder builder)
builder.HasMany(x => x.Categories)
.WithMany(x => x.Users);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Configs/UserHouseholdConfig.cs b/apps/api/src/Api/Persistence/Configs/UserHouseholdConfig.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Configs/UserHouseholdConfig.cs
rename to apps/api/src/Api/Persistence/Configs/UserHouseholdConfig.cs
index f6e6e8d..a6ea5dc 100644
--- a/apps/api/Kijk.Api/Persistence/Configs/UserHouseholdConfig.cs
+++ b/apps/api/src/Api/Persistence/Configs/UserHouseholdConfig.cs
@@ -1,4 +1,5 @@
using Kijk.Api.Domain.Entities;
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Kijk.Api.Persistence.Configs;
@@ -16,4 +17,4 @@ public void Configure(EntityTypeBuilder builder)
.HasForeignKey(x => x.UserId)
.OnDelete(DeleteBehavior.Cascade);
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Interceptors/AuditableEntityInterceptor.cs b/apps/api/src/Api/Persistence/Interceptors/AuditableEntityInterceptor.cs
similarity index 96%
rename from apps/api/Kijk.Api/Persistence/Interceptors/AuditableEntityInterceptor.cs
rename to apps/api/src/Api/Persistence/Interceptors/AuditableEntityInterceptor.cs
index 3503b93..6ebe313 100644
--- a/apps/api/Kijk.Api/Persistence/Interceptors/AuditableEntityInterceptor.cs
+++ b/apps/api/src/Api/Persistence/Interceptors/AuditableEntityInterceptor.cs
@@ -7,7 +7,6 @@ namespace Kijk.Api.Persistence.Interceptors;
public class AuditableEntityInterceptor : SaveChangesInterceptor
{
-
public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result)
{
UpdateEntities(eventData.Context);
@@ -27,7 +26,10 @@ public override ValueTask> SavingChangesAsync(
private static void UpdateEntities(DbContext? context)
{
- if (context == null) return;
+ if (context == null)
+ {
+ return;
+ }
var changedEntries = context.ChangeTracker.Entries();
@@ -54,4 +56,4 @@ public static bool HasChangedOwnedEntities(this EntityEntry entry) =>
r.TargetEntry != null &&
r.TargetEntry.Metadata.IsOwned() &&
r.TargetEntry.State is EntityState.Added or EntityState.Modified);
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs b/apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs
similarity index 91%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs
rename to apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs
index 8a98d8e..4801787 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.Designer.cs
@@ -44,7 +44,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("category_user", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -103,7 +103,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("accounts", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -181,7 +181,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("budgets", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -225,7 +225,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("categories", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -280,7 +280,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumptions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -354,7 +354,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumption_limits", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -397,7 +397,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("households", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -483,7 +483,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("recurring_transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -559,7 +559,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -615,7 +615,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("users", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
b.Property("UserId")
.HasColumnType("uuid")
@@ -664,14 +664,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
modelBuilder.Entity("CategoryUser", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", null)
+ b.HasOne("Api.Domain.Entities.Category", null)
.WithMany()
.HasForeignKey("CategoriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_category_user_categories_categories_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
@@ -679,9 +679,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_category_user_users_users_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Accounts")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -689,16 +689,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_accounts_users_user_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_budgets_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Budgets")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -708,9 +708,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptions")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -718,16 +718,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_energy_consumptions_households_household_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", "CreatedBy")
+ b.HasOne("Api.Domain.Entities.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_energy_consumption_limits_users_created_by_id");
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptionLimits")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -737,16 +737,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("CreatedBy");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("RecurringTransactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_recurring_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -758,25 +758,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("Transactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany("Transactions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_transactions_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.RecurringTransactions", null)
+ b.HasOne("Api.Domain.Entities.RecurringTransactions", null)
.WithOne("LastTransaction")
- .HasForeignKey("Kijk.Api.Domain.Entities.Transaction", "RecurringTransactionId")
+ .HasForeignKey("Api.Domain.Entities.Transaction", "RecurringTransactionId")
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("fk_transactions_recurring_transactions_recurring_transaction_id");
@@ -785,16 +785,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", "Household")
+ b.HasOne("Api.Domain.Entities.Household", "Household")
.WithMany("UserHouseholds")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_user_households_households_household_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany("UserHouseholds")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -806,19 +806,19 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Navigation("RecurringTransactions");
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Navigation("EnergyConsumptionLimits");
@@ -827,12 +827,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("UserHouseholds");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Navigation("LastTransaction");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Navigation("Accounts");
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.cs b/apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.cs
rename to apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.cs
index 6354670..c81fe3e 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240310184603_NewInitial.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240310184603_NewInitial.cs
@@ -1,5 +1,4 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs b/apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs
similarity index 91%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs
rename to apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs
index 89984c5..b2c68e9 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.Designer.cs
@@ -44,7 +44,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("category_user", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -103,7 +103,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("accounts", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -181,7 +181,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("budgets", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -229,7 +229,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("categories", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -284,7 +284,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumptions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -358,7 +358,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumption_limits", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -401,7 +401,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("households", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -487,7 +487,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("recurring_transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -563,7 +563,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -619,7 +619,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("users", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
b.Property("UserId")
.HasColumnType("uuid")
@@ -668,14 +668,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
modelBuilder.Entity("CategoryUser", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", null)
+ b.HasOne("Api.Domain.Entities.Category", null)
.WithMany()
.HasForeignKey("CategoriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_category_user_categories_categories_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
@@ -683,9 +683,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_category_user_users_users_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Accounts")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -693,16 +693,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_accounts_users_user_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_budgets_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Budgets")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -712,9 +712,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptions")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -722,16 +722,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_energy_consumptions_households_household_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", "CreatedBy")
+ b.HasOne("Api.Domain.Entities.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_energy_consumption_limits_users_created_by_id");
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptionLimits")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -741,16 +741,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("CreatedBy");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("RecurringTransactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_recurring_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -762,25 +762,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("Transactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany("Transactions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_transactions_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.RecurringTransactions", null)
+ b.HasOne("Api.Domain.Entities.RecurringTransactions", null)
.WithOne("LastTransaction")
- .HasForeignKey("Kijk.Api.Domain.Entities.Transaction", "RecurringTransactionId")
+ .HasForeignKey("Api.Domain.Entities.Transaction", "RecurringTransactionId")
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("fk_transactions_recurring_transactions_recurring_transaction_id");
@@ -789,16 +789,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", "Household")
+ b.HasOne("Api.Domain.Entities.Household", "Household")
.WithMany("UserHouseholds")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_user_households_households_household_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany("UserHouseholds")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -810,19 +810,19 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Navigation("RecurringTransactions");
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Navigation("EnergyConsumptionLimits");
@@ -831,12 +831,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("UserHouseholds");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Navigation("LastTransaction");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Navigation("Accounts");
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs b/apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs
similarity index 82%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs
rename to apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs
index 4420620..224104a 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240414151635_AddCategoryCreatorType.cs
@@ -8,22 +8,16 @@ namespace Kijk.Api.Persistence.Migrations
public partial class AddCategoryCreatorType : Migration
{
///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.AddColumn(
+ protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.AddColumn(
name: "creator_type",
table: "categories",
type: "integer",
nullable: false,
defaultValue: 0);
- }
///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropColumn(
+ protected override void Down(MigrationBuilder migrationBuilder) => migrationBuilder.DropColumn(
name: "creator_type",
table: "categories");
- }
}
}
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs b/apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs
similarity index 91%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs
rename to apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs
index b9dd73a..d4a76fd 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.Designer.cs
@@ -44,7 +44,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("category_user", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -103,7 +103,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("accounts", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -181,7 +181,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("budgets", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -230,7 +230,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("categories", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -285,7 +285,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumptions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -359,7 +359,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumption_limits", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -402,7 +402,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("households", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -488,7 +488,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("recurring_transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -564,7 +564,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -620,7 +620,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("users", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
b.Property("UserId")
.HasColumnType("uuid")
@@ -669,14 +669,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
modelBuilder.Entity("CategoryUser", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", null)
+ b.HasOne("Api.Domain.Entities.Category", null)
.WithMany()
.HasForeignKey("CategoriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_category_user_categories_categories_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
@@ -684,9 +684,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_category_user_users_users_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Accounts")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -694,16 +694,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_accounts_users_user_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_budgets_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Budgets")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -713,9 +713,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptions")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -723,16 +723,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_energy_consumptions_households_household_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", "CreatedBy")
+ b.HasOne("Api.Domain.Entities.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_energy_consumption_limits_users_created_by_id");
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptionLimits")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -742,16 +742,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("CreatedBy");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("RecurringTransactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_recurring_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -763,25 +763,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("Transactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany("Transactions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_transactions_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.RecurringTransactions", null)
+ b.HasOne("Api.Domain.Entities.RecurringTransactions", null)
.WithOne("LastTransaction")
- .HasForeignKey("Kijk.Api.Domain.Entities.Transaction", "RecurringTransactionId")
+ .HasForeignKey("Api.Domain.Entities.Transaction", "RecurringTransactionId")
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("fk_transactions_recurring_transactions_recurring_transaction_id");
@@ -790,16 +790,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", "Household")
+ b.HasOne("Api.Domain.Entities.Household", "Household")
.WithMany("UserHouseholds")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_user_households_households_household_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany("UserHouseholds")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -811,19 +811,19 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Navigation("RecurringTransactions");
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Navigation("EnergyConsumptionLimits");
@@ -832,12 +832,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("UserHouseholds");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Navigation("LastTransaction");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Navigation("Accounts");
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs b/apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs
similarity index 84%
rename from apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs
rename to apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs
index 97c59e6..907f0de 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs
+++ b/apps/api/src/Api/Persistence/Migrations/20240414151932_AddCorrectTypeConversion.cs
@@ -8,27 +8,21 @@ namespace Kijk.Api.Persistence.Migrations
public partial class AddCorrectTypeConversion : Migration
{
///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.AlterColumn(
+ protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.AlterColumn(
name: "creator_type",
table: "categories",
type: "text",
nullable: false,
oldClrType: typeof(int),
oldType: "integer");
- }
///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.AlterColumn(
+ protected override void Down(MigrationBuilder migrationBuilder) => migrationBuilder.AlterColumn(
name: "creator_type",
table: "categories",
type: "integer",
nullable: false,
oldClrType: typeof(string),
oldType: "text");
- }
}
}
diff --git a/apps/api/Kijk.Api/Persistence/Migrations/AppDbContextModelSnapshot.cs b/apps/api/src/Api/Persistence/Migrations/AppDbContextModelSnapshot.cs
similarity index 91%
rename from apps/api/Kijk.Api/Persistence/Migrations/AppDbContextModelSnapshot.cs
rename to apps/api/src/Api/Persistence/Migrations/AppDbContextModelSnapshot.cs
index 09e5c74..11cdd56 100644
--- a/apps/api/Kijk.Api/Persistence/Migrations/AppDbContextModelSnapshot.cs
+++ b/apps/api/src/Api/Persistence/Migrations/AppDbContextModelSnapshot.cs
@@ -41,7 +41,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("category_user", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -100,7 +100,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("accounts", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -178,7 +178,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("budgets", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -227,7 +227,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("categories", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -282,7 +282,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumptions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -356,7 +356,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("energy_consumption_limits", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -399,7 +399,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("households", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -485,7 +485,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("recurring_transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -561,7 +561,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("transactions", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Property("Id")
.ValueGeneratedOnAdd()
@@ -617,7 +617,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("users", (string)null);
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
b.Property("UserId")
.HasColumnType("uuid")
@@ -666,14 +666,14 @@ protected override void BuildModel(ModelBuilder modelBuilder)
modelBuilder.Entity("CategoryUser", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", null)
+ b.HasOne("Api.Domain.Entities.Category", null)
.WithMany()
.HasForeignKey("CategoriesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_category_user_categories_categories_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany()
.HasForeignKey("UsersId")
.OnDelete(DeleteBehavior.Cascade)
@@ -681,9 +681,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_category_user_users_users_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Accounts")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -691,16 +691,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_accounts_users_user_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Budget", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Budget", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_budgets_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", null)
+ b.HasOne("Api.Domain.Entities.User", null)
.WithMany("Budgets")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -710,9 +710,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumption", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumption", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptions")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -720,16 +720,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasConstraintName("fk_energy_consumptions_households_household_id");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.EnergyConsumptionLimit", b =>
+ modelBuilder.Entity("Api.Domain.Entities.EnergyConsumptionLimit", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.User", "CreatedBy")
+ b.HasOne("Api.Domain.Entities.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_energy_consumption_limits_users_created_by_id");
- b.HasOne("Kijk.Api.Domain.Entities.Household", null)
+ b.HasOne("Api.Domain.Entities.Household", null)
.WithMany("EnergyConsumptionLimits")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
@@ -739,16 +739,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("CreatedBy");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("RecurringTransactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_recurring_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -760,25 +760,25 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Transaction", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Transaction", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Account", "Account")
+ b.HasOne("Api.Domain.Entities.Account", "Account")
.WithMany("Transactions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_transactions_accounts_account_id");
- b.HasOne("Kijk.Api.Domain.Entities.Category", "Category")
+ b.HasOne("Api.Domain.Entities.Category", "Category")
.WithMany("Transactions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired()
.HasConstraintName("fk_transactions_categories_category_id");
- b.HasOne("Kijk.Api.Domain.Entities.RecurringTransactions", null)
+ b.HasOne("Api.Domain.Entities.RecurringTransactions", null)
.WithOne("LastTransaction")
- .HasForeignKey("Kijk.Api.Domain.Entities.Transaction", "RecurringTransactionId")
+ .HasForeignKey("Api.Domain.Entities.Transaction", "RecurringTransactionId")
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("fk_transactions_recurring_transactions_recurring_transaction_id");
@@ -787,16 +787,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("Category");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.UserHousehold", b =>
+ modelBuilder.Entity("Api.Domain.Entities.UserHousehold", b =>
{
- b.HasOne("Kijk.Api.Domain.Entities.Household", "Household")
+ b.HasOne("Api.Domain.Entities.Household", "Household")
.WithMany("UserHouseholds")
.HasForeignKey("HouseholdId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_user_households_households_household_id");
- b.HasOne("Kijk.Api.Domain.Entities.User", "User")
+ b.HasOne("Api.Domain.Entities.User", "User")
.WithMany("UserHouseholds")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -808,19 +808,19 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Account", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Account", b =>
{
b.Navigation("RecurringTransactions");
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Category", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Category", b =>
{
b.Navigation("Transactions");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.Household", b =>
+ modelBuilder.Entity("Api.Domain.Entities.Household", b =>
{
b.Navigation("EnergyConsumptionLimits");
@@ -829,12 +829,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("UserHouseholds");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.RecurringTransactions", b =>
+ modelBuilder.Entity("Api.Domain.Entities.RecurringTransactions", b =>
{
b.Navigation("LastTransaction");
});
- modelBuilder.Entity("Kijk.Api.Domain.Entities.User", b =>
+ modelBuilder.Entity("Api.Domain.Entities.User", b =>
{
b.Navigation("Accounts");
diff --git a/apps/api/Kijk.Api/Persistence/UtcDateTimeConverter.cs b/apps/api/src/Api/Persistence/UtcDateTimeConverter.cs
similarity index 99%
rename from apps/api/Kijk.Api/Persistence/UtcDateTimeConverter.cs
rename to apps/api/src/Api/Persistence/UtcDateTimeConverter.cs
index be88788..98c2180 100644
--- a/apps/api/Kijk.Api/Persistence/UtcDateTimeConverter.cs
+++ b/apps/api/src/Api/Persistence/UtcDateTimeConverter.cs
@@ -11,4 +11,4 @@ public UtcDateTimeConverter()
: base(v => DateTime.SpecifyKind(v, DateTimeKind.Utc), v => v)
{
}
-}
+}
\ No newline at end of file
diff --git a/apps/api/Kijk.Api/Program.cs b/apps/api/src/Api/Program.cs
similarity index 59%
rename from apps/api/Kijk.Api/Program.cs
rename to apps/api/src/Api/Program.cs
index 52fcf52..dd280ae 100644
--- a/apps/api/Kijk.Api/Program.cs
+++ b/apps/api/src/Api/Program.cs
@@ -1,15 +1,13 @@
-using Kijk.Api.Common;
-using Kijk.Api.Common.Extensions;
+using Kijk.Api.Common.Extensions;
using Kijk.Api.Common.Middleware;
using Kijk.Api.Common.Models;
using Kijk.Api.Common.Utils;
Log.Logger = LoggerUtils.CreateRootLogger();
+Log.Information("Application is starting ...");
try
{
- Log.Information("Application is starting ...");
-
// ##### Add services to the container. #####
var builder = WebApplication.CreateBuilder(args);
@@ -17,10 +15,9 @@
builder.AddLogging();
builder.Services
- .AddDatabase()
+ .AddDatabase(builder.Configuration)
.AddAppSettings(builder.Configuration)
.AddAuth(builder.Configuration)
- .AddExceptionHandler()
.AddScoped