Skip to content

Commit 7fbe360

Browse files
Managment structure (#9)
* add search * refactor autosuggest * refactor create report * remove store * correct reduce --------- Co-authored-by: aleksandr.z <aleksandr.z@ati.su>
1 parent b95e400 commit 7fbe360

File tree

36 files changed

+526
-127
lines changed

36 files changed

+526
-127
lines changed

backend/Bugget.BO/Mappers/ReportMapper.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Bugget.Entities.Adapters;
22
using Bugget.Entities.BO;
33
using Bugget.Entities.BO.ReportBo;
4-
using Bugget.Entities.Constants;
4+
using Bugget.Entities.BO.Search;
55
using Bugget.Entities.DbModels;
66
using Bugget.Entities.DbModels.Bug;
77
using Bugget.Entities.DbModels.Report;
@@ -35,6 +35,15 @@ public static ReportView ToView(this ReportDbModel report, IReadOnlyDictionary<s
3535
};
3636
}
3737

38+
public static SearchReportsView ToView(this SearchReportsDbModel search, IReadOnlyDictionary<string, Employee> employeesDict)
39+
{
40+
return new SearchReportsView
41+
{
42+
Reports = search.Reports.Select(r => ToView(r, employeesDict)).ToArray(),
43+
Total = search.Total
44+
};
45+
}
46+
3847
public static Report ToReport(this ReportCreateDto report, string userId)
3948
{
4049
return new Report
@@ -95,4 +104,42 @@ public static ReportUpdateDbModel ToReportUpdateDbModel(this ReportUpdate report
95104
ParticipantsUserIds = report.ParticipantsUserIds,
96105
};
97106
}
107+
108+
public static SearchReports ToSearchReports(
109+
string? query,
110+
int[]? reportStatuses,
111+
string[]? userIds,
112+
string[]? teamIds,
113+
string? sort,
114+
uint skip,
115+
uint take,
116+
IReadOnlyDictionary<string, IReadOnlyCollection<Employee>> employeesByTeam)
117+
{
118+
List<string> resultUserIds = [];
119+
if (teamIds?.Length >= 0)
120+
{
121+
foreach (var teamId in teamIds)
122+
{
123+
if (employeesByTeam.TryGetValue(teamId, out var team))
124+
{
125+
resultUserIds.AddRange(team.Select(e => e.Id));
126+
}
127+
}
128+
}
129+
130+
if (userIds?.Length >= 0)
131+
{
132+
resultUserIds.AddRange(userIds);
133+
}
134+
135+
return new SearchReports
136+
{
137+
Query = string.IsNullOrEmpty(query) ? null : query,
138+
ReportStatuses = reportStatuses?.Length > 0 ? reportStatuses : null,
139+
UserIds = resultUserIds.Count > 0 ? resultUserIds.ToArray() : null,
140+
Skip = skip,
141+
Take = take,
142+
Sort = SortOption.Parse(sort)
143+
};
144+
}
98145
}

backend/Bugget.BO/Services/EmployeesService.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,30 @@ public class EmployeesService(EmployeesDataAccess employeesDataAccess)
1010
{
1111
public (IEnumerable<EmployeeView>, int) ListEmployees(int skip, int take)
1212
{
13-
return (employeesDataAccess.ListEmployees().Skip(skip).Take(take).Select(EmployeeAdapter.Transform), employeesDataAccess.ListEmployees().Count);
13+
return (employeesDataAccess.ListEmployees().Skip(skip).Take(take).Select(EmployeeAdapter.Transform),
14+
employeesDataAccess.ListEmployees().Count);
1415
}
1516

16-
public (IEnumerable<EmployeeView>, int) AutocompleteEmployees(string searchString, int skip, int take)
17+
public (IEnumerable<EmployeeView>, int) AutocompleteEmployees(
18+
string userId,
19+
string searchString,
20+
int skip,
21+
int take,
22+
uint depth)
1723
{
24+
var user = employeesDataAccess.GetEmployee(userId);
25+
if (user == null)
26+
return ([], 0);
27+
1828
var foundedUsers = employeesDataAccess.ListEmployees()
29+
// текущая глубина + 1
30+
.Where(e => user.Depth == null || e.Depth >= user.Depth - depth)
1931
.Select(EmployeeAdapter.Transform)
20-
.Where(v => v.FullName.Contains(searchString, StringComparison.OrdinalIgnoreCase))
21-
.OrderBy(v => v.FullName.IndexOf(searchString, StringComparison.OrdinalIgnoreCase))
22-
.ThenBy(v => v.FullName)
32+
.Where(v => v.Name.Contains(searchString, StringComparison.OrdinalIgnoreCase))
33+
.OrderBy(v => v.Name.IndexOf(searchString, StringComparison.OrdinalIgnoreCase))
34+
.ThenBy(v => v.Name)
2335
.ToList();
24-
36+
2537
return (foundedUsers.Skip(skip).Take(take), foundedUsers.Count);
2638
}
2739

backend/Bugget.BO/Services/ReportsService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Bugget.BO.Mappers;
22
using Bugget.DA.Postgres;
33
using Bugget.Entities.BO.ReportBo;
4+
using Bugget.Entities.BO.Search;
45
using Bugget.Entities.DbModels.Report;
56
using Bugget.Features;
67
using Bugget.Features.Context;
@@ -45,4 +46,9 @@ public Task<ReportDbModel[]> ListReportsAsync(string userId)
4546

4647
return reportDbModel;
4748
}
49+
50+
public Task<SearchReportsDbModel> SearchReportsAsync(SearchReports search)
51+
{
52+
return reportsDbClient.SearchReportsAsync(search);
53+
}
4854
}

