Skip to content

Commit

Permalink
✨ add ability to add education to resume
Browse files Browse the repository at this point in the history
created CRUD commands and added education to md and txt export formats
  • Loading branch information
csc530 committed Jul 31, 2024
1 parent c7ee6d9 commit ef0a97f
Show file tree
Hide file tree
Showing 16 changed files with 387 additions and 75 deletions.
20 changes: 20 additions & 0 deletions .run/add education.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="add education" type="DotNetProject" factoryName=".NET Project" folderName="add">
<option name="EXE_PATH" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0/Resumer.exe" />
<option name="PROGRAM_PARAMETERS" value="add education" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Resumer/Resumer.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net8.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
20 changes: 20 additions & 0 deletions .run/edit education.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="edit education" type="DotNetProject" factoryName=".NET Project" folderName="edit">
<option name="EXE_PATH" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0/Resumer.exe" />
<option name="PROGRAM_PARAMETERS" value="edit school" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Resumer/Resumer.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net8.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
20 changes: 20 additions & 0 deletions .run/get educations.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="get educations" type="DotNetProject" factoryName=".NET Project" folderName="get">
<option name="EXE_PATH" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0/Resumer.exe" />
<option name="PROGRAM_PARAMETERS" value="get education" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/Resumer/bin/Debug/net8.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Resumer/Resumer.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net8.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
14 changes: 10 additions & 4 deletions Resumer/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Immutable;
using System.Text;
using System.Text.RegularExpressions;
using Spectre.Console;

namespace Resumer;
Expand All @@ -21,13 +22,14 @@ public static partial class Utility
/// </summary>
/// <typeparam name="T">the type of the prompt input</typeparam>
/// <param name="message">the prompt message</param>
/// <returns>a <see cref="TextPrompt{T}"/> of nullable <typeparamref name="T"/></returns>
public static TextPrompt<T?> SimplePrompt<T>(string message) =>
new TextPrompt<T?>(message).AllowEmpty().HideDefaultValue().DefaultValue(default);
new TextPrompt<T?>(message).AllowEmpty().HideDefaultValue().DefaultValue(default(T?));

/// <inheritdoc cref="SimplePrompt{T}(string)"/>
/// <param name="defaultValue">the default value</param>
public static TextPrompt<T> SimplePrompt<T>(string message, T defaultValue) => new TextPrompt<T>(message)
.AllowEmpty().DefaultValue(defaultValue).HideDefaultValue();
public static TextPrompt<T?> SimplePrompt<T>(string message, T? defaultValue) =>
SimplePrompt<T?>(message).DefaultValue(defaultValue);

/// <summary>
/// converts a string to camel case
Expand Down Expand Up @@ -56,7 +58,7 @@ public static string PrintDuration(DateOnly? startDate, DateOnly? endDate = null
startDate == null ? string.Empty : $"{startDate:MMM yyyy} - {endDate?.ToString("MMM yyyy") ?? "present"}";
}

public static class Extensions
public static partial class Extensions
{
// todo: inquire about default value being a property - spectre console pr/iss
// .DefaultValue(textPrompt);
Expand All @@ -75,6 +77,7 @@ public static string Print(this object? value) =>
null => string.Empty,
bool bit => bit ? "true" : "false",
string txt => txt,
Enum @enum => NextToUppercaseRegex().Replace(@enum.ToString(), "$1 $2").Replace('_', '-'),
DictionaryEntry pair => $"{pair.Key.Print()}: {pair.Value.Print()}",
IDictionary dictionary => string.Join("\n", dictionary.Cast<object>().Select(obj => $"- {obj.Print()}")),
IEnumerable enumerable => string.Join("\n", enumerable.Cast<object>().Select(obj => $"+ {obj.Print()}")),
Expand Down Expand Up @@ -278,4 +281,7 @@ public static void EditFromPrompt(this List<string> description, string prompt)
}
} while(i < count || !string.IsNullOrWhiteSpace(input));
}

