Skip to content

Persons API #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
25 changes: 21 additions & 4 deletions .github/workflows/build-and-push-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,35 @@ jobs:
name: Deploy '${{ needs.set-env.outputs.branch }}' to ${{ needs.set-env.outputs.environment }}
needs: [ set-env ]
uses: DFE-Digital/deploy-azure-container-apps-action/.github/workflows/build-push-deploy.yml@v2.2.0
strategy:
matrix:
image: [
"Dockerfile",
"Dockerfile.PersonsApi"
]
include:
- image: "Dockerfile"
aca_name_secret: "AZURE_ACA_NAME"
prefix: ""
name: "tramsapi-app"
- image: "Dockerfile.PersonsApi"
aca_name_secret: "AZURE_PERSONS_API_ACA_NAME"
prefix: "persons-api-"
name: "personsapi-app"
with:
docker-image-name: 'tramsapi-app'
docker-build-file-name: './Dockerfile'
docker-image-name: '${{ matrix.name }}'
docker-build-file-name: './${{ matrix.image }}'
docker-tag-prefix: ${{ matrix.prefix }}
environment: ${{ needs.set-env.outputs.environment }}
annotate-release: true
# Only annotate the release once, because both apps are deployed at the same time
annotate-release: ${{ matrix.name == 'tramsapi-app' }}
docker-build-args: |
COMMIT_SHA="${{ needs.set-env.outputs.checked-out-sha }}"
secrets:
azure-acr-name: ${{ secrets.ACR_NAME }}
azure-acr-credentials: ${{ secrets.ACR_CREDENTIALS }}
azure-aca-credentials: ${{ secrets.AZURE_ACA_CREDENTIALS }}
azure-aca-name: ${{ secrets.AZURE_ACA_NAME }}
azure-aca-name: ${{ secrets[matrix.aca_name_secret] }}
azure-aca-resource-group: ${{ secrets.AZURE_ACA_RESOURCE_GROUP }}

create-tag:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/continuous-integration-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ on:
paths:
- 'Dfe.Academies.*/**'
- 'TramsDataApi*/**'
- 'PersonsApi*/**'
- '!Dfe.Academies.Performance/**'
pull_request:
branches: [ main ]
types: [ opened, synchronize, reopened ]
paths:
- 'Dfe.Academies.*/**'
- 'TramsDataApi*/**'
- 'PersonsApi*/**'
- '!Dfe.Academies.Performance/**'

env:
Expand Down Expand Up @@ -73,15 +75,15 @@ jobs:

- name: Install dotnet reportgenerator
run: dotnet tool install --global dotnet-reportgenerator-globaltool

- name: Add nuget package source
run: dotnet nuget add source --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/DFE-Digital/index.json"

- name: Restore tools for tests
run: dotnet tool restore

- name: Restore dependencies
run: dotnet restore TramsDataApi.sln
run: dotnet restore

- name: Build, Test and Analyze
env:
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ on:
pull_request:
paths:
- Dockerfile
- Dockerfile.PersonsApi
types: [opened, synchronize]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
image: [
"Dockerfile",
"Dockerfile.PersonsApi"
]
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -19,5 +26,6 @@ jobs:
- name: Build docker image
uses: docker/build-push-action@v6
with:
file: './${{ matrix.image }}'
secrets: github_token=${{ secrets.GITHUB_TOKEN }}
push: false
7 changes: 7 additions & 0 deletions CypressTests/cypress.env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"url": "https://localhost",
"personsUrl": "https://localhost:7089",
"api": "https://localhost:7089",
"apiKey": "app-key",
"authKey": "app-key"
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Migrations\" />
<Folder Include="Migrations\Mop\" />
</ItemGroup>

</Project>
64 changes: 64 additions & 0 deletions Dfe.Academies.Api.Infrastructure/MopContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Dfe.Academies.Domain.Persons;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Dfe.Academies.Academisation.Data;

public class MopContext : DbContext
{
const string DEFAULT_SCHEMA = "mop";

public MopContext()
{

}

public MopContext(DbContextOptions<MopContext> options) : base(options)
{

}

public DbSet<MemberContactDetails> MemberContactDetails { get; set; } = null!;
public DbSet<Constituency> Constituencies { get; set; } = null!;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=localhost;Database=sip;Integrated Security=true;TrustServerCertificate=True");
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MemberContactDetails>(ConfigureMemberContactDetails);
modelBuilder.Entity<Constituency>(ConfigureConstituency);

base.OnModelCreating(modelBuilder);
}


