Skip to content
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

fix: limit data model fetching to models folder #14625

Merged
merged 10 commits into from
Feb 13, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ public class AltinnAppGitRepository : AltinnGitRepository
private static string ProcessDefinitionFilePath => Path.Combine(ProcessDefinitionFolderPath, ProcessDefinitionFilename);

private const string LayoutSettingsSchemaUrl = "https://altinncdn.no/schemas/json/layout/layoutSettings.schema.v1.json";

private const string LayoutSchemaUrl = "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json";

private const string TextResourceFileNamePattern = "resource.??.json";
private const string SchemaFilePatternJson = "*.schema.json";
private const string SchemaFilePatternXsd = "*.xsd";

public static readonly string InitialLayoutFileName = "Side1.json";

Expand Down Expand Up @@ -976,6 +977,41 @@ public List<string> GetAllImageFileNames()
return allFilePaths;
}

/// <summary>
/// Finds all schema files in App/models directory.
/// </summary>
public IList<AltinnCoreFile> GetSchemaFiles(bool xsd = false)
{
string schemaFilesPattern = xsd ? SchemaFilePatternXsd : SchemaFilePatternJson;
string schemaFilesPath = Path.Combine(ModelFolderPath, schemaFilesPattern);
IEnumerable<string> schemaFiles;

try
{
schemaFiles = FindFiles(new[] { schemaFilesPath });
}
catch (DirectoryNotFoundException)
{
schemaFiles = new List<string>();
}

var altinnCoreSchemaFiles = MapFilesToAltinnCoreFiles(schemaFiles);

return altinnCoreSchemaFiles;
}

private List<AltinnCoreFile> MapFilesToAltinnCoreFiles(IEnumerable<string> schemaFiles)
{
List<AltinnCoreFile> altinnCoreSchemaFiles = new();

foreach (string file in schemaFiles)
{
altinnCoreSchemaFiles.Add(AltinnCoreFile.CreateFromPath(file, RepositoryDirectory));
}

return altinnCoreSchemaFiles;
}

