diff --git a/Backend/Backend/Backend.csproj b/Backend/Backend/Backend.csproj
index 1c047f6..9ae8f89 100644
--- a/Backend/Backend/Backend.csproj
+++ b/Backend/Backend/Backend.csproj
@@ -7,13 +7,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
diff --git a/Backend/Backend/Controllers/AuthController.cs b/Backend/Backend/Controllers/AuthController.cs
index 3991508..7ea8469 100644
--- a/Backend/Backend/Controllers/AuthController.cs
+++ b/Backend/Backend/Controllers/AuthController.cs
@@ -75,15 +75,23 @@ public async Task GitHubLogin([FromBody] string code)
{ "redirect_uri", _config["GitHub:RedirectUri"] ?? "" }
};
- var request = new HttpRequestMessage(HttpMethod.Post, "https://github.com/login/oauth/access_token")
+ using var request = new HttpRequestMessage(HttpMethod.Post, "https://github.com/login/oauth/access_token")
{
Content = new FormUrlEncodedContent(requestData)
};
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
- var response = await client.SendAsync(request);
- var result = await response.Content.ReadFromJsonAsync();
- return result?.access_token;
+ try
+ {
+ var response = await client.SendAsync(request);
+ if (!response.IsSuccessStatusCode) return null;
+ var result = await response.Content.ReadFromJsonAsync();
+ return result?.access_token;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
}
private async Task GetGitHubUser(string token)
@@ -92,10 +100,16 @@ public async Task GitHubLogin([FromBody] string code)
client.DefaultRequestHeaders.UserAgent.ParseAdd("GitQuest-App");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
- var response = await client.GetAsync("https://api.github.com/user");
- if (!response.IsSuccessStatusCode) return null;
-
- return await response.Content.ReadFromJsonAsync();
+ try
+ {
+ var response = await client.GetAsync("https://api.github.com/user");
+ if (!response.IsSuccessStatusCode) return null;
+ return await response.Content.ReadFromJsonAsync();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
}
private string GenerateJwtToken(User user)
diff --git a/Backend/Backend/Controllers/IssuesController.cs b/Backend/Backend/Controllers/IssuesController.cs
index 7cc7031..702bd30 100644
--- a/Backend/Backend/Controllers/IssuesController.cs
+++ b/Backend/Backend/Controllers/IssuesController.cs
@@ -40,10 +40,14 @@ public async Task ClaimQuest(long id)
var userId = Guid.Parse(userIdClaim);
+ // Verify the issue exists in our database and is still active
+ var issue = await _context.Issues.FirstOrDefaultAsync(i => i.GitHubIssueId == id);
+ if (issue == null || !issue.IsActive) return NotFound("Issue not found or no longer active.");
+
var existingQuest = await _context.Quests
.FirstOrDefaultAsync(q => q.UserId == userId && q.GitHubIssueId == id && q.Status == "In Progress");
- if (existingQuest != null) return BadRequest("Quest already active.");
+ if (existingQuest != null) return Conflict("Quest already active.");
var quest = new Quest
{
@@ -55,7 +59,15 @@ public async Task ClaimQuest(long id)
};
_context.Quests.Add(quest);
- await _context.SaveChangesAsync();
+ try
+ {
+ await _context.SaveChangesAsync();
+ }
+ catch (DbUpdateException)
+ {
+ // Unique constraint violation: another concurrent request already claimed this quest
+ return Conflict("Quest already active.");
+ }
return Ok(new { message = "Quest claimed!", questId = quest.Id });
}
@@ -67,7 +79,9 @@ public async Task GetMyQuests()
if (userIdClaim == null) return Unauthorized();
var userId = Guid.Parse(userIdClaim);
- var quests = await _context.Quests.Where(q => q.UserId == userId).ToListAsync();
+ var quests = await _context.Quests
+ .Where(q => q.UserId == userId && q.Status == "In Progress")
+ .ToListAsync();
return Ok(quests);
}
@@ -83,17 +97,47 @@ public async Task SubmitQuest(long id)
if (quest == null) return NotFound("Quest not found.");
+ // Resolve the XP reward from the stored Issue record
+ var issue = await _context.Issues.FirstOrDefaultAsync(i => i.GitHubIssueId == id);
+ if (issue == null || !issue.IsActive) return BadRequest("Issue is no longer available.");
+
quest.Status = "Completed";
quest.CompletedAt = DateTime.UtcNow;
var user = await _context.Users.FindAsync(userId);
if (user != null)
{
- user.ExperiencePoints += 30;
- user.CurrentStreak += 1;
+ user.ExperiencePoints += issue.XPReward;
+
+ // Update streak based on contribution dates (once per day)
+ var today = DateTime.UtcNow.Date;
+ if (user.LastContributionDate.HasValue)
+ {
+ var lastDate = user.LastContributionDate.Value.Date;
+ if (lastDate == today)
+ {
+ // Already contributed today – do not increment streak
+ }
+ else if (lastDate == today.AddDays(-1))
+ {
+ // Contributed yesterday – extend streak
+ user.CurrentStreak += 1;
+ }
+ else
+ {
+ // Gap in contributions – reset streak
+ user.CurrentStreak = 1;
+ }
+ }
+ else
+ {
+ user.CurrentStreak = 1;
+ }
+
+ user.LastContributionDate = DateTime.UtcNow;
}
await _context.SaveChangesAsync();
- return Ok(new { message = "30 XP Awarded!", totalXp = user?.ExperiencePoints });
+ return Ok(new { message = $"{issue.XPReward} XP Awarded!", totalXp = user?.ExperiencePoints });
}
}
\ No newline at end of file
diff --git a/Backend/Backend/Controllers/UsersController.cs b/Backend/Backend/Controllers/UsersController.cs
index 6a82dfe..cc340ba 100644
--- a/Backend/Backend/Controllers/UsersController.cs
+++ b/Backend/Backend/Controllers/UsersController.cs
@@ -37,6 +37,28 @@ public async Task GetProfile(string username)
if (user == null) return NotFound();
- return Ok(user);
+ var profile = new
+ {
+ user.GitHubUsername,
+ user.AvatarUrl,
+ user.ExperiencePoints,
+ user.CurrentStreak,
+ user.LastContributionDate,
+ Contributions = user.Contributions.Select(c => new
+ {
+ c.CompletedAt,
+ c.PullRequestUrl,
+ Issue = c.Issue == null ? null : new
+ {
+ c.Issue.Title,
+ c.Issue.RepoFullName,
+ c.Issue.IssueUrl,
+ c.Issue.Difficulty,
+ c.Issue.XPReward
+ }
+ })
+ };
+
+ return Ok(profile);
}
}
\ No newline at end of file
diff --git a/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.Designer.cs b/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.Designer.cs
new file mode 100644
index 0000000..9acdc7e
--- /dev/null
+++ b/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.Designer.cs
@@ -0,0 +1,244 @@
+//
+using System;
+using GitQuest.Backend.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Backend.Migrations
+{
+ [DbContext(typeof(GitQuestContext))]
+ [Migration("20260315125659_AddUniqueConstraints")]
+ partial class AddUniqueConstraints
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.13")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("GitQuest.Backend.Models.Issue", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Description")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Difficulty")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("GitHubIssueId")
+ .HasColumnType("bigint");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.Property("IssueUrl")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Language")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("RepoFullName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("XPReward")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GitHubIssueId")
+ .IsUnique();
+
+ b.ToTable("Issues");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.Project", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Description")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("HtmlUrl")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("OwnerAvatarUrl")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Stars")
+ .HasColumnType("int");
+
+ b.Property("TechStackSummary")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Projects");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.Quest", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("CompletedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("GitHubIssueId")
+ .HasColumnType("bigint");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("UserId")
+ .HasColumnType("uniqueidentifier");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "GitHubIssueId", "Status")
+ .IsUnique()
+ .HasDatabaseName("IX_Quests_UserId_GitHubIssueId_ActiveStatus")
+ .HasFilter("[Status] = 'In Progress'");
+
+ b.ToTable("Quests");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("AvatarUrl")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("CurrentStreak")
+ .HasColumnType("int");
+
+ b.Property("Email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ExperiencePoints")
+ .HasColumnType("int");
+
+ b.Property("GitHubId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("GitHubUsername")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("LastContributionDate")
+ .HasColumnType("datetime2");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GitHubId")
+ .IsUnique();
+
+ b.HasIndex("GitHubUsername")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.UserContribution", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("CompletedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IssueId")
+ .HasColumnType("int");
+
+ b.Property("PullRequestUrl")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("UserId")
+ .HasColumnType("uniqueidentifier");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IssueId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Contributions");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.Quest", b =>
+ {
+ b.HasOne("GitQuest.Backend.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.UserContribution", b =>
+ {
+ b.HasOne("GitQuest.Backend.Models.Issue", "Issue")
+ .WithMany()
+ .HasForeignKey("IssueId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GitQuest.Backend.Models.User", "User")
+ .WithMany("Contributions")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Issue");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GitQuest.Backend.Models.User", b =>
+ {
+ b.Navigation("Contributions");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs b/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs
new file mode 100644
index 0000000..4f15c30
--- /dev/null
+++ b/Backend/Backend/Migrations/20260315125659_AddUniqueConstraints.cs
@@ -0,0 +1,80 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Backend.Migrations
+{
+ ///
+ public partial class AddUniqueConstraints : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_Quests_UserId",
+ table: "Quests");
+
+ migrationBuilder.AlterColumn(
+ name: "GitHubId",
+ table: "Users",
+ type: "nvarchar(450)",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "nvarchar(max)");
+
+ migrationBuilder.AlterColumn(
+ name: "Status",
+ table: "Quests",
+ type: "nvarchar(450)",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "nvarchar(max)");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Users_GitHubId",
+ table: "Users",
+ column: "GitHubId",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Quests_UserId_GitHubIssueId_ActiveStatus",
+ table: "Quests",
+ columns: new[] { "UserId", "GitHubIssueId", "Status" },
+ unique: true,
+ filter: "[Status] = 'In Progress'");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_Users_GitHubId",
+ table: "Users");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Quests_UserId_GitHubIssueId_ActiveStatus",
+ table: "Quests");
+
+ migrationBuilder.AlterColumn(
+ name: "GitHubId",
+ table: "Users",
+ type: "nvarchar(max)",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "nvarchar(450)");
+
+ migrationBuilder.AlterColumn(
+ name: "Status",
+ table: "Quests",
+ type: "nvarchar(max)",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "nvarchar(450)");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Quests_UserId",
+ table: "Quests",
+ column: "UserId");
+ }
+ }
+}
diff --git a/Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs b/Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs
index 7efdf0e..11123bb 100644
--- a/Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs
+++ b/Backend/Backend/Migrations/GitQuestContextModelSnapshot.cs
@@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "8.0.25")
+ .HasAnnotation("ProductVersion", "8.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@@ -119,14 +119,17 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("Status")
.IsRequired()
- .HasColumnType("nvarchar(max)");
+ .HasColumnType("nvarchar(450)");
b.Property("UserId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
- b.HasIndex("UserId");
+ b.HasIndex("UserId", "GitHubIssueId", "Status")
+ .IsUnique()
+ .HasDatabaseName("IX_Quests_UserId_GitHubIssueId_ActiveStatus")
+ .HasFilter("[Status] = 'In Progress'");
b.ToTable("Quests");
});
@@ -151,7 +154,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("GitHubId")
.IsRequired()
- .HasColumnType("nvarchar(max)");
+ .HasColumnType("nvarchar(450)");
b.Property("GitHubUsername")
.IsRequired()
@@ -162,6 +165,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("Id");
+ b.HasIndex("GitHubId")
+ .IsUnique();
+
b.HasIndex("GitHubUsername")
.IsUnique();
diff --git a/Backend/Backend/Models/GitQuestContext.cs b/Backend/Backend/Models/GitQuestContext.cs
index c050733..f887c68 100644
--- a/Backend/Backend/Models/GitQuestContext.cs
+++ b/Backend/Backend/Models/GitQuestContext.cs
@@ -15,13 +15,23 @@ public GitQuestContext(DbContextOptions options) : base(options
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
- // Many-to-Many Configuration or specific indexing
modelBuilder.Entity()
.HasIndex(u => u.GitHubUsername)
.IsUnique();
+ modelBuilder.Entity()
+ .HasIndex(u => u.GitHubId)
+ .IsUnique();
+
modelBuilder.Entity()
.HasIndex(i => i.GitHubIssueId)
.IsUnique();
+
+ // Prevent duplicate active quests for the same user/issue (TOCTOU protection)
+ modelBuilder.Entity()
+ .HasIndex(q => new { q.UserId, q.GitHubIssueId, q.Status })
+ .HasFilter("[Status] = 'In Progress'")
+ .IsUnique()
+ .HasDatabaseName("IX_Quests_UserId_GitHubIssueId_ActiveStatus");
}
}
\ No newline at end of file
diff --git a/Backend/Backend/Models/GitQuestContextFactory.cs b/Backend/Backend/Models/GitQuestContextFactory.cs
new file mode 100644
index 0000000..7059334
--- /dev/null
+++ b/Backend/Backend/Models/GitQuestContextFactory.cs
@@ -0,0 +1,25 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+
+namespace GitQuest.Backend.Models;
+
+public class GitQuestContextFactory : IDesignTimeDbContextFactory
+{
+ public GitQuestContext CreateDbContext(string[] args)
+ {
+ var optionsBuilder = new DbContextOptionsBuilder();
+
+ var configuration = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: true)
+ .AddEnvironmentVariables()
+ .Build();
+
+ var connectionString = configuration.GetConnectionString("DefaultConnection")
+ ?? "Server=(localdb)\\mssqllocaldb;Database=GitQuestDB;Trusted_Connection=True;";
+
+ optionsBuilder.UseSqlServer(connectionString);
+ return new GitQuestContext(optionsBuilder.Options);
+ }
+}
diff --git a/Backend/Backend/Program.cs b/Backend/Backend/Program.cs
index ea1ffa6..cb3098c 100644
--- a/Backend/Backend/Program.cs
+++ b/Backend/Backend/Program.cs
@@ -49,7 +49,9 @@
// 4. JWT Auth
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
-var secretKey = jwtSettings["Key"] ?? "Your_Fallback_Very_Long_Secret_Key_123!";
+var secretKey = jwtSettings["Key"];
+if (string.IsNullOrEmpty(secretKey))
+ throw new InvalidOperationException("JwtSettings:Key is not configured. Set it via environment variable or user secrets.");
var key = Encoding.ASCII.GetBytes(secretKey);
builder.Services.AddAuthentication(options =>
diff --git a/Backend/Backend/Services/GitHubService.cs b/Backend/Backend/Services/GitHubService.cs
index 05f267e..6aa655d 100644
--- a/Backend/Backend/Services/GitHubService.cs
+++ b/Backend/Backend/Services/GitHubService.cs
@@ -28,13 +28,17 @@ public GitHubService(HttpClient httpClient, IConfiguration config)
client_id = section["ClientId"],
client_secret = section["ClientSecret"],
code = code,
- redirect_uri = section["RedirectUri"] // Ensure this matches GitHub settings
+ redirect_uri = section["RedirectUri"]
};
- var response = await _httpClient.PostAsJsonAsync("https://github.com/login/oauth/access_token", payload);
+ using var request = new HttpRequestMessage(HttpMethod.Post, "https://github.com/login/oauth/access_token")
+ {
+ Content = JsonContent.Create(payload)
+ };
+ request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
- // GitHub returns this as form-url-encoded by default unless we ask for JSON
- _httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
+ var response = await _httpClient.SendAsync(request);
+ if (!response.IsSuccessStatusCode) return null;
var result = await response.Content.ReadFromJsonAsync();
return result?.AccessToken;
@@ -42,7 +46,7 @@ public GitHubService(HttpClient httpClient, IConfiguration config)
public async Task GetGitHubUser(string accessToken)
{
- var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user");
+ using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var response = await _httpClient.SendAsync(request);
@@ -71,8 +75,9 @@ public async Task> GetSuggestedIssues(string language)
RepoFullName = ExtractRepoName(item.RepositoryUrl),
Language = language,
IssueUrl = item.HtmlUrl,
- Difficulty = item.Labels.Any(l => l.Name.Contains("good first issue")) ? "Beginner" : "Intermediate",
- XPReward = item.Labels.Any(l => l.Name.Contains("good first issue")) ? 15 : 30,
+ Difficulty = item.Labels.Any(l => l.Name.Contains("good first issue", StringComparison.OrdinalIgnoreCase)) ? "Beginner" : "Intermediate",
+ XPReward = item.Labels.Any(l =>
+ l.Name.Contains("good first issue", StringComparison.OrdinalIgnoreCase)) ? 15 : 30,
IsActive = true
}).ToList() ?? new List();
}
@@ -96,7 +101,7 @@ public record GitHubSearchResponse([property: JsonPropertyName("items")] List Labels
diff --git a/Backend/Backend/appsettings.json b/Backend/Backend/appsettings.json
index ab7dc68..6df1133 100644
--- a/Backend/Backend/appsettings.json
+++ b/Backend/Backend/appsettings.json
@@ -10,14 +10,14 @@
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=GitQuestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"JwtSettings": {
- "Key": "Your_Super_Secret_Key_At_Least_32_Chars_Long!",
+ "Key": "",
"Issuer": "GitQuestBackend",
"Audience": "GitQuestFrontend",
"DurationInMinutes": 1440
},
"GitHub": {
- "ClientId": "Ov23lifeZIfuvH3zcfQk",
- "ClientSecret": "fc0f5479ac298f4adf28d64d11a24f4a8301806b",
+ "ClientId": "",
+ "ClientSecret": "",
"CallbackUrl": "http://localhost:3000/api/auth/callback/github"
}
}
\ No newline at end of file