Add PeopleByCompany DbSet and controller for managing company personnel

- Created migration to add PeopleByCompany DbSet to the database context.
- Updated MarechaiContext to include PeopleByCompany DbSet.
- Modified MarechaiContextModelSnapshot to reflect the new PeopleByCompany table.
- Implemented PeopleByCompanyController with CRUD operations for managing personnel by company.
This commit is contained in:
2026-03-23 10:32:29 +00:00
parent 1d1385be7c
commit e2f78871d3
26 changed files with 9713 additions and 4 deletions

View File

@@ -150,6 +150,42 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
[ObservableProperty]
private List<string> _statusItems = [];
// --- People junction state ---
[ObservableProperty]
private ObservableCollection<PersonByCompanyDto> _companyPeople = [];
[ObservableProperty]
private ObservableCollection<string> _companyPeopleDisplays = [];
[ObservableProperty]
private ObservableCollection<PersonDto> _availablePeople = [];
[ObservableProperty]
private PersonDto? _selectedAvailablePerson;
[ObservableProperty]
private string _personSearchText = string.Empty;
[ObservableProperty]
private string _newPersonPosition = string.Empty;
[ObservableProperty]
private DateTimeOffset? _newPersonStart;
[ObservableProperty]
private DateTimeOffset? _newPersonEnd;
[ObservableProperty]
private bool _newPersonOngoing;
[ObservableProperty]
private bool _isEditingExisting;
// When non-null, we are editing an existing person-company record
private long? _editingPersonCompanyId;
private List<PersonDto>? _allPeopleList;
public AdminCompaniesViewModel(ApiClient apiClient,
IJwtService jwtService,
ITokenService tokenService,
@@ -187,6 +223,11 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
DeleteTranslationCommand = new AsyncRelayCommand<CompanyDescriptionDto>(DeleteTranslationAsync);
EditTranslationCommand = new RelayCommand<CompanyDescriptionDto>(EditTranslation);
OpenLogosCommand = new RelayCommand<CompanyDto>(OpenLogos);
AddPersonCommand = new AsyncRelayCommand(AddPersonAsync);
RemovePersonCommand = new AsyncRelayCommand<string>(RemovePersonByDisplayAsync);
EditPersonCommand = new RelayCommand<string>(EditPerson);
SavePersonEditCommand = new AsyncRelayCommand(SavePersonEditAsync);
CancelPersonEditCommand = new RelayCommand(CancelPersonEdit);
InitializeLanguages();
@@ -206,6 +247,11 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
public IAsyncRelayCommand<CompanyDescriptionDto> DeleteTranslationCommand { get; }
public IRelayCommand<CompanyDescriptionDto> EditTranslationCommand { get; }
public IRelayCommand<CompanyDto> OpenLogosCommand { get; }
public IAsyncRelayCommand AddPersonCommand { get; }
public IAsyncRelayCommand<string> RemovePersonCommand { get; }
public IRelayCommand<string> EditPersonCommand { get; }
public IAsyncRelayCommand SavePersonEditCommand { get; }
public IRelayCommand CancelPersonEditCommand { get; }
// --- IRegionAware ---
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
@@ -294,6 +340,7 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
_editingCompanyId = null;
EditPanelTitle = _localizer["AddCompanyDialog_Title"];
ClearForm();
IsEditingExisting = false;
IsEditingDescription = false;
IsEditing = true;
}
@@ -306,8 +353,12 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
_editingCompanyId = company.Id;
EditPanelTitle = _localizer["EditCompanyDialog_Title"];
PopulateForm(company);
IsEditingExisting = true;
IsEditingDescription = false;
IsEditing = true;
if(company.Id != null)
_ = LoadCompanyPeopleAsync(company.Id.Value);
}
// --- Delete company ---
@@ -611,6 +662,18 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
_logger.LogError(ex, "Error loading companies for search");
}
}
if(_allPeopleList == null)
{
try
{
_allPeopleList = await _apiClient.People.GetAsync();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error loading people");
}
}
}
// --- Helpers ---
@@ -637,6 +700,9 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
SoldToSearchText = string.Empty;
HasError = false;
ErrorMessage = string.Empty;
CompanyPeople.Clear();
CompanyPeopleDisplays.Clear();
ClearPersonForm();
}
private void PopulateForm(CompanyDto company)
@@ -700,4 +766,192 @@ public partial class AdminCompaniesViewModel : ObservableObject, IRegionAware
_ => _localizer["StatusUnknown"]
};
}
// --- People junction methods ---
private async Task LoadCompanyPeopleAsync(int companyId)
{
CompanyPeople.Clear();
CompanyPeopleDisplays.Clear();
try
{
List<PersonByCompanyDto>? items = await _apiClient.Companies[companyId].People.GetAsync();
if(items != null)
{
foreach(PersonByCompanyDto p in items)
{
CompanyPeople.Add(p);
CompanyPeopleDisplays.Add(FormatPersonDisplay(p));
}
}
}
catch(Exception ex)
{
_logger.LogError(ex, "Error loading people for company {Id}", companyId);
}
}
private static string FormatPersonDisplay(PersonByCompanyDto p)
{
string name = p.DisplayName ?? p.Alias ?? $"{p.Name} {p.Surname}".Trim();
string display = name;
if(!string.IsNullOrWhiteSpace(p.Position))
display += $" — {p.Position}";
if(p.Ongoing == true)
display += " (Ongoing)";
else if(p.Start != null || p.End != null)
{
string start = p.Start?.ToString("yyyy") ?? "?";
string end = p.End?.ToString("yyyy") ?? "?";
display += $" ({start}{end})";
}
return display;
}
private async Task AddPersonAsync()
{
if(_editingCompanyId == null || SelectedAvailablePerson?.Id == null) return;
try
{
var dto = new PersonByCompanyDto
{
PersonId = SelectedAvailablePerson.Id,
CompanyId = _editingCompanyId,
Position = string.IsNullOrWhiteSpace(NewPersonPosition) ? null : NewPersonPosition,
Start = NewPersonStart,
End = NewPersonEnd,
Ongoing = NewPersonOngoing
};
await _apiClient.PeopleByCompany.PostAsync(dto);
ClearPersonForm();
await LoadCompanyPeopleAsync(_editingCompanyId.Value);
}
catch(Exception ex)
{
_logger.LogError(ex, "Error adding person to company");
}
}
private void EditPerson(string? display)
{
if(display == null) return;
int idx = CompanyPeopleDisplays.IndexOf(display);
if(idx < 0 || idx >= CompanyPeople.Count) return;
PersonByCompanyDto p = CompanyPeople[idx];
_editingPersonCompanyId = p.Id;
// Find and select the person in available people
if(p.PersonId != null && _allPeopleList != null)
{
PersonDto? person = _allPeopleList.FirstOrDefault(pp => pp.Id == p.PersonId);
if(person != null)
{
PersonSearchText = person.DisplayName ?? person.Alias ?? $"{person.Name} {person.Surname}".Trim();
UpdatePeopleSuggestions(PersonSearchText);
SelectedAvailablePerson = AvailablePeople.FirstOrDefault(pp => pp.Id == person.Id);
}
}
NewPersonPosition = p.Position ?? string.Empty;
NewPersonStart = p.Start;
NewPersonEnd = p.End;
NewPersonOngoing = p.Ongoing ?? false;
}
private async Task SavePersonEditAsync()
{
if(_editingPersonCompanyId == null || _editingCompanyId == null) return;
try
{
var dto = new PersonByCompanyDto
{
Position = string.IsNullOrWhiteSpace(NewPersonPosition) ? null : NewPersonPosition,
Start = NewPersonStart,
End = NewPersonEnd,
Ongoing = NewPersonOngoing
};
await _apiClient.PeopleByCompany[_editingPersonCompanyId.Value].PutAsync(dto);
CancelPersonEdit();
await LoadCompanyPeopleAsync(_editingCompanyId.Value);
}
catch(Exception ex)
{
_logger.LogError(ex, "Error updating person-company association");
}
}
private void CancelPersonEdit()
{
_editingPersonCompanyId = null;
ClearPersonForm();
}
private async Task RemovePersonByDisplayAsync(string? display)
{
if(display == null || _editingCompanyId == null) return;
int idx = CompanyPeopleDisplays.IndexOf(display);
if(idx < 0 || idx >= CompanyPeople.Count || CompanyPeople[idx].Id == null) return;
try
{
await _apiClient.PeopleByCompany[CompanyPeople[idx].Id!.Value].DeleteAsync();
await LoadCompanyPeopleAsync(_editingCompanyId.Value);
}
catch(Exception ex)
{
_logger.LogError(ex, "Error removing person from company");
}
}
public void UpdatePeopleSuggestions(string query)
{
AvailablePeople.Clear();
if(_allPeopleList == null) return;
IEnumerable<PersonDto> source = _allPeopleList;
if(!string.IsNullOrWhiteSpace(query))
source = source.Where(p =>
(p.Name != null &&
p.Name.Contains(query, StringComparison.OrdinalIgnoreCase)) ||
(p.Surname != null &&
p.Surname.Contains(query, StringComparison.OrdinalIgnoreCase)) ||
(p.DisplayName != null &&
p.DisplayName.Contains(query, StringComparison.OrdinalIgnoreCase)) ||
(p.Alias != null &&
p.Alias.Contains(query, StringComparison.OrdinalIgnoreCase)));
foreach(PersonDto match in source.Take(50))
AvailablePeople.Add(match);
}
private void ClearPersonForm()
{
SelectedAvailablePerson = null;
PersonSearchText = string.Empty;
NewPersonPosition = string.Empty;
NewPersonStart = null;
NewPersonEnd = null;
NewPersonOngoing = false;
_editingPersonCompanyId = null;
}
}