backend/Bugget.DA/Files/EmployeesDataAccess.cs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ public IReadOnlyCollection<Employee> ListEmployees()
2323
{
2424
return EmployeesCollection.Value;
2525
}
26+
27+
public IReadOnlyDictionary<string, IReadOnlyCollection<Employee>> DictByTeamEmployees()
28+
{
29+
return EmployeesByTeam.Value;
30+
}
2631

2732
protected override Task ExecuteAsync(CancellationToken stoppingToken)
2833
{
@@ -50,26 +55,72 @@ private async Task LoadEmployees()
5055

5156
private static Employee[] Employees =
5257
[
53-
new Employee { Id = "1", FirstName = "Иван", LastName = "Иванов", Surname = "Иванович", NotificationUserId = "66xpfgxex2da4p5fn8dx17pcnr" },
5458
new Employee
5559
{
56-
Id = "any-ldap-id", FirstName = "Петр", LastName = "Петров", Surname = "Петрович", NotificationUserId = "67xpfgxex2da4p5fn8dx17pcnr"
60+
Id = "1",
61+
FirstName = "Иван",
62+
LastName = "Иванов",
63+
Surname = "Иванович",
64+
NotificationUserId = "66xpfgxex2da4p5fn8dx17pcnr",
65+
TeamId = "4",
66+
TeamName = "test4",
67+
Depth = -1
68+
},
69+
new Employee
70+
{
71+
Id = "any-ldap-id",
72+
FirstName = "Петр",
73+
LastName = "Петров",
74+
Surname = "Петрович",
75+
NotificationUserId = "67xpfgxex2da4p5fn8dx17pcnr",
76+
TeamId = "4",
77+
TeamName = "test4",
78+
Depth = 0
5779
},
5880
new Employee
5981
{
60-
Id = "int", FirstName = "Сергей", LastName = "Сергеев", Surname = "Сергеевич", NotificationUserId = "68xpfgxex2da4p5fn8dx17pcnr"
82+
Id = "int",
83+
FirstName = "Сергей",
84+
LastName = "Сергеев",
85+
Surname = "Сергеевич",
86+
NotificationUserId = "68xpfgxex2da4p5fn8dx17pcnr",
87+
TeamId = "3",
88+
TeamName = "test3",
89+
Depth = 2
6190
},
6291
new Employee
6392
{
64-
Id = "guid", FirstName = "Алексей", LastName = "Алексеев", Surname = "Алексеевич", NotificationUserId = "69xpfgxex2da4p5fn8dx17pcnr"
93+
Id = "guid",
94+
FirstName = "Алексей",
95+
LastName = "Алексеев",
96+
Surname = "Алексеевич",
97+
NotificationUserId = "69xpfgxex2da4p5fn8dx17pcnr",
98+
TeamId = "2",
99+
TeamName = "test2",
100+
Depth = 1
65101
},
66102
new Employee
67103
{
68-
Id = "default-user", FirstName = "Дефолт", LastName = "Дефолтов", Surname = "Дефолтович", NotificationUserId = "69xpfgxex2da4p5fn8dx17pcnr"
104+
Id = "default-user",
105+
FirstName = "Дефолт",
106+
LastName = "Дефолтов",
107+
Surname = "Дефолтович",
108+
NotificationUserId = "69xpfgxex2da4p5fn8dx17pcnr",
109+
TeamId = "1",
110+
TeamName = "test1",
111+
Depth = 1
69112
}
70113
];
71114

72115
private static readonly Lazy<IReadOnlyCollection<Employee>> EmployeesCollection = new(() => Employees.AsReadOnly());
73116

74117
private static readonly Lazy<IReadOnlyDictionary<string, Employee>> EmployeesDict = new(() => Employees.ToDictionary(k => k.Id).AsReadOnly());
118+
119+
private static readonly Lazy<IReadOnlyDictionary<string, IReadOnlyCollection<Employee>>> EmployeesByTeam = new(() =>
120+
Employees
121+
.GroupBy(e => e.TeamId ?? string.Empty)
122+
.ToDictionary(
123+
g => g.Key, IReadOnlyCollection<Employee> (g) => g.ToArray().AsReadOnly()
124+
)
125+
.AsReadOnly());
75126
}

