Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 32 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
name: 'Publish to Github pages'
name: 'Publish to Github Pages'

on:
push:
branches:
- master

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: 3.x

- uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Restore Workloads
run: dotnet workload restore

- name: Test
run: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat="opencover"

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
env:
Expand All @@ -30,13 +37,26 @@ jobs:
with:
key: ${{ github.ref }}
path: .cache
- name: Install DocXml
run: dotnet tool install xmldocmd -g
- name: generate docs
working-directory: src/TailoredApps.Shared.DateTime/bin/Debug/netstandard2.0
run: xmldocmd ./TailoredApps.Shared.DateTime.dll ../../../../../docs/Libraries/
- run: pip install mkdocs-material
- name: Publish
run: mkdocs gh-deploy --force



- name: Install MkDocs Material
run: pip install mkdocs-material

# ── Docs build ────────────────────────────────────────────────────────

- name: Build Polish site (root)
run: mkdocs build --config-file mkdocs.yml --site-dir site

- name: Build English site (/en/)
run: mkdocs build --config-file mkdocs-en.yml --site-dir site/en

# ── Deploy ───────────────────────────────────────────────────────────

- name: Deploy to GitHub Pages
run: |
cd site
git init
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "docs: deploy PL + EN [skip ci]"
git push --force "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" HEAD:gh-pages
168 changes: 168 additions & 0 deletions docs-en/Libraries/DateTime/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# TailoredApps.Shared.DateTime