private void ConfigureMemberContactDetails(EntityTypeBuilder<MemberContactDetails> memberContactDetailsConfiguration)
{
memberContactDetailsConfiguration.HasKey(e => e.MemberID);

memberContactDetailsConfiguration.ToTable("MemberContactDetails", DEFAULT_SCHEMA);
memberContactDetailsConfiguration.Property(e => e.MemberID).HasColumnName("memberID");
memberContactDetailsConfiguration.Property(e => e.Email).HasColumnName("email");
memberContactDetailsConfiguration.Property(e => e.TypeId).HasColumnName("typeId");
}

private void ConfigureConstituency(EntityTypeBuilder<Constituency> constituencyConfiguration)
{
constituencyConfiguration.ToTable("Constituencies", DEFAULT_SCHEMA);
constituencyConfiguration.Property(e => e.ConstituencyId).HasColumnName("constituencyId");
constituencyConfiguration.Property(e => e.ConstituencyName).HasColumnName("constituencyName");
constituencyConfiguration.Property(e => e.NameList).HasColumnName("nameListAs");
constituencyConfiguration.Property(e => e.NameDisplayAs).HasColumnName("nameDisplayAs");
constituencyConfiguration.Property(e => e.NameFullTitle).HasColumnName("nameFullTitle");
constituencyConfiguration.Property(e => e.NameFullTitle).HasColumnName("nameFullTitle");
constituencyConfiguration.Property(e => e.LastRefresh).HasColumnName("lastRefresh");
}


}
12 changes: 12 additions & 0 deletions Dfe.Academies.Api.Infrastructure/MopRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Dfe.Academies.Academisation.Data;
using Dfe.Academies.Infrastructure.Repositories;

namespace Dfe.Academies.Infrastructure
{
public class MopRepository<TEntity> : Repository<TEntity, MopContext> where TEntity : class, new()
{
public MopRepository(MopContext dbContext) : base(dbContext)
{
}
}
}
186 changes: 186 additions & 0 deletions Dfe.Academies.Api.Infrastructure/Repositories/Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
using Dfe.Academies.Domain.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.Linq.Expressions;

namespace Dfe.Academies.Infrastructure.Repositories
{
public abstract class Repository<TEntity, TDbContext> : IRepository<TEntity>
where TEntity : class, new()
where TDbContext : DbContext
{
/// <summary>
/// The <typeparamref name="TDbContext" />
/// </summary>
protected readonly TDbContext DbContext;

/// <summary>Constructor</summary>
/// <param name="dbContext"></param>
protected Repository(TDbContext dbContext) => this.DbContext = dbContext;

/// <summary>Short hand for _dbContext.Set</summary>
/// <returns></returns>
protected virtual DbSet<TEntity> DbSet()
{
return this.DbContext.Set<TEntity>();
}

/// <inheritdoc />
public virtual IQueryable<TEntity> Query() => (IQueryable<TEntity>)this.DbSet();

/// <inheritdoc />
public virtual ICollection<TEntity> Fetch(Expression<Func<TEntity, bool>> predicate)
{
return (ICollection<TEntity>)((IQueryable<TEntity>)this.DbSet()).Where<TEntity>(predicate).ToList<TEntity>();
}

/// <inheritdoc />
public virtual async Task<ICollection<TEntity>> FetchAsync(
Expression<Func<TEntity, bool>> predicate,
CancellationToken cancellationToken = default(CancellationToken))
{
return (ICollection<TEntity>)await EntityFrameworkQueryableExtensions.ToListAsync<TEntity>(((IQueryable<TEntity>)this.DbSet()).Where<TEntity>(predicate), cancellationToken);
}

/// <inheritdoc />
public virtual TEntity Find(params object[] keyValues) => this.DbSet().Find(keyValues);

/// <inheritdoc />
public virtual async Task<TEntity> FindAsync(params object[] keyValues)
{
return await this.DbSet().FindAsync(keyValues);
}

/// <inheritdoc />
public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate)
{
return ((IQueryable<TEntity>)this.DbSet()).FirstOrDefault<TEntity>(predicate);
}

/// <inheritdoc />
public virtual async Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate,
CancellationToken cancellationToken = default(CancellationToken))
{
return await EntityFrameworkQueryableExtensions.FirstOrDefaultAsync<TEntity>((IQueryable<TEntity>)this.DbSet(), predicate, cancellationToken);
}

