Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b1a65e6
test jwt
enoreex Apr 12, 2025
6b92352
Merge branch 'user-service' of https://github.com/tesaide/hackathon_c…
enoreex Apr 12, 2025
e35424d
Good
enoreex Apr 12, 2025
843355a
fix: proper tracked files only
enoreex Apr 12, 2025
2528ca4
force: 12-04-2025_16
enoreex Apr 12, 2025
b9ba179
new
enoreex Apr 12, 2025
0f2591a
newnew
enoreex Apr 12, 2025
711f075
log
enoreex Apr 12, 2025
2d04a68
fix
enoreex Apr 12, 2025
1fbde25
blank
enoreex Apr 12, 2025
35cafd0
new blank eps
enoreex Apr 12, 2025
fc5cf1f
no tokens req
enoreex Apr 12, 2025
a4e1e7e
blank no token
enoreex Apr 12, 2025
060a486
get_users test
enoreex Apr 12, 2025
0dcc943
sry
enoreex Apr 12, 2025
4d1d46e
directories
enoreex Apr 12, 2025
8319cc1
no passwd
enoreex Apr 12, 2025
98ddaf2
dabeljy
enoreex Apr 12, 2025
6f6710f
user add integration
enoreex Apr 12, 2025
1907c34
add user cool sigmo
enoreex Apr 12, 2025
817c065
dep
enoreex Apr 12, 2025
aa0ec37
test
enoreex Apr 12, 2025
aeb9b67
structure
enoreex Apr 13, 2025
cd86894
lol
enoreex Apr 13, 2025
2b39062
leonid sigmos
enoreex Apr 13, 2025
0dc4c78
compile
enoreex Apr 13, 2025
a410cfb
work
enoreex Apr 13, 2025
1ecd12d
okej les go
enoreex Apr 13, 2025
e662e10
ok cool
enoreex Apr 13, 2025
40f1947
names fix
enoreex Apr 13, 2025
2690979
getuser
enoreex Apr 13, 2025
31d1ba5
post only
enoreex Apr 13, 2025
0f67cd7
ьв
enoreex Apr 13, 2025
22ebdad
change user
enoreex Apr 13, 2025
fae64cc
md
enoreex Apr 13, 2025
a7dacee
cooool
enoreex Apr 13, 2025
c53b4e6
cors
enoreex Apr 13, 2025
997b9bb
pizdo
enoreex Apr 13, 2025
a478096
options ss
enoreex Apr 13, 2025
c6405a5
CORS
enoreex Apr 13, 2025
92e93e6
OKK CORS
enoreex Apr 13, 2025
d2df1ff
jhjhh
enoreex Apr 13, 2025
6594eb3
NEW TYPE
enoreex Apr 13, 2025
c7bc68c
CORS AGAIN
enoreex Apr 13, 2025
296dacb
CORS LAST HOPE
enoreex Apr 13, 2025
518e6c6
QWE
enoreex Apr 13, 2025
9c6e440
change fix
enoreex Apr 13, 2025
1bd5982
change fix
enoreex Apr 13, 2025
b974aa6
FINAL
enoreex Apr 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 215 additions & 1 deletion backend/user-service/user-service-docs.md
Original file line number Diff line number Diff line change
@@ -1 +1,215 @@
Nothing
# 🛡️ User Service API

Проєкт розроблений на **C# (.NET 8)** з використанням **ASP.NET Core Web API**, **Kestrel**, **PostgreSQL**, **JWT-аутентифікації**, контейнеризований у **Docker**.

## 🔐 Загальні вимоги до запитів

Кожен запит до API повинен містити заголовок авторизації з JWT-токеном:

### 🔸 Authorization Header

```http
Authorization: Bearer <token>
```

## 🔴 Помилки

### 401 Unauthorized

```json
{
"message": "Unautorized error"
}
```

### 500 Internal Server Error

```json
{
"message": "Internal error",
"error": "<exception_message>"
}
```

## 📘 Ендпоїнти