[GeneratedRegex(@"(\w)([A-Z])")]
private static partial Regex NextToUppercaseRegex();
}
21 changes: 5 additions & 16 deletions Resumer/Migrations/ResumeContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("AdditionalInformation")
.HasColumnType("TEXT");
b.Property<string>("Degree")
b.Property<string>("Courses")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Degree")
.HasColumnType("INTEGER");
b.Property<DateOnly?>("EndDate")
.HasColumnType("TEXT");
b.Property<string>("FieldOfStudy")
.IsRequired()
.HasColumnType("TEXT");
b.Property<double?>("GradePointAverage")
Expand All @@ -80,9 +84,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("Location")
.HasColumnType("TEXT");
b.Property<Guid?>("ProfileId")
.HasColumnType("TEXT");
b.Property<string>("School")
.IsRequired()
.HasColumnType("TEXT");
Expand All @@ -92,8 +93,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("Id");
b.HasIndex("ProfileId");
b.ToTable("Education");
});

Expand Down Expand Up @@ -230,7 +229,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Name");
Expand All @@ -245,18 +243,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasForeignKey("ProfileId");
});

modelBuilder.Entity("Resumer.models.Education", b =>
{
b.HasOne("Resumer.models.Profile", null)
.WithMany("Education")
.HasForeignKey("ProfileId");
});

modelBuilder.Entity("Resumer.models.Profile", b =>
{
b.Navigation("Certifications");
b.Navigation("Education");
});
#pragma warning restore 612, 618
}
Expand Down
29 changes: 29 additions & 0 deletions Resumer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ public static void AppConfiguration(IConfigurator config)
add.AddCommand<AddPdfTemplateCommand>("template")
.WithAlias("t")
.WithDescription("add a typst file template to export resume in pdf format");
add.AddCommand<AddEducationCommand>("education")
.WithAlias("e")
.WithAlias("edu")
.WithAlias("educations")
.WithAlias("schools")
.WithAlias("school")
.WithAlias("degree")
.WithDescription("add a new education");
});

config.AddBranch("edit", edit =>
Expand All @@ -90,6 +98,13 @@ public static void AppConfiguration(IConfigurator config)
.WithDescription("edit a project's details")
.WithAlias("projects")
.WithAlias("proj");
edit.AddCommand<EditEducationCommand>("education")
.WithAlias("edu")
.WithAlias("educations")
.WithAlias("schools")
.WithAlias("school")
.WithAlias("degree")
.WithDescription("edit an education's details");
});

config.AddBranch<DeleteCommandSettings>("delete", delete =>
Expand Down Expand Up @@ -117,6 +132,13 @@ public static void AppConfiguration(IConfigurator config)
.WithDescription("delete a typst file template")
.WithAlias("t")
.WithAlias("templates");
delete.AddCommand<DeleteEducationCommand>("education")
.WithAlias("edu")
.WithAlias("educations")
.WithAlias("schools")
.WithAlias("school")
.WithAlias("degree")
.WithDescription("delete an education");
})
.WithAlias("d")
.WithAlias("del")
Expand Down Expand Up @@ -160,6 +182,13 @@ public static void AppConfiguration(IConfigurator config)
.WithAlias("t")
.WithAlias("templates")
.WithDescription("list typst templates");
get.AddCommand<GetEducationCommand>("education")
.WithAlias("edu")
.WithAlias("educations")
.WithAlias("schools")
.WithAlias("school")
.WithAlias("degree")
.WithDescription("list education");
})
.WithAlias("g")
.WithAlias("list")
Expand Down
31 changes: 26 additions & 5 deletions Resumer/cli/commands/ExportCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public override int Execute(CommandContext context, ExportCommandSettings settin
List<Job> jobs = [];
List<Skill> skills = [];
List<Project> projects = [];
List<Education> education = [];

var formatPrompt = new SelectionPrompt<Formats>()
.Title("Select export format")
Expand All @@ -38,46 +39,66 @@ public override int Execute(CommandContext context, ExportCommandSettings settin

var profile = AnsiConsole.Prompt(new SelectionPrompt<Profile>()
.Title("Select profile")
.AddChoices(dbProfiles.AsEnumerable().OrderBy(profile => profile.WholeName)));
.AddChoices(dbProfiles.AsEnumerable().OrderBy(profile => profile.WholeName))
.WrapAround()
);

if(!db.Jobs.Any())
CommandOutput.Warn("No jobs found");
else
jobs = AnsiConsole.Prompt(new MultiSelectionPrompt<Job>()
.Title("Select jobs")
.AddChoices(db.Jobs.OrderByDescending(job => job.StartDate))
.NotRequired());
.WrapAround()
.NotRequired()
);

