From 02be152cf3a91420a53310b064edbd385a7ed8d8 Mon Sep 17 00:00:00 2001 From: Mathieu Guindon Date: Fri, 18 Apr 2025 12:37:38 -0400 Subject: [PATCH 1/3] tweak cors --- rubberduckvba.Server/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/rubberduckvba.Server/Program.cs b/rubberduckvba.Server/Program.cs index 2e204e6..7ac1d3d 100644 --- a/rubberduckvba.Server/Program.cs +++ b/rubberduckvba.Server/Program.cs @@ -51,6 +51,7 @@ public static void Main(string[] args) { policy .SetIsOriginAllowed(origin => true) + .AllowAnyOrigin() .AllowAnyHeader() .WithMethods("OPTIONS", "GET", "POST") .AllowCredentials() From a2deed7f29c7e3b771e86e103518ab9ba0e93a22 Mon Sep 17 00:00:00 2001 From: Mathieu Guindon Date: Fri, 18 Apr 2025 12:40:57 -0400 Subject: [PATCH 2/3] cors tweaks --- rubberduckvba.Server/Api/Admin/AdminController.cs | 1 + rubberduckvba.Server/Api/Auth/AuthController.cs | 1 + rubberduckvba.Server/Program.cs | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rubberduckvba.Server/Api/Admin/AdminController.cs b/rubberduckvba.Server/Api/Admin/AdminController.cs index 9cb8ed6..64b6397 100644 --- a/rubberduckvba.Server/Api/Admin/AdminController.cs +++ b/rubberduckvba.Server/Api/Admin/AdminController.cs @@ -46,6 +46,7 @@ public IActionResult ClearCache() } #if DEBUG + [EnableCors("CorsPolicy")] [HttpGet("admin/config/current")] public IActionResult Config() { diff --git a/rubberduckvba.Server/Api/Auth/AuthController.cs b/rubberduckvba.Server/Api/Auth/AuthController.cs index 92247ab..5c0d87e 100644 --- a/rubberduckvba.Server/Api/Auth/AuthController.cs +++ b/rubberduckvba.Server/Api/Auth/AuthController.cs @@ -37,6 +37,7 @@ public AuthController(IOptions configuration, IOptions true) - .AllowAnyOrigin() .AllowAnyHeader() .WithMethods("OPTIONS", "GET", "POST") .AllowCredentials() From facc139b4ee09ab0406106dd0c1cb4b83e0f9b05 Mon Sep 17 00:00:00 2001 From: Mathieu Guindon Date: Mon, 2 Jun 2025 12:11:03 -0400 Subject: [PATCH 3/3] fix cache validation bug, inspection/quickfix viewmodels --- .../Api/Admin/AdminController.cs | 10 ++-- .../Api/Admin/WebhookController.cs | 2 +- .../Api/Auth/AuthController.cs | 6 +-- .../Api/Downloads/DownloadsController.cs | 2 + .../Api/Features/FeatureViewModel.cs | 10 ++-- .../Api/Features/FeaturesController.cs | 13 +++++- .../Api/Indenter/IndenterController.cs | 2 + .../Api/Tags/TagsController.cs | 3 +- .../Pipeline/Sections/Context/SyncContext.cs | 1 - .../GitHubAuthenticationHandler.cs | 4 +- rubberduckvba.Server/Program.cs | 19 +++++++- rubberduckvba.Server/Services/CacheService.cs | 12 ++--- rubberduckvba.client/src/app/app.module.ts | 9 ++-- .../auth-menu/auth-menu.component.html | 2 +- .../auth-menu/auth-menu.component.ts | 1 - .../feature-info/feature-info.component.html | 6 +-- .../feature-info/feature-info.component.ts | 11 ----- .../inspection-item-box.component.html | 6 +-- .../inspection-item-box.component.ts | 46 ++++--------------- .../src/app/model/feature.model.ts | 4 +- .../inspection/inspection.component.html | 13 +++--- .../routes/inspection/inspection.component.ts | 5 +- .../src/app/services/auth.service.ts | 15 ++++-- .../src/app/services/data.service.ts | 5 +- .../src/environments/environment.test.ts | 4 +- 25 files changed, 104 insertions(+), 107 deletions(-) diff --git a/rubberduckvba.Server/Api/Admin/AdminController.cs b/rubberduckvba.Server/Api/Admin/AdminController.cs index 64b6397..c478ca3 100644 --- a/rubberduckvba.Server/Api/Admin/AdminController.cs +++ b/rubberduckvba.Server/Api/Admin/AdminController.cs @@ -6,7 +6,6 @@ namespace rubberduckvba.Server.Api.Admin; - [ApiController] public class AdminController(ConfigurationOptions options, HangfireLauncherService hangfire, CacheService cache) : ControllerBase { @@ -15,7 +14,7 @@ public class AdminController(ConfigurationOptions options, HangfireLauncherServi /// /// The unique identifier of the enqueued job. [Authorize("github")] - [EnableCors("CorsPolicy")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [HttpPost("admin/update/xmldoc")] public IActionResult UpdateXmldocContent() { @@ -28,7 +27,7 @@ public IActionResult UpdateXmldocContent() /// /// The unique identifier of the enqueued job. [Authorize("github")] - [EnableCors("CorsPolicy")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [HttpPost("admin/update/tags")] public IActionResult UpdateTagMetadata() { @@ -37,7 +36,7 @@ public IActionResult UpdateTagMetadata() } [Authorize("github")] - [EnableCors("CorsPolicy")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [HttpPost("admin/cache/clear")] public IActionResult ClearCache() { @@ -46,7 +45,8 @@ public IActionResult ClearCache() } #if DEBUG - [EnableCors("CorsPolicy")] + [AllowAnonymous] + [EnableCors(CorsPolicies.AllowAll)] [HttpGet("admin/config/current")] public IActionResult Config() { diff --git a/rubberduckvba.Server/Api/Admin/WebhookController.cs b/rubberduckvba.Server/Api/Admin/WebhookController.cs index 6ded8a6..94cf711 100644 --- a/rubberduckvba.Server/Api/Admin/WebhookController.cs +++ b/rubberduckvba.Server/Api/Admin/WebhookController.cs @@ -22,7 +22,7 @@ public WebhookController( } [Authorize("webhook")] - [EnableCors("webhookPolicy")] + [EnableCors(CorsPolicies.AllowAll)] [HttpPost("webhook/github")] public async Task GitHub([FromBody] dynamic body) => GuardInternalAction(() => diff --git a/rubberduckvba.Server/Api/Auth/AuthController.cs b/rubberduckvba.Server/Api/Auth/AuthController.cs index 5c0d87e..31f50b6 100644 --- a/rubberduckvba.Server/Api/Auth/AuthController.cs +++ b/rubberduckvba.Server/Api/Auth/AuthController.cs @@ -37,7 +37,7 @@ public AuthController(IOptions configuration, IOptions tagsByAssetId) + public InspectionViewModel(Inspection model, IEnumerable quickFixes, IDictionary tagsByAssetId) { Id = model.Id; DateTimeInserted = model.DateTimeInserted; @@ -78,7 +78,7 @@ public InspectionViewModel(Inspection model, IDictionary tagsByAssetId InspectionType = model.InspectionType; DefaultSeverity = model.DefaultSeverity; - QuickFixes = model.QuickFixes; + QuickFixes = quickFixes.Where(e => model.QuickFixes.Any(name => string.Equals(e.Name, name, StringComparison.InvariantCultureIgnoreCase))).ToArray(); Reasoning = model.Reasoning; HostApp = model.HostApp; @@ -110,7 +110,7 @@ public InspectionViewModel(Inspection model, IDictionary tagsByAssetId public string? Remarks { get; init; } public string? HostApp { get; init; } public string[] References { get; init; } = []; - public string[] QuickFixes { get; init; } = []; + public QuickFixViewModel[] QuickFixes { get; init; } = []; public InspectionExample[] Examples { get; init; } = []; } @@ -239,11 +239,11 @@ public record class QuickFixInspectionLinkViewModel public class InspectionsFeatureViewModel : FeatureViewModel { - public InspectionsFeatureViewModel(FeatureGraph model, IDictionary tagsByAssetId, bool summaryOnly = false) + public InspectionsFeatureViewModel(FeatureGraph model, IEnumerable quickFixes, IDictionary tagsByAssetId, bool summaryOnly = false) : base(model, summaryOnly) { - Inspections = model.Inspections.OrderBy(e => e.Name).Select(e => new InspectionViewModel(e, tagsByAssetId)).ToArray(); + Inspections = model.Inspections.OrderBy(e => e.Name).Select(e => new InspectionViewModel(e, quickFixes, tagsByAssetId)).ToArray(); } public InspectionViewModel[] Inspections { get; init; } = []; diff --git a/rubberduckvba.Server/Api/Features/FeaturesController.cs b/rubberduckvba.Server/Api/Features/FeaturesController.cs index 8c87349..6868419 100644 --- a/rubberduckvba.Server/Api/Features/FeaturesController.cs +++ b/rubberduckvba.Server/Api/Features/FeaturesController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using rubberduckvba.Server.Data; using rubberduckvba.Server.Model; @@ -37,6 +38,7 @@ await db.GetTopLevelFeatures(repositoryId) .ContinueWith(t => t.Result.Select(e => new FeatureOptionViewModel { Id = e.Id, Name = e.Name, Title = e.Title }).ToArray()); [HttpGet("features")] + [EnableCors(CorsPolicies.AllowAll)] [AllowAnonymous] public IActionResult Index() { @@ -66,6 +68,7 @@ public IActionResult Index() } [HttpGet("features/{name}")] + [EnableCors(CorsPolicies.AllowAll)] [AllowAnonymous] public IActionResult Info([FromRoute] string name) { @@ -82,6 +85,7 @@ public IActionResult Info([FromRoute] string name) } [HttpGet("inspections/{name}")] + [EnableCors(CorsPolicies.AllowAll)] [AllowAnonymous] public IActionResult Inspection([FromRoute] string name) { @@ -103,6 +107,7 @@ public IActionResult Inspection([FromRoute] string name) } [HttpGet("annotations/{name}")] + [EnableCors(CorsPolicies.AllowAll)] [AllowAnonymous] public IActionResult Annotation([FromRoute] string name) { @@ -124,6 +129,7 @@ public IActionResult Annotation([FromRoute] string name) } [HttpGet("quickfixes/{name}")] + [EnableCors(CorsPolicies.AllowAll)] [AllowAnonymous] public IActionResult QuickFix([FromRoute] string name) { @@ -145,6 +151,7 @@ public IActionResult QuickFix([FromRoute] string name) } [HttpGet("features/create")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [Authorize("github")] public async Task> Create([FromQuery] RepositoryId repository = RepositoryId.Rubberduck, [FromQuery] int? parentId = default) { @@ -156,6 +163,7 @@ public async Task> Create([FromQuery] Reposit } [HttpPost("create")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [Authorize("github")] public async Task> Create([FromBody] FeatureEditViewModel model) { @@ -178,6 +186,7 @@ public async Task> Create([FromBody] FeatureE } [HttpPost("features/update")] + [EnableCors(CorsPolicies.AllowAuthenticated)] [Authorize("github")] public async Task> Update([FromBody] FeatureEditViewModel model) { @@ -203,8 +212,10 @@ private InspectionsFeatureViewModel GetInspections() InspectionsFeatureViewModel result; if (!cache.TryGetInspections(out result!)) { + var quickfixesModel = GetQuickFixes(); + var feature = features.Get("Inspections") as FeatureGraph; - result = new InspectionsFeatureViewModel(feature, + result = new InspectionsFeatureViewModel(feature, quickfixesModel.QuickFixes, feature.Inspections .Select(e => e.TagAssetId).Distinct() .ToDictionary(id => id, id => new Tag(tagsRepository.GetById(assetsRepository.GetById(id).TagId)))); diff --git a/rubberduckvba.Server/Api/Indenter/IndenterController.cs b/rubberduckvba.Server/Api/Indenter/IndenterController.cs index 80f59b4..11a9eed 100644 --- a/rubberduckvba.Server/Api/Indenter/IndenterController.cs +++ b/rubberduckvba.Server/Api/Indenter/IndenterController.cs @@ -1,10 +1,12 @@ using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using RubberduckServices; namespace rubberduckvba.Server.Api.Indenter; [AllowAnonymous] +[EnableCors(CorsPolicies.AllowAll)] public class IndenterController : RubberduckApiController { private readonly IIndenterService service; diff --git a/rubberduckvba.Server/Api/Tags/TagsController.cs b/rubberduckvba.Server/Api/Tags/TagsController.cs index 13ef731..84c0584 100644 --- a/rubberduckvba.Server/Api/Tags/TagsController.cs +++ b/rubberduckvba.Server/Api/Tags/TagsController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using rubberduckvba.Server.Services; @@ -6,6 +7,7 @@ namespace rubberduckvba.Server.Api.Tags; [AllowAnonymous] +[EnableCors(CorsPolicies.AllowAll)] public class TagsController : RubberduckApiController { private readonly CacheService cache; @@ -23,7 +25,6 @@ public TagsController(CacheService cache, IRubberduckDbService db, ILogger [HttpGet("api/v1/public/tags")] // legacy route [HttpGet("tags/latest")] - [AllowAnonymous] public IActionResult Latest() { return GuardInternalAction(() => diff --git a/rubberduckvba.Server/ContentSynchronization/Pipeline/Sections/Context/SyncContext.cs b/rubberduckvba.Server/ContentSynchronization/Pipeline/Sections/Context/SyncContext.cs index bb6773b..ee71d83 100644 --- a/rubberduckvba.Server/ContentSynchronization/Pipeline/Sections/Context/SyncContext.cs +++ b/rubberduckvba.Server/ContentSynchronization/Pipeline/Sections/Context/SyncContext.cs @@ -21,7 +21,6 @@ public SyncContext(IRequestParameters parameters) IRequestParameters IPipelineContext.Parameters => Parameters; public void LoadParameters(SyncRequestParameters parameters) { - InvalidContextParameterException.ThrowIfNull(nameof(parameters), parameters); _parameters = parameters; _staging = new StagingContext(parameters); } diff --git a/rubberduckvba.Server/GitHubAuthenticationHandler.cs b/rubberduckvba.Server/GitHubAuthenticationHandler.cs index 3de2c45..51ee239 100644 --- a/rubberduckvba.Server/GitHubAuthenticationHandler.cs +++ b/rubberduckvba.Server/GitHubAuthenticationHandler.cs @@ -25,7 +25,7 @@ protected async override Task HandleAuthenticateAsync() var token = Context.Request.Headers["X-ACCESS-TOKEN"].SingleOrDefault(); if (string.IsNullOrWhiteSpace(token)) { - return AuthenticateResult.NoResult(); + return AuthenticateResult.Fail("Access token was not provided"); } var principal = await _github.ValidateTokenAsync(token); @@ -36,7 +36,7 @@ protected async override Task HandleAuthenticateAsync() return AuthenticateResult.Success(new AuthenticationTicket(principal, "github")); } - return AuthenticateResult.NoResult(); + return AuthenticateResult.Fail("An invalid access token was provided"); } catch (InvalidOperationException e) { diff --git a/rubberduckvba.Server/Program.cs b/rubberduckvba.Server/Program.cs index 2e204e6..05feb62 100644 --- a/rubberduckvba.Server/Program.cs +++ b/rubberduckvba.Server/Program.cs @@ -32,6 +32,12 @@ public class HangfireAuthenticationFilter : IDashboardAuthorizationFilter public bool Authorize([NotNull] DashboardContext context) => Debugger.IsAttached || context.Request.RemoteIpAddress == "20.220.30.154"; } +public static class CorsPolicies +{ + public const string AllowAll = "AllowAll"; + public const string AllowAuthenticated = "AllowAuthenticated"; +} + public class Program { public static void Main(string[] args) @@ -47,12 +53,20 @@ public static void Main(string[] args) builder.Services.AddCors(builder => { - builder.AddPolicy("CorsPolicy", policy => + builder.AddPolicy(CorsPolicies.AllowAll, policy => { policy .SetIsOriginAllowed(origin => true) .AllowAnyHeader() .WithMethods("OPTIONS", "GET", "POST") + .Build(); + }); + builder.AddPolicy(CorsPolicies.AllowAuthenticated, policy => + { + policy + .SetIsOriginAllowed(origin => true) + .WithHeaders("X-ACCESS-TOKEN") + .WithMethods("OPTIONS", "GET", "POST") .AllowCredentials() .Build(); }); @@ -105,6 +119,7 @@ public static void Main(string[] args) app.UseRouting(); app.UseCors(); + app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); @@ -118,7 +133,7 @@ public static void Main(string[] args) var hangfireOptions = app.Services.GetService>()?.Value ?? new(); new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions { - Delay = TimeSpan.FromSeconds(10), + Delay = TimeSpan.FromSeconds(30), MaxRetryAttempts = hangfireOptions.MaxInitializationAttempts, OnRetry = (context) => { diff --git a/rubberduckvba.Server/Services/CacheService.cs b/rubberduckvba.Server/Services/CacheService.cs index 40a82be..6c56254 100644 --- a/rubberduckvba.Server/Services/CacheService.cs +++ b/rubberduckvba.Server/Services/CacheService.cs @@ -104,7 +104,7 @@ public void Invalidate(FeatureViewModel[] newContent) public void Invalidate(InspectionsFeatureViewModel newContent) { GetCurrentJobState(); - if (XmldocJobState?.StateName == JobStateSucceeded) + if (!TryReadXmldocCache("inspections", out _) || XmldocJobState?.StateName == JobStateSucceeded) { Write("inspections", newContent); foreach (var item in newContent.Inspections) @@ -171,10 +171,10 @@ private bool IsCacheValid(HangfireJobState? initial, Func get GetCurrentJobState(); var current = getCurrent.Invoke(); - return current != null // no job state -> no valid cache - && current.StateName == JobStateSucceeded // last executed job must have succeeded + return current is null + || (current.StateName == JobStateSucceeded // last executed job must have succeeded && current.LastJobId == initial?.LastJobId // last executed job must be the same job ID we know about - && current.StateTimestamp == initial?.StateTimestamp; // same execution -> cache was not invalidated + && current.StateTimestamp == initial?.StateTimestamp); // same execution -> cache was not invalidated } private void Write(string key, T value) @@ -185,7 +185,7 @@ private void Write(string key, T value) private bool TryReadFromTagsCache(string key, out T? cached) { - var result = _cache.TryGetValue(key, out cached) && IsTagsCacheValid(); + var result = _cache.TryGetValue(key, out cached); _logger.LogDebug("TagsCache hit: '{key}' (valid: {result})", key, result); return result; @@ -193,7 +193,7 @@ private bool TryReadFromTagsCache(string key, out T? cached) private bool TryReadXmldocCache(string key, out T? cached) { - var result = _cache.TryGetValue(key, out cached) && IsXmldocCacheValid(); + var result = _cache.TryGetValue(key, out cached); _logger.LogDebug("XmldocCache hit: '{key}' (valid: {result})", key, result); return result; diff --git a/rubberduckvba.client/src/app/app.module.ts b/rubberduckvba.client/src/app/app.module.ts index 1c4f01b..86f5ce9 100644 --- a/rubberduckvba.client/src/app/app.module.ts +++ b/rubberduckvba.client/src/app/app.module.ts @@ -86,17 +86,18 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { BrowserModule, FormsModule, RouterModule.forRoot([ - { path: '', component: HomeComponent, pathMatch: 'full' }, + // legacy routes: + { path: 'inspections/details/:name', redirectTo: 'inspections/:name' }, + // actual routes: + { path: 'auth/github', component: AuthComponent }, { path: 'features', component: FeaturesComponent }, { path: 'features/:name', component: FeatureComponent }, { path: 'inspections/:name', component: InspectionComponent }, { path: 'annotations/:name', component: AnnotationComponent }, { path: 'quickfixes/:name', component: QuickFixComponent }, { path: 'about', component: AboutComponent }, - { path: 'auth/github', component: AuthComponent }, { path: 'indenter', component: IndenterComponent }, - // legacy routes: - { path: 'inspections/details/:name', redirectTo: 'inspections/:name' }, + { path: '', component: HomeComponent, pathMatch: 'full' }, ]), FontAwesomeModule, NgbModule diff --git a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.html b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.html index ca5cf7f..1f6b45b 100644 --- a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.html +++ b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.html @@ -55,7 +55,7 @@
Res diff --git a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts index 2739df8..0411a94 100644 --- a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts +++ b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts @@ -64,7 +64,6 @@ export class AuthMenuComponent implements OnInit { public signin(): void { this.auth.signin(); - this.getUserInfo(); } public signout(): void { diff --git a/rubberduckvba.client/src/app/components/feature-info/feature-info.component.html b/rubberduckvba.client/src/app/components/feature-info/feature-info.component.html index 91ef7ab..7e4620a 100644 --- a/rubberduckvba.client/src/app/components/feature-info/feature-info.component.html +++ b/rubberduckvba.client/src/app/components/feature-info/feature-info.component.html @@ -10,7 +10,7 @@

{{feature?.title}}

- +
@@ -35,7 +35,7 @@

{{feature?.title}}

- +
@@ -84,7 +84,7 @@
Search
- +
diff --git a/rubberduckvba.client/src/app/components/feature-info/feature-info.component.ts b/rubberduckvba.client/src/app/components/feature-info/feature-info.component.ts index 79bfbb8..1c51009 100644 --- a/rubberduckvba.client/src/app/components/feature-info/feature-info.component.ts +++ b/rubberduckvba.client/src/app/components/feature-info/feature-info.component.ts @@ -63,17 +63,6 @@ export class FeatureInfoComponent implements OnInit, OnChanges { return (this.feature as FeatureViewModel)?.features ?? []; } - @Input() - public set quickFixes(value: QuickFixViewModel[]) { - if (value != null) { - this._quickfixes.next(value); - } - } - - public get quickFixes(): QuickFixViewModel[] { - return this._quickfixes.value; - } - public get links(): BlogLink[] { let feature = this.feature; return feature?.links ?? []; diff --git a/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.html b/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.html index 0cbab67..961f67d 100644 --- a/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.html +++ b/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.html @@ -91,10 +91,10 @@

This inspection offers the following fixes:

  • - +
    -
     {{fix.replace('QuickFix','')}}
    -

    +
     {{fix.name}}
    +

  • diff --git a/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.ts b/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.ts index 5333d7e..352852e 100644 --- a/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.ts +++ b/rubberduckvba.client/src/app/components/feature-item-box/inspection-item-box/inspection-item-box.component.ts @@ -4,6 +4,7 @@ import { BehaviorSubject } from 'rxjs'; import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { fas } from '@fortawesome/free-solid-svg-icons'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ApiClientService } from '../../../services/api-client.service'; @Component({ selector: 'inspection-item-box', @@ -14,10 +15,9 @@ export class InspectionItemBoxComponent implements OnInit, OnChanges { private readonly _info: BehaviorSubject = new BehaviorSubject(null!); private readonly _inspectionInfo: BehaviorSubject = new BehaviorSubject(null!); - private readonly _quickfixes: BehaviorSubject = new BehaviorSubject(null!); - private _quickfixMap: Map = null!; + private quickFixVM: QuickFixViewModel = null!; - constructor(private fa: FaIconLibrary) { + constructor(private fa: FaIconLibrary, private api: ApiClientService) { fa.addIconPacks(fas); } @@ -31,32 +31,11 @@ export class InspectionItemBoxComponent implements OnInit, OnChanges { @ViewChild('content', { read: TemplateRef }) content: TemplateRef | undefined; public modal = inject(NgbModal); - public quickFixVM: QuickFixViewModel = null!; - - - @Input() - public set quickFixes(value: any[]) { - if (value != null) { - this._quickfixes.next(value); - this._quickfixMap = new Map(this._quickfixes.value.map(e => [e.name, this.getQuickFixItem(e)])); - } - } - - private getQuickFixItem(item: QuickFixViewModel): QuickFixViewModel { - item.title = item.name.replace('QuickFix', ''); - - return item; - } - - public get quickFixes(): QuickFixViewModel[] { - return this._quickfixes.value; - } @Input() public set item(value: XmlDocItemViewModel) { if (value != null) { this._info.next(value); - this._inspectionInfo.next(value as InspectionViewModel); } } @@ -65,27 +44,18 @@ export class InspectionItemBoxComponent implements OnInit, OnChanges { return this._info.value; } - public getQuickFix(name: string): QuickFixViewModel { - if (this._quickfixMap) { - return this._quickfixMap.get(name)!; - } - return null!; - } - public showDetailsModal(): void { - console.log(`Showing details for inspection: ${this.inspectionInfo.name}`); - this.modal.open(this.inspectionDetails); + this.api.getInspection(this.inspectionInfo.name).subscribe((inspection: InspectionViewModel) => { + this._inspectionInfo.next(inspection); + this.modal.open(this.inspectionDetails); + }); } public showQuickFixModal(name: string): void { - this.quickFixVM = this.getQuickFix(name); + this.quickFixVM = this.inspectionInfo.quickFixes.find(e => e.title == name)!; this.modal.open(this.content) } - public getQuickFixSummary(name: string): string { - return this.getQuickFix(name).summary; - } - isInspectionInfo: boolean = false; public get inspectionInfo(): InspectionViewModel { return this._inspectionInfo.value; diff --git a/rubberduckvba.client/src/app/model/feature.model.ts b/rubberduckvba.client/src/app/model/feature.model.ts index ae65f33..97a0534 100644 --- a/rubberduckvba.client/src/app/model/feature.model.ts +++ b/rubberduckvba.client/src/app/model/feature.model.ts @@ -108,7 +108,7 @@ export interface InspectionViewModel extends XmlDocViewModel { hostApp?: string; references: string[]; - quickFixes: string[]; + quickFixes: QuickFixViewModel[]; examples: InspectionExample[]; @@ -280,7 +280,7 @@ export class InspectionViewModelClass extends SubFeatureViewModelClass implement remarks?: string | undefined; hostApp?: string | undefined; references: string[]; - quickFixes: string[]; + quickFixes: QuickFixViewModel[]; examples: InspectionExample[]; tagAssetId: number; tagName: string; diff --git a/rubberduckvba.client/src/app/routes/inspection/inspection.component.html b/rubberduckvba.client/src/app/routes/inspection/inspection.component.html index 3aef04e..ec35b07 100644 --- a/rubberduckvba.client/src/app/routes/inspection/inspection.component.html +++ b/rubberduckvba.client/src/app/routes/inspection/inspection.component.html @@ -1,6 +1,7 @@

    HomeFeaturesCodeInspectionsInspections

    -

    {{info.title}}

    -
    +

    {{info.title}}

    +

    +
    @@ -29,8 +30,8 @@
    +
    -

    @@ -67,10 +68,10 @@

    This inspection offers the following fixes:

    • - +
      -
       {{fix.replace('QuickFix','')}}
      - +
       {{fix.name}}
      +

      {{fix.summary}}

    • diff --git a/rubberduckvba.client/src/app/routes/inspection/inspection.component.ts b/rubberduckvba.client/src/app/routes/inspection/inspection.component.ts index e6fa44b..796e195 100644 --- a/rubberduckvba.client/src/app/routes/inspection/inspection.component.ts +++ b/rubberduckvba.client/src/app/routes/inspection/inspection.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from "@angular/core"; import { InspectionViewModel } from "../../model/feature.model"; -import { ActivatedRoute } from "@angular/router"; +import { ActivatedRoute, Router } from "@angular/router"; import { FaIconLibrary } from "@fortawesome/angular-fontawesome"; import { fas } from "@fortawesome/free-solid-svg-icons"; import { BehaviorSubject, switchMap } from "rxjs"; @@ -21,7 +21,7 @@ export class InspectionComponent implements OnInit { return this._info.getValue(); } - constructor(private api: ApiClientService, private fa: FaIconLibrary, private route: ActivatedRoute) { + constructor(private api: ApiClientService, private fa: FaIconLibrary, private route: ActivatedRoute, private router: Router) { fa.addIconPacks(fas); } @@ -31,6 +31,7 @@ export class InspectionComponent implements OnInit { const name = params.get('name')!; return this.api.getInspection(name); })).subscribe(e => { + console.log(e); this.info = e; }); } diff --git a/rubberduckvba.client/src/app/services/auth.service.ts b/rubberduckvba.client/src/app/services/auth.service.ts index db807a2..fc0c3da 100644 --- a/rubberduckvba.client/src/app/services/auth.service.ts +++ b/rubberduckvba.client/src/app/services/auth.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Observable } from "rxjs"; +import { Observable, map } from "rxjs"; import { environment } from "../../environments/environment"; import { UserViewModel } from "../model/feature.model"; import { AuthViewModel, DataService } from "./data.service"; @@ -14,6 +14,11 @@ export class AuthService { return new Promise(resolve => setTimeout(resolve, ms)); } + private redirect(url: string = '/'): void { + console.log(`redirecting: ${url}`); + window.location.href = url; + } + private writeStorage(key: string, value: string): void { sessionStorage.setItem(key, value); while (sessionStorage.getItem(key) != value) { @@ -32,7 +37,7 @@ export class AuthService { const url = `${environment.apiBaseUrl}auth/signin`; this.data.postAsync(url, vm) - .subscribe(redirectUrl => location.href = redirectUrl); + .subscribe((result: string) => this.redirect(result)); } public signout(): void { @@ -52,17 +57,17 @@ export class AuthService { this.data.postAsync(url, vm) .subscribe(result => { this.writeStorage('github:access_token', result.token!); - location.href = '/'; + this.redirect(); }); } catch (error) { console.log(error); - location.href = '/'; + this.redirect(); } } else { console.log('xsrf:state mismatched!'); - location.href = '/'; + this.redirect(); } } } diff --git a/rubberduckvba.client/src/app/services/data.service.ts b/rubberduckvba.client/src/app/services/data.service.ts index 4b1f094..c66a376 100644 --- a/rubberduckvba.client/src/app/services/data.service.ts +++ b/rubberduckvba.client/src/app/services/data.service.ts @@ -36,6 +36,7 @@ export class DataService { .append('Access-Control-Allow-Origin', '*') .append('accept', 'application/json') .append('Content-Type', 'application/json; charset=utf-8'); + const token = sessionStorage.getItem('github:access_token'); let withCreds = false; if (token) { @@ -44,8 +45,8 @@ export class DataService { } return (content - ? this.http.post(url, content, { headers, withCredentials:withCreds }) - : this.http.post(url, { headers, withCredentials: withCreds })) + ? this.http.post(url, content, { headers, withCredentials: withCreds }) + : this.http.post(url, null, { headers, withCredentials: withCreds })) .pipe( map(result => result), timeout(this.timeout), diff --git a/rubberduckvba.client/src/environments/environment.test.ts b/rubberduckvba.client/src/environments/environment.test.ts index 26d101a..0b96c60 100644 --- a/rubberduckvba.client/src/environments/environment.test.ts +++ b/rubberduckvba.client/src/environments/environment.test.ts @@ -1,4 +1,4 @@ export const environment = { - production: true, - apiBaseUrl: 'https://test.api.rubberduckvba.com/' + production: false, + apiBaseUrl: 'https://localhost:44314/' };