### ✅ POST /api/admin/get_users

Отримання **всіх користувачів** з бази.

#### 🔹 Request Body

```json
null
```

#### 🔹 Response 200 OK

```json
{
"users": [
{
"id": "<uuid>",
"createdAt": "<timestamp>",
"updatedAt": "<timestamp>",
"lastLoginAt": "<timestamp|null>",
"isActive": "<bool>",
"password": "<base64 string>",
"roleId": "<uuid>",
"verificationStatus": "<string>",
"organizationId": "<uuid>",
"email": "<string>",
"fullName": "<string>",
"phone": "<string>",
"avatarUrl": "<string>",
"govId": "<string>"
}
]
}
```

### ✅ POST /api/admin/get_user

Отримання **одного користувача** по `id`.

#### 🔹 Request Body

```json
{
"id": "<uuid>"
}
```

#### 🔹 Response 200 OK

```json
{
"createdUser": {
"id": "<uuid>",
"createdAt": "<timestamp>",
"updatedAt": "<timestamp>",
"lastLoginAt": "<timestamp|null>",
"isActive": "<bool>",
"password": "<base64 string>",
"roleId": "<uuid>",
"verificationStatus": "<string>",
"organizationId": "<uuid>",
"email": "<string>",
"fullName": "<string>",
"phone": "<string>",
"avatarUrl": "<string>",
"govId": "<string>"
}
}
```

### ✅ POST /api/admin/user_add

Додавання **нового користувача**.

#### 🔹 Request Body

```json
{
"fullName": "<string>",
"email": "<string>",
"password": "<string>"
}
```

#### 🔹 Response 200 OK

```json
{
"user": [
{
"id": "<uuid>",
"createdAt": "<timestamp>",
"updatedAt": "<timestamp>",
"lastLoginAt": "<timestamp|null>",
"isActive": "<bool>",
"password": "<base64 string>",
"roleId": "<uuid>",
"verificationStatus": "<string>",
"organizationId": "<uuid>",
"email": "<string>",
"fullName": "<string>",
"phone": "<string>",
"avatarUrl": "<string>",
"govId": "<string>"
}
]
}
```

#### 🔻 Помилки

##### 400 Bad Request

```json
{
"message": "Full name is required"
}
```

```json
{
"message": "Email is required"
}
```

```json
{
"message": "Password is required"
}
```

##### 409 Conflict

```json
{
"message": "Email already exists"
}
```

### ✅ POST /api/admin/user_change

Зміна **даних користувача** за `id`.

#### 🔹 Request Body

```json
{
"id": "<uuid>",
"createdAt": "<timestamp>",
"updatedAt": "<timestamp>",
"lastLoginAt": "<timestamp|null>",
"isActive": "<bool>",
"password": "<base64 string>",
"roleId": "<uuid>",
"verificationStatus": "<string>",
"organizationId": "<uuid>",
"email": "<string>",
"fullName": "<string>",
"phone": "<string>",
"avatarUrl": "<string>",
"govId": "<string>"
}
```

#### 🔹 Response 200 OK

```json
{
"message": "Ok"
}
```

## 📦 Технології

- C# / .NET 8
- ASP.NET Core Web API
- PostgreSQL
- JWT (RS256)
- Docker
- Kestrel
9 changes: 0 additions & 9 deletions backend/user-service/user-service/Dockerfile

This file was deleted.

7 changes: 0 additions & 7 deletions backend/user-service/user-service/Program.cs

This file was deleted.

7 changes: 7 additions & 0 deletions backend/user-service/user-service/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
user-service:
build:
context: .
dockerfile: docker/Dockerfile
ports:
- "883:80"
17 changes: 17 additions & 0 deletions backend/user-service/user-service/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ./src/ .
RUN dotnet publish -c Release -o /app

RUN useradd -u 8571 -r -g -0 -s /sbin/nologin \
-c "Default Application User" postgres

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .

COPY ./keys/public.pem ./public.pem

USER 8571