View File

@@ -78,6 +78,11 @@ public partial class CompanyDetailViewModel : ObservableObject, IRegionAware
[ObservableProperty]
private string _descriptionHtml = string.Empty;
[ObservableProperty]
private ObservableCollection<string> _people = [];
public bool ShowPeople => People.Count > 0;
public CompanyDetailViewModel(CompanyDetailService companyDetailService, FlagCache flagCache,
CompanyLogoCache logoCache, IStringLocalizer localizer,
ILogger<CompanyDetailViewModel> logger, IRegionManager regionManager,
@@ -508,6 +513,42 @@ public partial class CompanyDetailViewModel : ObservableObject, IRegionAware
FilteredComputers = new ObservableCollection<CompanyDetailMachine>(Computers);
FilteredConsoles = new ObservableCollection<CompanyDetailMachine>(Consoles);
// Load people associated with this company
try
{
People.Clear();
List<PersonByCompanyDto> people = await _companyDetailService.GetPeopleByCompanyAsync(CompanyId);
foreach(PersonByCompanyDto person in people)
{
string name = person.DisplayName ?? person.Alias ??
$"{person.Name} {person.Surname}".Trim();
string display = name;
if(!string.IsNullOrWhiteSpace(person.Position))
display += $" — {person.Position}";
if(person.Ongoing == true)
display += $" ({_localizer["OngoingText"].Value})";
else if(person.Start != null || person.End != null)
{
string start = person.Start?.ToString("yyyy") ?? "?";
string end = person.End?.ToString("yyyy") ?? "?";
display += $" ({start}{end})";
}
People.Add(display);
}
OnPropertyChanged(nameof(ShowPeople));
}
catch(Exception ex)
{
_logger.LogError("Failed to load people for company: {Exception}", ex.Message);
}
// Load localized description
try
{

View File

@@ -298,6 +298,101 @@
Text="{Binding Twitter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Header="{Binding Source={StaticResource Strings}, Path=FacebookText}"
Text="{Binding Facebook, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<!-- People Section (only when editing existing company) -->
<StackPanel Visibility="{Binding IsEditingExisting, Converter={StaticResource BoolToVisibilityConverter}}"
Spacing="8"
Margin="0,16,0,0">
<!-- Section header -->
<TextBlock Text="{Binding Source={StaticResource Strings}, Path=CompanyPeopleSection}"
FontSize="16"
FontWeight="SemiBold" />
<!-- Current people list -->
<ItemsRepeater ItemsSource="{Binding CompanyPeopleDisplays}">
<ItemsRepeater.Layout>
<StackLayout Spacing="4" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding}"
VerticalAlignment="Center"
TextWrapping="Wrap" />
<Button Grid.Column="1"
Content="✏️"
Command="{Binding DataContext.EditPersonCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Padding="4,2"
Style="{ThemeResource TextBlockButtonStyle}" />
<Button Grid.Column="2"
Content="🗑️"
Command="{Binding DataContext.RemovePersonCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Padding="4,2"
Style="{ThemeResource TextBlockButtonStyle}" />
</Grid>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<!-- Add/Edit person form -->
<AutoSuggestBox Header="{Binding Source={StaticResource Strings}, Path=CompanyPeopleLabel}"
PlaceholderText="{Binding Source={StaticResource Strings}, Path=CompanyPeopleLabel}"
Text="{Binding PersonSearchText, Mode=TwoWay}"
QueryIcon="Find"
x:Name="PersonSearchBox"
TextChanged="PersonSearchBox_TextChanged" />
<ComboBox ItemsSource="{Binding AvailablePeople}"
SelectedItem="{Binding SelectedAvailablePerson, Mode=TwoWay}"
HorizontalAlignment="Stretch"
PlaceholderText="{Binding Source={StaticResource Strings}, Path=CompanyPeopleLabel}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Name}" />
<Run Text=" " />
<Run Text="{Binding Surname}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox Header="{Binding Source={StaticResource Strings}, Path=CompanyPersonPositionLabel}"
Text="{Binding NewPersonPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CalendarDatePicker Header="{Binding Source={StaticResource Strings}, Path=CompanyPersonStartLabel}"
Date="{Binding NewPersonStart, Mode=TwoWay}"
HorizontalAlignment="Stretch" />
<CalendarDatePicker Header="{Binding Source={StaticResource Strings}, Path=CompanyPersonEndLabel}"
Date="{Binding NewPersonEnd, Mode=TwoWay}"
HorizontalAlignment="Stretch" />
<CheckBox Content="{Binding Source={StaticResource Strings}, Path=CompanyPersonOngoingLabel}"
IsChecked="{Binding NewPersonOngoing, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal"
Spacing="8">
<Button Content="+"
Command="{Binding AddPersonCommand}"
Style="{ThemeResource AccentButtonStyle}"
Padding="8,4" />
<Button Content="{Binding Source={StaticResource Strings}, Path=SaveButton}"
Command="{Binding SavePersonEditCommand}"
Padding="8,4" />
<Button Content="{Binding Source={StaticResource Strings}, Path=CancelButton}"
Command="{Binding CancelPersonEditCommand}"
Padding="8,4" />
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>

View File

@@ -31,4 +31,11 @@ public sealed partial class AdminCompaniesPage : Page
vm.ApplyFilter();
}
private void PersonSearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput &&
DataContext is AdminCompaniesViewModel vm)
vm.UpdatePeopleSuggestions(sender.Text);
}
}