/// <inheritdoc />
public virtual TEntity Get(params object[] keyValues)
{
return this.Find(keyValues) ?? throw new InvalidOperationException(string.Format("Entity type {0} is null for primary key {1}", (object)typeof(TEntity), (object)keyValues));
}

/// <inheritdoc />
public virtual async Task<TEntity> GetAsync(params object[] keyValues)
{
return await this.FindAsync(keyValues) ?? throw new InvalidOperationException(string.Format("Entity type {0} is null for primary key {1}", (object)typeof(TEntity), (object)keyValues));
}

/// <inheritdoc />
public virtual TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return ((IQueryable<TEntity>)this.DbSet()).Single<TEntity>(predicate);
}

/// <inheritdoc />
public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate)
{
return await EntityFrameworkQueryableExtensions.SingleAsync<TEntity>((IQueryable<TEntity>)this.DbSet(), predicate, new CancellationToken());
}

/// <inheritdoc />
public virtual TEntity Add(TEntity entity)
{
this.DbContext.Add<TEntity>(entity);
this.DbContext.SaveChanges();
return entity;
}

/// <inheritdoc />
public virtual async Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken))
{
EntityEntry<TEntity> entityEntry = await this.DbContext.AddAsync<TEntity>(entity, cancellationToken);
int num = await this.DbContext.SaveChangesAsync(cancellationToken);
return entity;
}

/// <inheritdoc />
public virtual IEnumerable<TEntity> AddRange(ICollection<TEntity> entities)
{
this.DbContext.AddRange((IEnumerable<object>)entities);
this.DbContext.SaveChanges();
return (IEnumerable<TEntity>)entities;
}

/// <inheritdoc />
public virtual async Task<IEnumerable<TEntity>> AddRangeAsync(
ICollection<TEntity> entities,
CancellationToken cancellationToken = default(CancellationToken))
{
await this.DbContext.AddRangeAsync((IEnumerable<object>)entities, cancellationToken);
int num = await this.DbContext.SaveChangesAsync(cancellationToken);
return (IEnumerable<TEntity>)entities;
}

/// <inheritdoc />
public virtual TEntity Remove(TEntity entity)
{
this.DbContext.Remove<TEntity>(entity);
this.DbContext.SaveChanges();
return entity;
}

/// <inheritdoc />
public virtual async Task<TEntity> RemoveAsync(
TEntity entity,
CancellationToken cancellationToken = default(CancellationToken))
{
this.DbContext.Remove<TEntity>(entity);
int num = await this.DbContext.SaveChangesAsync(cancellationToken);
return entity;
}

/// <inheritdoc />
public virtual int Delete(Expression<Func<TEntity, bool>> predicate)
{
return DbSet().Where(predicate).ExecuteDelete();
}

/// <inheritdoc />
public virtual IEnumerable<TEntity> RemoveRange(ICollection<TEntity> entities)
{
this.DbSet().RemoveRange((IEnumerable<TEntity>)entities);
this.DbContext.SaveChanges();
return (IEnumerable<TEntity>)entities;
}

/// <inheritdoc />
public virtual async Task<IEnumerable<TEntity>> RemoveRangeAsync(
ICollection<TEntity> entities,
CancellationToken cancellationToken = default(CancellationToken))
{
this.DbSet().RemoveRange((IEnumerable<TEntity>)entities);
int num = await this.DbContext.SaveChangesAsync(cancellationToken);
return (IEnumerable<TEntity>)entities;
}

/// <inheritdoc />
public virtual TEntity Update(TEntity entity)
{
this.DbContext.Update<TEntity>(entity);
this.DbContext.SaveChanges();
return entity;
}

/// <inheritdoc />
public virtual async Task<TEntity> UpdateAsync(
TEntity entity,
CancellationToken cancellationToken = default(CancellationToken))
{
this.DbContext.Update<TEntity>(entity);
int num = await this.DbContext.SaveChangesAsync(cancellationToken);
return entity;
}
}
}
Loading
Loading