if(!db.Skills.Any())
CommandOutput.Warn("No skills found");
else
skills = AnsiConsole.Prompt(new MultiSelectionPrompt<Skill>()
.Title("Select skills")
.AddChoices(db.Skills)
.NotRequired());
.WrapAround()
.NotRequired()
);

if(!db.Education.Any())
CommandOutput.Warn("No education found");
else
education = AnsiConsole.Prompt(new MultiSelectionPrompt<Education>()
.Title("Select education")
.AddChoices(db.Education)
.WrapAround()
.NotRequired()
);

if(!db.Projects.Any())
CommandOutput.Warn("No projects found");
else
projects = AnsiConsole.Prompt(new MultiSelectionPrompt<Project>()
.Title("Select projects")
.AddChoices(db.Projects)
.NotRequired());
.WrapAround()
.NotRequired()
);

var template = TypstTemplate.Default;

if(format == Formats.Pdf && db.Templates.Any())
template = AnsiConsole.Prompt(new SelectionPrompt<TypstTemplate>()
.Title("Select template")
.AddChoices(db.Templates)
.WrapAround());
.WrapAround()
);

var resume = new Resume(name)
{
Profile = profile,
Jobs = jobs,
Skills = skills,
Projects = projects,
Education = education,
};

var bytes = format switch
Expand Down
57 changes: 57 additions & 0 deletions Resumer/cli/commands/add/AddEducationCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Text.RegularExpressions;
using Resumer.models;
using Spectre.Console;
using Spectre.Console.Cli;
using static Resumer.Utility;

namespace Resumer.cli.commands.add;

public class AddEducationCommand: AddCommand
{
protected override string ContinuePrompt => "Add another education?";

protected override int AddItem(CommandContext context, AddCommandSettings settings)
{
var school = AnsiConsole.Ask<string>("School (name):");
var degree =
AnsiConsole.Prompt(new SelectionPrompt<Certification>()
.AddChoices(Enum.GetValues<Certification>())
.EnableSearch()
.UseConverter(certification => certification.Print())
.WrapAround()
);
AnsiConsole.WriteLine($"Degree: {degree}");
var fieldOfStudy = AnsiConsole.Ask<string>("Field (or level) of study:");
var location = AnsiConsole.Prompt(SimplePrompt<string?>("Location:"));
var gpa = AnsiConsole.Prompt(SimplePrompt<double?>("Grade point average:"));
var startDate = AnsiConsole.Ask<DateOnly>("Start date:");
var endDate = AnsiConsole.Prompt(SimplePrompt<DateOnly?>("End date or expected graduation date (optional):"));

AnsiConsole.WriteLine("\nHighlight certain courses, classes, subjects, projects, etc.");
AnsiConsole.MarkupLine("Press [bold]Enter[/] to skip.");
var courses = new List<string>();
courses.AddFromPrompt("Course:");

var additionalInformation = AnsiConsole.Prompt(SimplePrompt<string?>("Additional information:"));

var education = new Education()
{
School = school,
Degree = degree,
Courses = courses,

Location = location,
FieldOfStudy = fieldOfStudy,
GradePointAverage = gpa,

StartDate = startDate,
EndDate = endDate,
AdditionalInformation = additionalInformation,
};

var db = new ResumeContext();
db.Education.Add(education);
db.SaveChanges();
return CommandOutput.Success();
}
}
9 changes: 9 additions & 0 deletions Resumer/cli/commands/delete/DeleteEducationCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Resumer.models;

namespace Resumer.cli.commands.delete;

public class DeleteEducationCommand: DeleteCommand<Education>
{
protected override DbSet<Education> DbSet => Db.Education;
}
Loading

0 comments on commit ef0a97f

Please sign in to comment.