View File

@@ -348,6 +348,35 @@
</ScrollViewer>
</StackPanel>
<!-- People Section -->
<StackPanel Visibility="{Binding ShowPeople, Converter={StaticResource BoolToVisibilityConverter}}"
Spacing="8"
Margin="0,16,0,0">
<TextBlock Text="{Binding Source={StaticResource Strings}, Path=CompanyPeopleLabel}"
FontSize="20"
FontWeight="SemiBold" />
<ItemsControl ItemsSource="{Binding People}"
HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Padding="12,8">
<TextBlock Text="{Binding}"
FontSize="14"
TextWrapping="Wrap" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<!-- Description Section -->
<StackPanel Visibility="{Binding HasDescription, Converter={StaticResource BoolToVisibilityConverter}}"
Spacing="8"

View File

@@ -1819,4 +1819,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>Keine Zeitschriften für diesen Filter gefunden</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Fehler beim Laden der Zeitschriften. Bitte versuchen Sie es später erneut.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Zeitschrift nicht gefunden</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>Personen</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Position</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Beginn</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>Ende</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>Laufend</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>Personen</value></data>
<data name="OngoingText" xml:space="preserve"><value>Laufend</value></data>
</root>

View File

@@ -1959,4 +1959,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>No se encontraron revistas para este filtro</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Error al cargar las revistas. Por favor, inténtelo de nuevo más tarde.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Revista no encontrada</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>Personas</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Cargo</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Inicio</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>Fin</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>En curso</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>Personas</value></data>
<data name="OngoingText" xml:space="preserve"><value>En curso</value></data>
</root>