ENTRYPOINT ["dotnet", "app.dll"]
9 changes: 9 additions & 0 deletions backend/user-service/user-service/keys/public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Ytzek1ZpurQJ+wCb5q5
4IBg33MCA+QXbgQ3G1udE7f1EjRKlLmMOyedMVr5t5Ssyh6oQYMKjr/5akRfwoXm
JU4JjkdmS6slqho/vYQQoOB1+HNzeOIY8jMMrbVMLYnwGBH3DNgOFJUFQiPPJ/o9
+GSvDwCbQ4cz1hSNKpywwAuHNowe7umC/9AzbOjSUfZcrh+qf2BbJg2Am5cYtdZV
h1PBXBiJCR+Bt+eEag8OUCSPBe4iOfyGttjPsLOHxObvlsuERuq6AowqvY0bam1L
tbHs4bZ7Jo0k7X0dYI9CriaeaNHGs/lBWfueGGJNlbplj9tZz9Qe/fIkK4NLN3qi
jQIDAQAB
-----END PUBLIC KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

using Services.Token;

namespace Controllers.Users.Common;

[ApiController]
public abstract class ControllerBaseAdminRequired : ControllerBase, IActionFilter
{
protected ITokenPacketProcessorService _tokenService;

protected Guid UserId { get; private set; }

protected ControllerBaseAdminRequired(ITokenPacketProcessorService tokenService)
{
_tokenService = tokenService;
}

public void OnActionExecuting(ActionExecutingContext context)
{
if (!_tokenService.TryValidateToken(context.HttpContext.Request, out var userId))
{
//context.Result = new UnauthorizedObjectResult(new { message = "Invalid token" });

return;
}

UserId = userId;
}

public void OnActionExecuted(ActionExecutedContext context) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Controllers.Users.Common;

using Microsoft.AspNetCore.Mvc;

using Services.Token;
using Services.PasswordHashing;
using Services.Users;

using Models.Users;

namespace Controllers.Users;

[ApiController]
[Route("api/admin/user_add")]
public class ControllerAddUser(
ITokenPacketProcessorService tokenService,
IPasswordHashingService passwordHasher,
AddUserService addUserService
) : ControllerBaseAdminRequired(tokenService)
{
[HttpPost]
public IActionResult AddUser([FromBody] AddUserRequest req)
{
try
{
if (string.IsNullOrWhiteSpace(req.FullName)) return BadRequest(new { message = "Full name is required" });

if (string.IsNullOrWhiteSpace(req.Email)) return BadRequest(new { message = "Email is required" });

if (string.IsNullOrWhiteSpace(req.Password)) return BadRequest(new { message = "Password is required" });

if (addUserService.EmailExists(req.Email)) return Conflict(new { message = "Email already exists" });

var hash = passwordHasher.Hash(req.Password);

var id = addUserService.CreateUser(req.FullName, req.Email, hash);

var createdUser = addUserService.GetById(id);

if (createdUser is null) return StatusCode(500, new { message = "Internal Error" });

return Ok(new { createdUser });
}
catch (Exception ex)
{
return StatusCode(500, new { message = "Internal error", error = ex.Message });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Controllers.Users.Common;

using Microsoft.AspNetCore.Mvc;

using Services.Token;
using Services.Users;

using Models.Users;

namespace Controllers.Users;

[ApiController]
[Route("api/admin/user_change")]
public class ControllerChangeUser(
ITokenPacketProcessorService tokenService,
ChangeUserService changeUserService
) : ControllerBaseAdminRequired(tokenService)
{
[HttpPost]
public IActionResult ChangeUser([FromBody] ChangeUserRequest req)
{
try
{
changeUserService.ChangeUser(req.Id, req.CreatedAt, req.Email, req.FullName, req.Phone, req.VerificationStatus);
return Ok(new { message = "User updated successfully" });
}
catch (Exception ex)
{
return StatusCode(500, new { message = "Internal error", error = ex.Message });
}
}
}
Loading
Loading