backend/Bugget.DA/Postgres/ReportsDbClient.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using System.Text.Json;
2-
using System.Text.Json.Serialization;
3-
using Bugget.Entities.Config;
2+
using Bugget.Entities.BO.Search;
43
using Bugget.Entities.DbModels;
54
using Bugget.Entities.DbModels.Report;
65
using Dapper;
7-
using Microsoft.Extensions.Options;
8-
using Npgsql;
96

107
namespace Bugget.DA.Postgres;
118

@@ -88,5 +85,26 @@ public async Task<ReportDbModel[]> ListReportsAsync(string userId)
8885
: null;
8986
}
9087

88+
public async Task<SearchReportsDbModel> SearchReportsAsync(SearchReports search)
89+
{
90+
await using var connection = await DataSource.OpenConnectionAsync();
91+
92+
var jsonResult = await connection.ExecuteScalarAsync<string>(
93+
"SELECT public.search_reports(@query, @statuses, @userIds, @sortField, @sortDesc, @skip, @take);",
94+
new
95+
{
96+
query = search.Query,
97+
statuses = search.ReportStatuses,
98+
userIds = search.UserIds,
99+
sortField = search.Sort.Field, // "created_at" или "updated_at"
100+
sortDesc = search.Sort.IsDescending,
101+
skip = (int)search.Skip,
102+
take = (int)search.Take
103+
}
104+
);
105+
106+
return Deserialize<SearchReportsDbModel>(jsonResult);
107+
}
108+
91109
private T? Deserialize<T>(string json) => JsonSerializer.Deserialize<T>(json, JsonSerializerOptions);
92110
}

backend/Bugget.Entities/Adapters/EmployeeAdapter.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ public static EmployeeView Transform(Employee e)
1212
.AppendWithSeparator(e.Surname)
1313
.AppendWithSeparator(e.FirstName)
1414
.AppendWithSeparator(e.LastName);
15+
16+
var fullName = sb.ToString().TrimEnd();
17+
18+
if(string.IsNullOrEmpty(fullName))
19+
fullName = e.Id;
1520

16-
return new EmployeeView { UserId = e.Id, FullName = sb.ToString().TrimEnd() };
21+
return new EmployeeView { Id = e.Id, Name = fullName };
1722
}
1823

1924
public static UserView ToUserView(Employee e)

backend/Bugget.Entities/BO/Employee.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,31 @@ namespace Bugget.Entities.BO;
22

33
public class Employee
44
{
5+
/// <summary>
6+
/// Уникальный идентификатор соответствующий хэдеру авторизации LDAP_USER_ID_KEY
7+
/// </summary>
58
public required string Id { get; init; }
69
public string? FirstName { get; init; }
710
public string? LastName { get; init; }
811
public string? Surname { get; init; }
12+
13+
/// <summary>
14+
/// Идентификатор пользователя в системе уведомлений
15+
/// </summary>
916
public string? NotificationUserId { get; init; }
17+
18+
/// <summary>
19+
/// Идентификатор команды/отдела
20+
/// </summary>
21+
public string? TeamId { get; init; }
22+
23+
/// <summary>
24+
/// Название команды/отдела
25+
/// </summary>
26+
public string? TeamName { get; init; }
27+
28+
/// <summary>
29+
/// Глубина пользователя в иерархии компании
30+
/// </summary>
31+
public int? Depth { get; init; }
1032
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Bugget.Entities.BO.Search;
2+
3+
public sealed class SearchReports
4+
{
5+
public required string? Query { get; init; }
6+
public required int[]? ReportStatuses { get; init; }
7+
public required string[]? UserIds { get; init; }
8+
public required SortOption Sort { get; init; }
9+
public required uint Skip { get; init; }
10+
public required uint Take { get; init; }
11+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace Bugget.Entities.BO.Search;
2+
3+
public class SortOption
4+
{
5+
public string Field { get; set; } = "created";
6+
public bool IsDescending { get; set; } = true;
7+
8+
public static SortOption Parse(string? sort)
9+
{
10+
if (string.IsNullOrWhiteSpace(sort))
11+
return new SortOption();
12+
13+
var parts = sort.Split('_');
14+
if (parts.Length != 2)
15+
throw new ArgumentException("Invalid sort format");
16+
17+
return new SortOption
18+
{
19+
Field = parts[0],
20+
IsDescending = parts[1].Equals("desc", StringComparison.OrdinalIgnoreCase)
21+
};
22+
}
23+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Bugget.Entities.DTO.Report;
2+
3+
public sealed class ReportsSearchDto
4+
{
5+
public string? Search { get; set; }
6+
public string? Order { get; init; } = "created";
7+
public bool? Desc { get; init; } = true;
8+
public int[]? ReportStatuses { get; init; }
9+
public string[]? UserIds { get; init; }
10+
public string[]? TeamIds { get; init; }
11+
}

0 commit comments

Comments
 (0)