View File

@@ -1923,4 +1923,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>Aucun magazine trouvé pour ce filtre</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Erreur de chargement des magazines. Veuillez réessayer plus tard.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Magazine non trouvé</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>Personnes</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Poste</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Début</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>Fin</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>En cours</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>Personnes</value></data>
<data name="OngoingText" xml:space="preserve"><value>En cours</value></data>
</root>

View File

@@ -1819,4 +1819,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>Nullae ephemerides inventae pro hoc filtro</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Error in ephemeridibus onerandis. Quaeso, iterum posterius tempta.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Ephemeris non inventa</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>Personae</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Munus</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Initium</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>Finis</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>In cursu</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>Personae</value></data>
<data name="OngoingText" xml:space="preserve"><value>In cursu</value></data>
</root>

View File

@@ -1819,4 +1819,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>Nenhuma revista encontrada para este filtro</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Erro ao carregar as revistas. Por favor, tente novamente mais tarde.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Revista não encontrada</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>Pessoas</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Cargo</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Início</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>Fim</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>Em andamento</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>Pessoas</value></data>
<data name="OngoingText" xml:space="preserve"><value>Em andamento</value></data>
</root>

View File

@@ -2165,4 +2165,11 @@
<data name="No magazines found for this filter" xml:space="preserve"><value>No magazines found for this filter</value></data>
<data name="Failed to load magazines. Please try again later." xml:space="preserve"><value>Failed to load magazines. Please try again later.</value></data>
<data name="Magazine not found" xml:space="preserve"><value>Magazine not found</value></data>
<data name="CompanyPeopleSection" xml:space="preserve"><value>People</value></data>
<data name="CompanyPersonPositionLabel" xml:space="preserve"><value>Position</value></data>
<data name="CompanyPersonStartLabel" xml:space="preserve"><value>Start</value></data>
<data name="CompanyPersonEndLabel" xml:space="preserve"><value>End</value></data>
<data name="CompanyPersonOngoingLabel" xml:space="preserve"><value>Ongoing</value></data>
<data name="CompanyPeopleLabel" xml:space="preserve"><value>People</value></data>
<data name="OngoingText" xml:space="preserve"><value>Ongoing</value></data>
</root>