/// <summary>
/// Gets the relative path to a json schema model.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -23,10 +22,7 @@ namespace Altinn.Studio.Designer.Infrastructure.GitRepository
/// and not any methods that are specific to App or Datamodels repositories.</remarks>
public class AltinnGitRepository : GitRepository, IAltinnGitRepository
{
private const string SCHEMA_FILES_PATTERN_JSON = "*.schema.json";
private const string SCHEMA_FILES_PATTERN_XSD = "*.xsd";
private const string STUDIO_SETTINGS_FILEPATH = ".altinnstudio/settings.json";
private const string TEXT_FILES_PATTERN_JSON = "*.texts.json";

private AltinnStudioSettings _altinnStudioSettings;

Expand Down Expand Up @@ -80,19 +76,6 @@ public async Task SaveAltinnStudioSettings(AltinnStudioSettings altinnStudioSett
await WriteObjectByRelativePathAsync(STUDIO_SETTINGS_FILEPATH, altinnStudioSettings, true);
}

/// <summary>
/// Finds all schema files regardless of location in repository.
/// </summary>
public IList<AltinnCoreFile> GetSchemaFiles(bool xsd = false)
{
string schemaFilesPattern = xsd ? SCHEMA_FILES_PATTERN_XSD : SCHEMA_FILES_PATTERN_JSON;
var schemaFiles = FindFiles(new[] { schemaFilesPattern });

var altinnCoreSchemaFiles = MapFilesToAltinnCoreFiles(schemaFiles);

return altinnCoreSchemaFiles;
}

/// <summary>
/// Parses the filename and extracts the logical schema name.
/// </summary>
Expand Down Expand Up @@ -242,17 +225,5 @@ private bool IsDatamodelsRepo()
{
return Repository.Contains("-datamodels");
}

private List<AltinnCoreFile> MapFilesToAltinnCoreFiles(IEnumerable<string> schemaFiles)
{
List<AltinnCoreFile> altinnCoreSchemaFiles = new();

foreach (string file in schemaFiles)
{
altinnCoreSchemaFiles.Add(AltinnCoreFile.CreateFromPath(file, RepositoryDirectory));
}

return altinnCoreSchemaFiles;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ public SchemaModelService(
/// <inheritdoc/>
public IList<AltinnCoreFile> GetSchemaFiles(AltinnRepoEditingContext altinnRepoEditingContext, bool xsd = false)
{
var altinnGitRepository = _altinnGitRepositoryFactory.GetAltinnGitRepository(altinnRepoEditingContext.Org, altinnRepoEditingContext.Repo, altinnRepoEditingContext.Developer);
var altinnAppGitRepository = _altinnGitRepositoryFactory.GetAltinnAppGitRepository(altinnRepoEditingContext.Org, altinnRepoEditingContext.Repo, altinnRepoEditingContext.Developer);

return altinnGitRepository.GetSchemaFiles(xsd);
return altinnAppGitRepository.GetSchemaFiles(xsd);
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,54 @@ public async Task CreateOrOverwriteOptions_WithAppThatHasOptionLists_ShouldOverw
Assert.Equal(newOptionsListString, savedOptionsList);
}

[Theory]
[InlineData("ttd", "apps-test", "testUser", 0)]
[InlineData("ttd", "ttd-datamodels", "testUser", 0)]
[InlineData("ttd", "hvem-er-hvem", "testUser", 7)]
public async Task GetSchemaFiles_FilesExist_ShouldReturnFiles(string org, string repository, string developer, int expectedSchemaFiles)
{
string targetRepository = TestDataHelper.GenerateTestRepoName();
await TestDataHelper.CopyRepositoryForTest(org, repository, developer, targetRepository);
AltinnAppGitRepository altinnAppGitRepository = PrepareRepositoryForTest(org, targetRepository, developer);

var files = altinnAppGitRepository.GetSchemaFiles();

Assert.Equal(expectedSchemaFiles, files.Count);
}

[Fact]
public async Task GetSchemaFiles_FilesExist_ShouldReturnFilesWithCorrectProperties()
{
string org = "ttd";
string repository = "hvem-er-hvem";
string developer = "testUser";
string targetRepository = TestDataHelper.GenerateTestRepoName();

await TestDataHelper.CopyRepositoryForTest(org, repository, developer, targetRepository);
AltinnAppGitRepository altinnAppGitRepository = PrepareRepositoryForTest(org, targetRepository, developer);

var file = altinnAppGitRepository.GetSchemaFiles().First(f => f.FileName == "HvemErHvem_ExternalTypes.schema.json");

Assert.Equal(".json", file.FileType);
Assert.Equal(@"/App/models/HvemErHvem_ExternalTypes.schema.json", file.RepositoryRelativeUrl);
}

[Fact]
public async Task GetSchemaFiles_FilesExistOutsideModelsFolder_ShouldNotReturnFiles()
{
string org = "ttd";
string repository = "app-with-misplaced-datamodels";
string developer = "testUser";
string targetRepository = TestDataHelper.GenerateTestRepoName();

await TestDataHelper.CopyRepositoryForTest(org, repository, developer, targetRepository);
AltinnAppGitRepository altinnAppGitRepository = PrepareRepositoryForTest(org, targetRepository, developer);

var files = altinnAppGitRepository.GetSchemaFiles();

Assert.Empty(files);
}

private static AltinnAppGitRepository PrepareRepositoryForTest(string org, string repository, string developer)
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,6 @@ public void Constructor_InvalidPathParameters_ShouldThrowException()
Assert.Throws<ArgumentException>(() => new AltinnGitRepository("ttd", "hvem-er-hvem", "testUser", repositoriesRootDirectory, repositoryDirectory));
}

[Theory]
[InlineData("ttd", "apps-test", "testUser", 0)]
[InlineData("ttd", "ttd-datamodels", "testUser", 0)]
[InlineData("ttd", "hvem-er-hvem", "testUser", 7)]
public void GetSchemaFiles_FilesExist_ShouldReturnFiles(string org, string repository, string developer, int expectedSchemaFiles)
{
var repositoriesRootDirectory = TestDataHelper.GetTestDataRepositoriesRootDirectory();
var altinnGitRepositoryFactory = new AltinnGitRepositoryFactory(repositoriesRootDirectory);

var altinnGitRepository = altinnGitRepositoryFactory.GetAltinnGitRepository(org, repository, developer);
var files = altinnGitRepository.GetSchemaFiles();

Assert.Equal(expectedSchemaFiles, files.Count);
}

[Fact]
public void GetSchemaFiles_FilesExist_ShouldReturnFilesWithCorrectProperties()
{
var altinnGitRepository = GetTestRepository("ttd", "hvem-er-hvem", "testUser");
var file = altinnGitRepository.GetSchemaFiles().First(f => f.FileName == "HvemErHvem_ExternalTypes.schema.json");

Assert.Equal(".json", file.FileType);
Assert.Equal(@"/App/models/HvemErHvem_ExternalTypes.schema.json", file.RepositoryRelativeUrl);
}

[Fact]
public async Task RepositoryType_SettingsExists_ShouldUseThat()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public async Task DeleteSchema_ModelsRepo_ShouldDelete()
{
// Arrange
var org = "ttd";
var sourceRepository = "xyz-datamodels";
var sourceRepository = "hvem-er-hvem";
var developer = "testUser";
var targetRepository = TestDataHelper.GenerateTestRepoName();
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, targetRepository, developer);
Expand All @@ -125,15 +125,15 @@ public async Task DeleteSchema_ModelsRepo_ShouldDelete()
{

var schemaFiles = _schemaModelService.GetSchemaFiles(editingContext);
Assert.Equal(6, schemaFiles.Count);
Assert.Equal(7, schemaFiles.Count);

// Act
var schemaToDelete = schemaFiles.First(s => s.FileName == "Kursdomene_HvemErHvem_M_2021-04-08_5742_34627_SERES.schema.json");
await _schemaModelService.DeleteSchema(editingContext, schemaToDelete.RepositoryRelativeUrl);

// Assert
schemaFiles = _schemaModelService.GetSchemaFiles(editingContext);
Assert.Equal(5, schemaFiles.Count);
Assert.Equal(6, schemaFiles.Count);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"repotype": "datamodels",
"datamodelling.preference": "jsonSchema"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://altinn-repositories:3000/bjosttveit/v4-data/App/models/model.schema.json",
"info": {
"rootNode": ""
},
"@xsdNamespaces": {
"xsd": "http://www.w3.org/2001/XMLSchema",
"xsi": "http://www.w3.org/2001/XMLSchema-instance",
"seres": "http://seres.no/xsd/forvaltningsdata"
},
"@xsdSchemaAttributes": {
"AttributeFormDefault": "Unqualified",
"ElementFormDefault": "Qualified",
"BlockDefault": "None",
"FinalDefault": "None"
},
"@xsdRootElement": "model",
"type": "object",
"required": [
"property1",
"property2"
],
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
},
"property3": {
"type": "string"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:seres="http://seres.no/xsd/forvaltningsdata" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation>
<xsd:attribute name="rootNode" fixed="" />
</xs:documentation>
</xs:annotation>
<xs:element name="model">
<xs:complexType>
<xs:sequence>
<xs:element name="property1" type="xs:string" />
<xs:element name="property2" type="xs:string" />
<xs:element minOccurs="0" name="property3" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xsd:schema>