[![NuGet](https://img.shields.io/nuget/v/TailoredApps.Shared.DateTime)](https://www.nuget.org/packages/TailoredApps.Shared.DateTime/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/tailored-apps/SharedComponents/blob/master/LICENSE)

---

## Description

This library solves one of the fundamental testability problems in .NET — direct use of `System.DateTime.Now` in production code, which prevents writing deterministic unit tests.

`TailoredApps.Shared.DateTime` provides the `IDateTimeProvider` interface and its default implementation `DateTimeProvider`. Instead of calling `DateTime.Now` directly, you inject `IDateTimeProvider` via DI and call `provider.Now`. In tests you swap the implementation for a mock that returns any point in time — making tests repeatable and independent of the system clock.

---

## Instalacja

```bash
dotnet add package TailoredApps.Shared.DateTime
```

---

## Rejestracja w DI

```csharp
// Program.cs
using TailoredApps.Shared.DateTime;

builder.Services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
```

---

## Przykład użycia

### Kod produkcyjny

```csharp
public class OrderService
{
private readonly IDateTimeProvider _dateTime;

public OrderService(IDateTimeProvider dateTime)
{
_dateTime = dateTime;
}

public Order CreateOrder(string customerId, decimal amount)
{
return new Order
{
Id = Guid.NewGuid(),
CustomerId = customerId,
Amount = amount,
CreatedAt = _dateTime.UtcNow, // zamiast DateTime.UtcNow
ExpiresAt = _dateTime.UtcNow.AddDays(30)
};
}

public bool IsOrderExpired(Order order)
{
return order.ExpiresAt < _dateTime.UtcNow;
}
}
```

### Test jednostkowy (Moq)

```csharp
using Moq;
using TailoredApps.Shared.DateTime;
using Xunit;

public class OrderServiceTests
{
[Fact]
public void CreateOrder_ShouldSetCreatedAtToCurrentUtcTime()
{
// Arrange
var fixedTime = new DateTime(2024, 6, 1, 12, 0, 0, DateTimeKind.Utc);
var dateTimeMock = new Mock<IDateTimeProvider>();
dateTimeMock.Setup(d => d.UtcNow).Returns(fixedTime);

var service = new OrderService(dateTimeMock.Object);

// Act
var order = service.CreateOrder("customer-1", 99.99m);

// Assert
Assert.Equal(fixedTime, order.CreatedAt);
Assert.Equal(fixedTime.AddDays(30), order.ExpiresAt);
}

[Fact]
public void IsOrderExpired_WhenExpiresInPast_ReturnsTrue()
{
// Arrange
var now = new DateTime(2024, 6, 1, DateTimeKind.Utc);
var dateTimeMock = new Mock<IDateTimeProvider>();
dateTimeMock.Setup(d => d.UtcNow).Returns(now);

var service = new OrderService(dateTimeMock.Object);
var expiredOrder = new Order { ExpiresAt = now.AddDays(-1) };

// Act & Assert
Assert.True(service.IsOrderExpired(expiredOrder));
}
}
```

---

## API Reference

| Typ | Rodzaj | Opis |
|-----|--------|------|
| `IDateTimeProvider` | Interfejs | Główny kontrakt — wszystkie właściwości do pobierania czasu |
| `DateTimeProvider` | Klasa | Implementacja produkcyjna — deleguje do `System.DateTime` |
| `IDateTimeProvider.Now` | Właściwość | Aktualny czas lokalny (`DateTime.Now`) |
| `IDateTimeProvider.UtcNow` | Właściwość | Aktualny czas UTC (`DateTime.UtcNow`) |
| `IDateTimeProvider.Today` | Właściwość | Aktualna data lokalna (`DateTime.Today`) |
| `IDateTimeProvider.UtcToday` | Właściwość | Aktualna data UTC (`DateTime.UtcNow.Date`) |
| `IDateTimeProvider.TimeOfDay` | Właściwość | Pora dnia (lokalnie) jako `TimeSpan` |
| `IDateTimeProvider.UtcTimeOfDaty` | Właściwość | Pora dnia UTC jako `TimeSpan` |

---

## 🤖 AI Agent Prompt

```markdown
## TailoredApps.Shared.DateTime — Instrukcja dla agenta AI

Używasz biblioteki TailoredApps.Shared.DateTime w projekcie .NET.

### Rejestracja
```csharp
// Program.cs
builder.Services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
```

### Użycie
- Nigdy nie używaj `DateTime.Now` ani `DateTime.UtcNow` bezpośrednio w kodzie produkcyjnym
- Wstrzykuj `IDateTimeProvider` przez konstruktor
- Używaj `provider.UtcNow` dla timestampów w bazie danych
- Używaj `provider.Now` tylko gdy potrzebujesz czasu lokalnego (np. do wyświetlania)

```csharp
// ✅ Poprawnie
public class MyService
{
private readonly IDateTimeProvider _dateTime;
public MyService(IDateTimeProvider dateTime) => _dateTime = dateTime;
public DateTime GetExpiry() => _dateTime.UtcNow.AddHours(1);
}

// ❌ Niepoprawnie
public class MyService
{
public DateTime GetExpiry() => DateTime.UtcNow.AddHours(1); // nie testowalny!
}
```

### Zasady
- Zawsze używaj `IDateTimeProvider` zamiast `System.DateTime` bezpośrednio
- W testach mockuj interfejs, aby zwracał stały punkt w czasie
- Preferuj `UtcNow`/`UtcToday` dla wartości zapisywanych w bazie danych
```
91 changes: 91 additions & 0 deletions docs-en/Libraries/Email/Models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# TailoredApps.Shared.Email.Models

[![NuGet](https://img.shields.io/nuget/v/TailoredApps.Shared.Email.Models)](https://www.nuget.org/packages/TailoredApps.Shared.Email.Models/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/tailored-apps/SharedComponents/blob/master/LICENSE)

---

## Description

A lightweight package containing only the `MailMessage` data model — a representation of an email message. Separating the model into its own package allows other libraries (e.g. `TailoredApps.Shared.Email.Office365`) to depend only on the model without pulling in the full SMTP implementation.

---

## Instalacja

```bash
dotnet add package TailoredApps.Shared.Email.Models
```

---

## Przykład użycia

```csharp
using TailoredApps.Shared.Email.Models;

// Przykład: wyświetlenie listy odebranych wiadomości
ICollection<MailMessage> messages = await emailProvider.GetMail(
folder: "Inbox",
sender: "boss@company.com",
fromLast: TimeSpan.FromDays(7)
);

foreach (var msg in messages)
{
Console.WriteLine($"[{msg.Date:yyyy-MM-dd}] Od: {msg.Sender}");
Console.WriteLine($" Temat: {msg.Topic}");
Console.WriteLine($" Do: {msg.Recipent}");

if (!string.IsNullOrEmpty(msg.HtmlBody))
Console.WriteLine($" (HTML body, {msg.HtmlBody.Length} znaków)");

if (msg.Attachements?.Count > 0)
Console.WriteLine($" Załączniki: {string.Join(", ", msg.Attachements.Keys)}");
}
```

---

## API Reference

### Klasa `MailMessage`

| Właściwość | Typ | Opis |
|------------|-----|------|
| `Topic` | `string` | Temat wiadomości |
| `Sender` | `string` | Adres nadawcy |
| `Recipent` | `string` | Adres odbiorcy |
| `Copy` | `string` | Adres CC (kopia) |
| `Body` | `string` | Treść tekstowa (plain-text) |
| `HtmlBody` | `string` | Treść HTML |
| `Attachements` | `Dictionary<string, string>` | Załączniki: nazwa pliku → zawartość Base64 |
| `Date` | `DateTimeOffset` | Data i czas wysłania wiadomości |

---

## 🤖 AI Agent Prompt

```markdown
## TailoredApps.Shared.Email.Models — Instrukcja dla agenta AI

Używasz modelu `MailMessage` z biblioteki TailoredApps.Shared.Email.Models.

### Model MailMessage
```csharp
// Właściwości:
msg.Topic // temat
msg.Sender // nadawca
msg.Recipent // odbiorca
msg.Copy // CC
msg.Body // treść plain-text
msg.HtmlBody // treść HTML
msg.Attachements // Dictionary<string, string> — Base64 załączniki
msg.Date // DateTimeOffset — data wysłania
```

### Zasady
- Model jest używany jako zwracana wartość przez IEmailProvider.GetMail()
- Załączniki przechowywane jako Base64 — dekoduj przez Convert.FromBase64String() gdy potrzebujesz byte[]
- Właściwość Recipent (nie Recipient) — literówka w API, nie zmieniaj
```
Loading
Loading