View File

@@ -27,6 +27,7 @@ using Marechai.App.MemoriesByMachine;
using Marechai.App.News;
using Marechai.App.People;
using Marechai.App.PeopleByBook;
using Marechai.App.PeopleByCompany;
using Marechai.App.PeopleByDocument;
using Marechai.App.PeopleByMagazine;
using Marechai.App.Processor;
@@ -195,6 +196,11 @@ namespace Marechai.App
{
get => new global::Marechai.App.PeopleByBook.PeopleByBookRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The peopleByCompany property</summary>
public global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder PeopleByCompany
{
get => new global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The peopleByDocument property</summary>
public global::Marechai.App.PeopleByDocument.PeopleByDocumentRequestBuilder PeopleByDocument
{
@@ -285,7 +291,7 @@ namespace Marechai.App
ApiClientBuilder.RegisterDefaultDeserializer<FormParseNodeFactory>();
if (string.IsNullOrEmpty(RequestAdapter.BaseUrl))
{
RequestAdapter.BaseUrl = "http://localhost:5023";
RequestAdapter.BaseUrl = "http://localhost:5099";
}
PathParameters.TryAdd("baseurl", RequestAdapter.BaseUrl);
}

View File

@@ -4,6 +4,7 @@ using Marechai.App.Companies.Item.Description;
using Marechai.App.Companies.Item.Descriptions;
using Marechai.App.Companies.Item.Logos;
using Marechai.App.Companies.Item.Machines;
using Marechai.App.Companies.Item.People;
using Marechai.App.Companies.Item.Soldto;
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
@@ -42,6 +43,11 @@ namespace Marechai.App.Companies.Item
{
get => new global::Marechai.App.Companies.Item.Machines.MachinesRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The people property</summary>
public global::Marechai.App.Companies.Item.People.PeopleRequestBuilder People
{
get => new global::Marechai.App.Companies.Item.People.PeopleRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The soldto property</summary>
public global::Marechai.App.Companies.Item.Soldto.SoldtoRequestBuilder Soldto
{

View File

@@ -0,0 +1,92 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Companies.Item.People
{
/// <summary>
/// Builds and executes requests for operations under \companies\{company-id}\people
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Companies.Item.People.PeopleRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/companies/{company%2Did}/people", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Companies.Item.People.PeopleRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/companies/{company%2Did}/people", rawUrl)
{
}
/// <returns>A List&lt;global::Marechai.App.Models.PersonByCompanyDto&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<global::Marechai.App.Models.PersonByCompanyDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<global::Marechai.App.Models.PersonByCompanyDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.PersonByCompanyDto>(requestInfo, global::Marechai.App.Models.PersonByCompanyDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Companies.Item.People.PeopleRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Companies.Item.People.PeopleRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Companies.Item.People.PeopleRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,129 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class PersonByCompanyDto : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The alias property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Alias { get; set; }
#nullable restore
#else
public string Alias { get; set; }
#endif
/// <summary>The company_id property</summary>
public int? CompanyId { get; set; }
/// <summary>The display_name property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? DisplayName { get; set; }
#nullable restore
#else
public string DisplayName { get; set; }
#endif
/// <summary>The end property</summary>
public DateTimeOffset? End { get; set; }
/// <summary>The id property</summary>
public long? Id { get; set; }
/// <summary>The name property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Name { get; set; }
#nullable restore
#else
public string Name { get; set; }
#endif
/// <summary>The ongoing property</summary>
public bool? Ongoing { get; set; }
/// <summary>The person_id property</summary>
public int? PersonId { get; set; }
/// <summary>The position property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Position { get; set; }
#nullable restore
#else
public string Position { get; set; }
#endif
/// <summary>The start property</summary>
public DateTimeOffset? Start { get; set; }
/// <summary>The surname property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Surname { get; set; }
#nullable restore
#else
public string Surname { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.PersonByCompanyDto"/> and sets the default values.
/// </summary>
public PersonByCompanyDto()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.PersonByCompanyDto"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.PersonByCompanyDto CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.PersonByCompanyDto();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "alias", n => { Alias = n.GetStringValue(); } },
{ "company_id", n => { CompanyId = n.GetIntValue(); } },
{ "display_name", n => { DisplayName = n.GetStringValue(); } },
{ "end", n => { End = n.GetDateTimeOffsetValue(); } },
{ "id", n => { Id = n.GetLongValue(); } },
{ "name", n => { Name = n.GetStringValue(); } },
{ "ongoing", n => { Ongoing = n.GetBoolValue(); } },
{ "person_id", n => { PersonId = n.GetIntValue(); } },
{ "position", n => { Position = n.GetStringValue(); } },
{ "start", n => { Start = n.GetDateTimeOffsetValue(); } },
{ "surname", n => { Surname = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("alias", Alias);
writer.WriteIntValue("company_id", CompanyId);
writer.WriteStringValue("display_name", DisplayName);
writer.WriteDateTimeOffsetValue("end", End);
writer.WriteLongValue("id", Id);
writer.WriteStringValue("name", Name);
writer.WriteBoolValue("ongoing", Ongoing);
writer.WriteIntValue("person_id", PersonId);
writer.WriteStringValue("position", Position);
writer.WriteDateTimeOffsetValue("start", Start);
writer.WriteStringValue("surname", Surname);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,148 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.PeopleByCompany.Item
{
/// <summary>
/// Builds and executes requests for operations under \people-by-company\{id}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleByCompanyItemRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleByCompanyItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/people-by-company/{id}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleByCompanyItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/people-by-company/{id}", rawUrl)
{
}
/// <returns>A <see cref="string"/></returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<string?> DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<string> DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToDeleteRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendPrimitiveAsync<string>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="string"/></returns>
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<string?> PutAsync(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<string> PutAsync(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPutRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendPrimitiveAsync<string>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleByCompanyItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleByCompanyItemRequestBuilderPutRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,124 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Marechai.App.PeopleByCompany.Item;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.PeopleByCompany
{
/// <summary>
/// Builds and executes requests for operations under \people-by-company
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleByCompanyRequestBuilder : BaseRequestBuilder
{
/// <summary>Gets an item from the Marechai.App.peopleByCompany.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder"/></returns>
public global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder this[long position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
urlTplParams.Add("id", position);
return new global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>Gets an item from the Marechai.App.peopleByCompany.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder"/></returns>
[Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")]
public global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder this[string position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("id", position);
return new global::Marechai.App.PeopleByCompany.Item.PeopleByCompanyItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleByCompanyRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/people-by-company", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PeopleByCompanyRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/people-by-company", rawUrl)
{
}
/// <returns>A <see cref="long"/></returns>
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<long?> PostAsync(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<long?> PostAsync(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPostRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendPrimitiveAsync<long?>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.PersonByCompanyDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.PeopleByCompany.PeopleByCompanyRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PeopleByCompanyRequestBuilderPostRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -1,6 +1,6 @@
{
"descriptionHash": "9EB39BF8E4AA5D63DF0C504518159C0573E586602ADD2205D8933F573E4DE414028948042F214DF5BAC865B24211792103EA2F63DC2B3AC8E18E1DC0AE707CFE",
"descriptionLocation": "http://localhost:5023/openapi/v1.json",
"descriptionHash": "454544AAD533B545EB9E8F5F78836E3518A07778A09BCDAD07079A61CCAB2549DCB3EAA44571547A158D9FA7AD38FA317BAA03481608E4F2A4B92D27A7D0C340",
"descriptionLocation": "http://localhost:5099/openapi/v1.json",
"lockFileVersion": "1.0.0",
"kiotaVersion": "1.29.0",
"clientClassName": "ApiClient",

View File

@@ -151,4 +151,86 @@ public class CompanyDetailService
return null;
}
}
/// <summary>
/// Gets people associated with a company
/// </summary>
public async Task<List<PersonByCompanyDto>> GetPeopleByCompanyAsync(int companyId)
{
try
{
_logger.LogInformation("Fetching people for company {CompanyId}", companyId);
List<PersonByCompanyDto>? people = await _apiClient.Companies[companyId].People.GetAsync();
if(people == null) return [];
_logger.LogInformation("Successfully fetched {Count} people for company {CompanyId}",
people.Count,
companyId);
return people;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error fetching people for company {CompanyId}", companyId);
return [];
}
}
/// <summary>
/// Adds a person to a company
/// </summary>
public async Task<long?> AddPersonToCompanyAsync(PersonByCompanyDto dto)
{
try
{
return await _apiClient.PeopleByCompany.PostAsync(dto);
}
catch(Exception ex)
{
_logger.LogError(ex, "Error adding person to company");
return null;
}
}
/// <summary>
/// Updates a person-company association
/// </summary>
public async Task<bool> UpdatePersonInCompanyAsync(long id, PersonByCompanyDto dto)
{
try
{
await _apiClient.PeopleByCompany[id].PutAsync(dto);
return true;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error updating person-company association {Id}", id);
return false;
}
}
/// <summary>
/// Removes a person from a company
/// </summary>
public async Task<bool> RemovePersonFromCompanyAsync(long id)
{
try
{
await _apiClient.PeopleByCompany[id].DeleteAsync();
return true;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error removing person from company {Id}", id);
return false;
}
}
}

View File

@@ -197,6 +197,13 @@ public class LocalizedStrings
public string FoundedDayUnknownLabel => _l["FoundedDayUnknownLabel"];
public string SoldMonthUnknownLabel => _l["SoldMonthUnknownLabel"];
public string SoldDayUnknownLabel => _l["SoldDayUnknownLabel"];
public string CompanyPeopleSection => _l["CompanyPeopleSection"];
public string CompanyPersonPositionLabel => _l["CompanyPersonPositionLabel"];
public string CompanyPersonStartLabel => _l["CompanyPersonStartLabel"];
public string CompanyPersonEndLabel => _l["CompanyPersonEndLabel"];
public string CompanyPersonOngoingLabel => _l["CompanyPersonOngoingLabel"];
public string CompanyPeopleLabel => _l["CompanyPeopleLabel"];
public string OngoingText => _l["OngoingText"];
public string SaveButton => _l["SaveButton"];
public string CancelButton => _l["CancelButton"];

View File

@@ -0,0 +1,55 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2026 Natalia Portillo
*******************************************************************************/
using System;
using System.Text.Json.Serialization;
namespace Marechai.Data.Dtos;
public class PersonByCompanyDto : BaseDto<long>
{
[JsonPropertyName("person_id")]
public int PersonId { get; set; }
[JsonPropertyName("company_id")]
public int CompanyId { get; set; }
[JsonPropertyName("position")]
public string? Position { get; set; }
[JsonPropertyName("start")]
public DateTime? Start { get; set; }
[JsonPropertyName("end")]
public DateTime? End { get; set; }
[JsonPropertyName("ongoing")]
public bool Ongoing { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("alias")]
public string? Alias { get; set; }
[JsonPropertyName("surname")]
public string? Surname { get; set; }
[JsonPropertyName("display_name")]
public string? DisplayName { get; set; }
[JsonIgnore]
public string FullName => DisplayName ?? Alias ?? $"{Name} {Surname}";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Marechai.Database.Migrations
{
/// <inheritdoc />
public partial class AddPeopleByCompanyDbSet : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@@ -4673,7 +4673,7 @@ namespace Marechai.Database.Migrations
b.HasIndex("Start");
b.ToTable("PeopleByCompany");
b.ToTable("PeopleByCompany", (string)null);
});
modelBuilder.Entity("Marechai.Database.Models.PeopleByDocument", b =>

View File

@@ -111,6 +111,7 @@ public class MarechaiContext : IdentityDbContext<ApplicationUser, ApplicationRol
public virtual DbSet<OwnedMachine> OwnedMachines { get; set; }
public virtual DbSet<OwnedMachinePhoto> OwnedMachinePhotos { get; set; }
public virtual DbSet<PeopleByBook> PeopleByBooks { get; set; }
public virtual DbSet<PeopleByCompany> PeopleByCompanies { get; set; }
public virtual DbSet<PeopleByDocument> PeopleByDocuments { get; set; }
public virtual DbSet<PeopleByMagazine> PeopleByMagazines { get; set; }
public virtual DbSet<Person> People { get; set; }
@@ -1294,6 +1295,8 @@ public class MarechaiContext : IdentityDbContext<ApplicationUser, ApplicationRol
modelBuilder.Entity<PeopleByCompany>(entity =>
{
entity.ToTable("PeopleByCompany");
entity.HasIndex(e => e.PersonId);
entity.HasIndex(e => e.CompanyId);

View File

@@ -0,0 +1,144 @@
/*******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ---------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] -----------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
// Copyright © 2003-2026 Natalia Portillo
*******************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Marechai.Data.Dtos;
using Marechai.Database.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace Marechai.Server.Controllers;
[Route("/people-by-company")]
[ApiController]
public class PeopleByCompanyController(MarechaiContext context) : ControllerBase
{
[HttpGet("/companies/{companyId:int}/people")]
[AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<List<PersonByCompanyDto>> GetByCompany(int companyId) =>
(await context.PeopleByCompanies
.Where(p => p.CompanyId == companyId)
.Select(p => new PersonByCompanyDto
{
Id = p.Id,
Name = p.Person.Name,
Surname = p.Person.Surname,
Alias = p.Person.Alias,
DisplayName = p.Person.DisplayName,
PersonId = p.PersonId,
CompanyId = p.CompanyId,
Position = p.Position,
Start = p.Start,
End = p.End,
Ongoing = p.Ongoing
})
.ToListAsync()).OrderBy(p => p.FullName)
.ThenBy(p => p.Position)
.ThenBy(p => p.Start)
.ToList();
[HttpPost]
[Authorize(Roles = "Admin,UberAdmin")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<long>> CreateAsync([FromBody] PersonByCompanyDto dto)
{
string userId = User.FindFirstValue(ClaimTypes.Sid);
if(userId is null) return Unauthorized();
var item = new PeopleByCompany
{
PersonId = dto.PersonId,
CompanyId = dto.CompanyId,
Position = dto.Position,
Start = dto.Start,
End = dto.End,
Ongoing = dto.Ongoing
};
await context.PeopleByCompanies.AddAsync(item);
await context.SaveChangesWithUserAsync(userId);
return item.Id;
}
[HttpPut("{id:long}")]
[Authorize(Roles = "Admin,UberAdmin")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> UpdateAsync(long id, [FromBody] PersonByCompanyDto dto)
{
string userId = User.FindFirstValue(ClaimTypes.Sid);
if(userId is null) return Unauthorized();
PeopleByCompany item = await context.PeopleByCompanies.FindAsync(id);
if(item is null) return NotFound();
item.Position = dto.Position;
item.Start = dto.Start;
item.End = dto.End;
item.Ongoing = dto.Ongoing;
await context.SaveChangesWithUserAsync(userId);
return Ok();
}
[HttpDelete("{id:long}")]
[Authorize(Roles = "Admin,UberAdmin")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> DeleteAsync(long id)
{
string userId = User.FindFirstValue(ClaimTypes.Sid);
if(userId is null) return Unauthorized();
PeopleByCompany item = await context.PeopleByCompanies.FindAsync(id);
if(item is null) return NotFound();
context.PeopleByCompanies.Remove(item);
await context.SaveChangesWithUserAsync(userId);
return Ok();
}
}