Compare commits
4 Commits
45763a7040
...
1b4d859692
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b4d859692 | |||
| 2d45a5e5f1 | |||
| dc116a33ab | |||
| 840379bfda |
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,4 +8,5 @@ UpgradeLog.XML
|
||||
**/[Oo]bj/
|
||||
**/[Tt]est[Rr]esults/
|
||||
**/.vs/
|
||||
*.user
|
||||
*.user
|
||||
/ExtensiblePortfolioSite/Plugins
|
||||
|
||||
@ -5,11 +5,11 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
||||
{
|
||||
internal static class GitManager
|
||||
{
|
||||
private static readonly SortedDictionary<String, GitService> Providers = new ();
|
||||
private static readonly SortedDictionary<String, GitService> Providers = new();
|
||||
|
||||
public static void Register(String Service, IGitProvider Provider)
|
||||
{
|
||||
if(Providers.TryGetValue(Service, out GitService? GitService))
|
||||
if (Providers.TryGetValue(Service, out GitService? GitService))
|
||||
{
|
||||
GitService.addProvider(Provider);
|
||||
return;
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ExtensiblePortfolioSite.SDK.Git
|
||||
{
|
||||
@ -19,6 +15,10 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
||||
/// <see cref="IRepository"/>
|
||||
/// </summary>
|
||||
Repository,
|
||||
/// <summary>
|
||||
/// <see cref="ICommit"/>
|
||||
/// </summary>
|
||||
Commit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -26,6 +26,11 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
||||
/// </summary>
|
||||
public readonly struct GitReference
|
||||
{
|
||||
public GitReference(GitReferenceKind Kind, String ReferenceString)
|
||||
{
|
||||
this.Kind = Kind;
|
||||
this.ReferenceString = ReferenceString;
|
||||
}
|
||||
/// <summary>
|
||||
/// Reference Kind
|
||||
/// </summary>
|
||||
|
||||
24
EPS.SDK/Git/ICommit.cs
Normal file
24
EPS.SDK/Git/ICommit.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ExtensiblePortfolioSite.SDK.Git
|
||||
{
|
||||
/// <summary>
|
||||
/// A commit inside a git repository
|
||||
/// </summary>
|
||||
public interface ICommit : IGitObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The description of the commit
|
||||
/// </summary>
|
||||
public String Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of files modified in the commit
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<String> ModifiedFiles { get; }
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ExtensiblePortfolioSite.SDK.Git
|
||||
namespace ExtensiblePortfolioSite.SDK.Git
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Git Object Interface
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ExtensiblePortfolioSite.SDK.Git
|
||||
{
|
||||
@ -12,9 +7,43 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
||||
/// </summary>
|
||||
public interface IRepository : IGitObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the repository
|
||||
/// </summary>
|
||||
public String Name { get; }
|
||||
/// <summary>
|
||||
/// Owner of the repository
|
||||
/// </summary>
|
||||
public IUser Owner { get; }
|
||||
|
||||
public Boolean TryGetFile(String RelativePath, out Stream File);
|
||||
/// <summary>
|
||||
/// Get a commit from the repository, defaults to latest
|
||||
/// </summary>
|
||||
/// <param name="HeadOffset">How far to go back in the commit tree (default 0)</param>
|
||||
/// <returns>A commit</returns>
|
||||
public ICommit? GetCommit(uint HeadOffset = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Get a commit from the repository, defaults to latest
|
||||
/// </summary>
|
||||
/// <param name="HeadOffset">How far to go back in the commit tree (default 0)</param>
|
||||
/// <param name="Commit">Reference to the commit</param>
|
||||
/// <returns>If the commit could be found</returns>
|
||||
public bool TryGetCommit(uint HeadOffset, out ICommit? Commit);
|
||||
|
||||
/// <summary>
|
||||
/// Get a commit from the repository by it's hash
|
||||
/// </summary>
|
||||
/// <param name="Reference">Which commit to get from the repo</param>
|
||||
/// <returns>A commit</returns>
|
||||
public ICommit? GetCommitByRef(string Reference);
|
||||
|
||||
/// <summary>
|
||||
/// Get a commit from the repository, defaults to latest
|
||||
/// </summary>
|
||||
/// <param name="Reference">Which commit to get from the repo</param>
|
||||
/// <param name="Commit">Reference to the commit</param>
|
||||
/// <returns>If the commit could be found</returns>
|
||||
public bool TryGetCommitByRef(string Reference, out ICommit? Commit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
@ -27,6 +28,7 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
||||
|
||||
List<Byte[]> PublicKeyTokens = new();
|
||||
PublicKeyTokens.Add(typeof(String).Assembly.GetName().GetPublicKeyToken()!); // Framework Libraries
|
||||
PublicKeyTokens.Add(typeof(System.Runtime.GCSettings).Assembly.GetName().GetPublicKeyToken()!);
|
||||
KnownPublicKeyTokens = PublicKeyTokens.ToArray();
|
||||
}
|
||||
|
||||
@ -41,9 +43,13 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
||||
public static void LoadPlugins(string RootPath)
|
||||
{
|
||||
RootPath = Path.GetFullPath(RootPath);
|
||||
if (!Directory.Exists(RootPath))
|
||||
Directory.CreateDirectory(RootPath);
|
||||
LibraryPaths.Add(RootPath);
|
||||
foreach (String Dll in Directory.EnumerateFiles(RootPath, "*.dll", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
TryLoadPlugin(Path.GetFullPath(Dll, RootPath), out Plugin? _);
|
||||
}
|
||||
}
|
||||
public static Boolean TryLoadPlugin(string AsmPath, out Plugin? plugin)
|
||||
{
|
||||
@ -101,17 +107,17 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
||||
TypeReference AttrType = MD.GetTypeReference((TypeReferenceHandle)Ctor.Parent);
|
||||
String AttrTypeName = MD.GetString(AttrType.Name);
|
||||
String AttrTypeNamespace = MD.GetString(AttrType.Namespace);
|
||||
|
||||
if (
|
||||
AttrType.ResolutionScope.Kind == HandleKind.AssemblyReference &&
|
||||
AttrTypeName == EPSPluginAttribute_type.Name &&
|
||||
AttrTypeNamespace == EPSPluginAttribute_type.Namespace
|
||||
)
|
||||
{
|
||||
|
||||
AssemblyReference AsmRef = MD.GetAssemblyReference((AssemblyReferenceHandle)AttrType.ResolutionScope);
|
||||
|
||||
String AsmName = MD.GetString(AsmRef.Name);
|
||||
if (AsmName == EPSPluginAttribute_type.Assembly.FullName)
|
||||
if (AsmName == EPSPluginAttribute_type.Assembly.GetName().Name)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -182,7 +188,7 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new FileNotFoundException($"Unable to load Assembly '{AsmName}'");
|
||||
return null;
|
||||
}
|
||||
internal static IPluginUnmanagedLibrary? LoadUnmanagedLibrary(String Name)
|
||||
{
|
||||
|
||||
@ -5,7 +5,9 @@ VisualStudioVersion = 17.3.32819.101
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensiblePortfolioSite", "ExtensiblePortfolioSite\ExtensiblePortfolioSite.csproj", "{F9C668EB-F7E8-4EA1-BB8E-7102E8B2B857}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPS.SDK", "EPS.SDK\EPS.SDK.csproj", "{8B5864BB-1EDC-4E51-A190-E5C627CA1D91}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPS.SDK", "EPS.SDK\EPS.SDK.csproj", "{8B5864BB-1EDC-4E51-A190-E5C627CA1D91}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GithubPlugin", "GithubPlugin\GithubPlugin.csproj", "{CFC01285-8EF5-45A3-9470-380314116489}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -21,6 +23,10 @@ Global
|
||||
{8B5864BB-1EDC-4E51-A190-E5C627CA1D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8B5864BB-1EDC-4E51-A190-E5C627CA1D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8B5864BB-1EDC-4E51-A190-E5C627CA1D91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CFC01285-8EF5-45A3-9470-380314116489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CFC01285-8EF5-45A3-9470-380314116489}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CFC01285-8EF5-45A3-9470-380314116489}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CFC01285-8EF5-45A3-9470-380314116489}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ExtensiblePortfolioSite
|
||||
{
|
||||
@ -13,9 +12,17 @@ namespace ExtensiblePortfolioSite
|
||||
}
|
||||
|
||||
|
||||
public static String FullName { get; } = "invalid";
|
||||
public static String? Phone { get; } = null;
|
||||
public static String? Email { get; } = null;
|
||||
public static String Name { get; private set; } = "invalid";
|
||||
public static String? Phone { get; private set; } = null;
|
||||
public static String? Email { get; private set; } = null;
|
||||
public static String[]? Description { get; private set; } = null;
|
||||
public static Dictionary<string, string> Languages = new Dictionary<string, string>()
|
||||
{
|
||||
{ "C#", "https://seeklogo.com/images/C/c-sharp-c-logo-02F17714BA-seeklogo.com.png" },
|
||||
{ "Kotlin", "https://upload.wikimedia.org/wikipedia/commons/7/74/Kotlin_Icon.png" },
|
||||
{ "Lua", "https://upload.wikimedia.org/wikipedia/commons/c/cf/Lua-Logo.svg" },
|
||||
{ "C/C++", "https://upload.wikimedia.org/wikipedia/commons/1/19/C_Logo.png" },
|
||||
};
|
||||
|
||||
public static void LoadConfig()
|
||||
{
|
||||
@ -25,8 +32,49 @@ namespace ExtensiblePortfolioSite
|
||||
CommentHandling = JsonCommentHandling.Skip,
|
||||
MaxDepth = 16,
|
||||
});
|
||||
|
||||
|
||||
foreach (JsonProperty property in Doc.RootElement.EnumerateObject())
|
||||
{
|
||||
switch (property.Value.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
String value = property.Value.GetString()!;
|
||||
switch (property.Name)
|
||||
{
|
||||
case "Name":
|
||||
Config.Name = value;
|
||||
break;
|
||||
case "Phone":
|
||||
Config.Phone = value;
|
||||
break;
|
||||
case "Email":
|
||||
Config.Email = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JsonValueKind.Array:
|
||||
switch (property.Name)
|
||||
{
|
||||
case "Description":
|
||||
Config.Description = new string[property.Value.GetArrayLength()];
|
||||
var enumerator = property.Value.EnumerateArray();
|
||||
for (int i = 0; i < property.Value.GetArrayLength(); i++)
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
break;
|
||||
if (enumerator.Current.ValueKind == JsonValueKind.String)
|
||||
Config.Description[i] = enumerator.Current.GetString()!;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JsonValueKind.Object:
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
break;
|
||||
case JsonValueKind.True: //Why, why isn't it called boolean
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,10 @@
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="Pages\Projects.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||
</ItemGroup>
|
||||
@ -18,4 +22,8 @@
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Pages\Projects\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -123,7 +123,7 @@ namespace ExtensiblePortfolioSite
|
||||
|
||||
String Dir = Path.GetDirectoryName(FileOutput)!;
|
||||
if(!Directory.Exists(Dir)) Directory.CreateDirectory(Dir);
|
||||
this.FOut = new StreamWriter(new FileStream(FileOutput, FileMode.CreateNew, FileAccess.Write, FileShare.Read, 1024, false), ENCODING, 1024, false);
|
||||
this.FOut = new StreamWriter(new FileStream(FileOutput, FileMode.Append, FileAccess.Write, FileShare.Read, 1024, false), ENCODING, 1024, false);
|
||||
|
||||
this.LogWriter = new Thread(LogWriter_thread)
|
||||
{
|
||||
|
||||
39
ExtensiblePortfolioSite/Pages/About/Index.cshtml
Normal file
39
ExtensiblePortfolioSite/Pages/About/Index.cshtml
Normal file
@ -0,0 +1,39 @@
|
||||
@page
|
||||
@model AboutModel
|
||||
@{
|
||||
ViewData["Title"] = "About";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<div class="about-me" style="display: flex; flex-direction: row; width: 100%; flex-grow: 1; justify-content: center; align-items: center;">
|
||||
<div class="languages-container" style="min-width: 20%;">
|
||||
<h3 style="width: 100%; text-align:center;">Known Languages</h3>
|
||||
@foreach(var language in Config.Languages)
|
||||
{
|
||||
<div style="display: flex; flex-direction: row; align-items: center; border-top: solid 1px var(--bs-gray-800); padding: 0.25em 0; ">
|
||||
<img src="@language.Value" style="height: 2em; margin-right: 1em;" />
|
||||
<h3 style="margin: 0 0 0 .25em;">@language.Key</h3>
|
||||
<h4 style="margin: 0 0 0 auto;">100%</h4>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="about-me-container" style="display: flex; flex-direction: column; flex: 1; align-items: center; min-width: 60%; min-height: 40vh;">
|
||||
<h2>About Me</h2>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce commodo imperdiet hendrerit. Vestibulum pretium mauris eu sagittis tristique. Sed tellus nulla, facilisis in molestie id, fermentum facilisis nulla. Nullam vel tristique neque. Nam accumsan arcu vel nulla efficitur, posuere convallis diam rhoncus. Mauris mollis at sapien eu gravida. Nullam viverra velit porttitor ex mattis, in iaculis justo tincidunt. Morbi pulvinar odio nec mauris luctus facilisis. Phasellus aliquam commodo turpis. Quisque in tincidunt tellus, vel facilisis massa.</p>
|
||||
<p>Pellentesque auctor eros vitae pretium ornare. Donec quam erat, tempor id elit eu, aliquet suscipit mi. Morbi facilisis nisi vel dapibus facilisis. Phasellus efficitur ac odio id ultricies. Cras ullamcorper lacinia posuere. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus lobortis, arcu a mollis venenatis, nisi libero cursus risus, ut sodales felis erat quis lorem. Praesent nisl turpis, egestas ac auctor et, tempor ac mauris. Donec aliquam lacus nisi, id hendrerit neque aliquam ut. Nullam maximus velit nulla, quis euismod lacus porttitor ac. Nullam lacinia non arcu vitae scelerisque. Nulla nisl nibh, vestibulum eget ex sit amet, viverra vulputate purus. Nullam non arcu ac diam sagittis consectetur.</p>
|
||||
</div>
|
||||
<div class="personals-container" style="min-width: 20%;">
|
||||
<div style="display: flex; flex-direction: row; align-items: center; padding: 0.25em 0; ">
|
||||
<img src="img/user.svg" style="height: 2em; margin-right: 1em;" />
|
||||
<span style="margin: 0 0 0 .25em;">@Config.Name</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row; align-items: center; border-top: solid 1px var(--bs-gray-800); padding: 0.25em 0; ">
|
||||
<img src="img/email.svg" style="height: 2em; margin-right: 1em;" />
|
||||
<span style="margin: 0 0 0 .25em;">@Config.Email</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row; align-items: center; border-top: solid 1px var(--bs-gray-800); padding: 0.25em 0; ">
|
||||
<img src="img/phone.svg" style="height: 2em; margin-right: 1em;" />
|
||||
<span style="margin: 0 0 0 .25em;">@Config.Phone</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
12
ExtensiblePortfolioSite/Pages/About/Index.cshtml.cs
Normal file
12
ExtensiblePortfolioSite/Pages/About/Index.cshtml.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace ExtensiblePortfolioSite.Pages.About
|
||||
{
|
||||
public class AboutModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,31 @@
|
||||
@model IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "Home page";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
|
||||
<h1 class="display-4">@Config.Name</h1>
|
||||
@if(Config.Description == null)
|
||||
{
|
||||
<p>
|
||||
No description ;(
|
||||
</p>
|
||||
} else
|
||||
{
|
||||
@foreach(String s in Config.Description)
|
||||
{
|
||||
<div class="description">
|
||||
<span>@s</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<div class="links">
|
||||
<a href="/About">About Me</a>
|
||||
<vr ></vr>
|
||||
<a href="/Projects">Projects</a>
|
||||
<vr ></vr>
|
||||
<a href="/Socials">Contact Me</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace ExtensiblePortfolioSite.Pages
|
||||
{
|
||||
|
||||
92
ExtensiblePortfolioSite/Pages/Projects/Index.cshtml
Normal file
92
ExtensiblePortfolioSite/Pages/Projects/Index.cshtml
Normal file
@ -0,0 +1,92 @@
|
||||
@page
|
||||
@using System.Text.Json
|
||||
@using ExtensiblePortfolioSite.SDK.Git
|
||||
@model ProjectsModel
|
||||
@{
|
||||
ViewData["Title"] = "Projects";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<div class="container repo-container">
|
||||
@{
|
||||
//var githubService = GitManager.GetService("github.com");
|
||||
//var user = githubService.GetUser(new Uri("https://github.com/KoromaruKoruko"));
|
||||
//Console.WriteLine("FOUND USER");
|
||||
//Console.WriteLine(user.Name);
|
||||
//var repos = user.GetUserRepositories();
|
||||
//Console.WriteLine("REPOSITORIES");
|
||||
//foreach(var repo in repos)
|
||||
// Console.WriteLine(repo.Name);
|
||||
var client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "KoromaruKoruko");
|
||||
client.DefaultRequestHeaders.Add("Authorization", "Bearer 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");
|
||||
HttpResponseMessage response = await client.GetAsync("https://api.github.com/users/KoromaruKoruko/repos");
|
||||
JsonDocument json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
|
||||
|
||||
foreach(JsonElement elem in json.RootElement.EnumerateArray())
|
||||
{
|
||||
int popout_id = Random.Shared.Next();
|
||||
HttpResponseMessage commitResponse = await client.GetAsync(elem.GetProperty("commits_url").GetString().Split('{')[0]);
|
||||
JsonDocument commitInfo = await JsonDocument.ParseAsync(await commitResponse.Content.ReadAsStreamAsync());
|
||||
JsonElement commitJson = commitInfo.RootElement.EnumerateArray().First();
|
||||
String[] lastCommitMessage = commitJson.GetProperty("commit").GetProperty("message")!.GetString()!.Split("\n").Where(s => s != "").ToArray();
|
||||
|
||||
// Begin repo
|
||||
<div class="repo">
|
||||
<div class="repo-title">
|
||||
<span class="eps-lineclamp-1">KoromaruKoruko/</span>
|
||||
<span class="eps-lineclamp-1">@elem.GetProperty("name")</span>
|
||||
</div>
|
||||
<div class="repo-description eps-lineclamp-2">
|
||||
@elem.GetProperty("description")
|
||||
</div>
|
||||
<div class="popout">
|
||||
<span class="popout-title">@elem.GetProperty("description")</span>
|
||||
</div>
|
||||
<div class="commit">
|
||||
<img class="commit-author" src="@commitJson.GetProperty("author").GetProperty("avatar_url").GetString()"/>
|
||||
<div class="commit-info">
|
||||
<div class="commit-title eps-lineclamp-1">
|
||||
@if(lastCommitMessage.Length > 0)
|
||||
{
|
||||
@lastCommitMessage[0]
|
||||
}
|
||||
</div>
|
||||
<div class="commit-description eps-lineclamp-1">
|
||||
@if(lastCommitMessage.Length > 1)
|
||||
{
|
||||
@lastCommitMessage[1]
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="popout popout-commit">
|
||||
@if (lastCommitMessage.Length > 0)
|
||||
{
|
||||
<span class="popout-title">@lastCommitMessage[0]</span>
|
||||
<br />
|
||||
var commitDescription = lastCommitMessage.Skip(1).ToHashSet();
|
||||
<div class="popout-content">
|
||||
@if(commitDescription.Count > 0)
|
||||
@commitDescription.Aggregate((a, b) => a + "\n" + b)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="repo-footer">
|
||||
<a class="repo-link" href="@elem.GetProperty("html_url").GetString()">
|
||||
<span>visit repo >></span>
|
||||
</a>
|
||||
<img class="repo-icon" src="/img/logos/github/Light-64px.png"/>
|
||||
</div>
|
||||
</div>
|
||||
// End repo
|
||||
}
|
||||
<script>
|
||||
function processMarkdown(element) {
|
||||
element.getElementsByClassName('popout-content')[0].innerHTML = marked.parse(element.getElementsByClassName('popout-content')[0].innerHTML);
|
||||
}
|
||||
Array.from(document.getElementsByClassName('popout-commit')).forEach(processMarkdown);
|
||||
</script>
|
||||
}
|
||||
</div>
|
||||
18
ExtensiblePortfolioSite/Pages/Projects/Index.cshtml.cs
Normal file
18
ExtensiblePortfolioSite/Pages/Projects/Index.cshtml.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace ExtensiblePortfolioSite.Pages
|
||||
{
|
||||
public class ProjectsModel : PageModel
|
||||
{
|
||||
private readonly ILogger<IndexModel> _logger;
|
||||
|
||||
public ProjectsModel(ILogger<IndexModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,40 +4,56 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - ExtensiblePortfolioSite</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://bootswatch.com/5/superhero/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/ExtensiblePortfolioSite.styles.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">@Config.FullName</a>
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">@Config.Name</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/About">About</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/Projects">Projects</a>
|
||||
</li>
|
||||
<li class="nav-item contact-me">
|
||||
<a class="nav-link" href="/Socials">Socials</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container">
|
||||
<div class="container page-contents">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2022 - @Config.FullName
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll('.navbar-nav a.nav-link').forEach(function(a) {
|
||||
if(a.getAttribute("href") == document.location.pathname) {
|
||||
a.classList.add("active");
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<footer class="border-top footer text-muted container">
|
||||
<span id="copyright-disclaimer">© 2022 - @Config.Name</span>
|
||||
<span>Photo by <a href="https://unsplash.com/photos/iqrdLI5p87I">Serge Bauwens</a> on Unsplash</span>
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
|
||||
@ -5,11 +5,7 @@ a.navbar-brand {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0077cc;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
@ -39,6 +35,11 @@ button.accept-policy {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.contact-me {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@ -46,3 +47,4 @@ button.accept-policy {
|
||||
white-space: nowrap;
|
||||
line-height: 60px;
|
||||
}
|
||||
*/
|
||||
6
ExtensiblePortfolioSite/Pages/Socials/Index.cshtml
Normal file
6
ExtensiblePortfolioSite/Pages/Socials/Index.cshtml
Normal file
@ -0,0 +1,6 @@
|
||||
@page
|
||||
@model SocialsModel
|
||||
@{
|
||||
ViewData["Title"] = "Socials";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
12
ExtensiblePortfolioSite/Pages/Socials/Index.cshtml.cs
Normal file
12
ExtensiblePortfolioSite/Pages/Socials/Index.cshtml.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace ExtensiblePortfolioSite.Pages.Socials
|
||||
{
|
||||
public class SocialsModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
39
ExtensiblePortfolioSite/Pages/Staging/GitRepo.html
Normal file
39
ExtensiblePortfolioSite/Pages/Staging/GitRepo.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - ExtensiblePortfolioSite</title>
|
||||
<link rel="stylesheet" href="https://bootswatch.com/5/superhero/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="../../wwwroot/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="../../wwwroot/ExtensiblePortfolioSite.styles.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container repo-container">
|
||||
<div class="row">
|
||||
<!-- Begin repo -->
|
||||
<div class="col-md-auto repo">
|
||||
<div class="repo-title">KoromaruKoruko/ Code_Olive</div>
|
||||
<div class="repo-description">Code_Olive .Net Plugins for the future. </div>
|
||||
<div class="commit">
|
||||
<img class="commit-author" src="https://avatars.githubusercontent.com/u/17232928?s=48&v=4"/>
|
||||
<div class="commit-info">
|
||||
<div class="commit-title">
|
||||
Initial commit
|
||||
</div>
|
||||
<div class="commit-description">
|
||||
added some stuff :D
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="repo-footer">
|
||||
<a class="repo-link" href="https://github.com/KoromaruKoruko/Code_Olive">
|
||||
<span>visit repo >></span>
|
||||
</a>
|
||||
<img class="repo-icon" src="../../wwwroot/img/logos/github/Light-64px.png"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End repo -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
@ -71,8 +71,8 @@ namespace ExtensiblePortfolioSite
|
||||
else
|
||||
builder.Logging.AddProvider(new LoggerProvider(
|
||||
log_output
|
||||
.Replace("{date}", DateTime.Now.ToShortDateString())
|
||||
.Replace("{time}", DateTime.Now.ToShortTimeString())
|
||||
.Replace("{date}", DateTime.Now.ToString("yyyy-MM-dd"))
|
||||
.Replace("{time}", DateTime.Now.ToString("HH.mm.ss"))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
// Multiple Lines to make up your Profile Description
|
||||
"Description": [
|
||||
"I'm a c# Programmer who prides herself in making thins configureable and highly optimized."
|
||||
"I'm a c# Programmer who prides herself in making things configurable and highly optimized."
|
||||
],
|
||||
|
||||
// Languages you'd like to advertise
|
||||
@ -36,9 +36,13 @@
|
||||
"GitRepos": [
|
||||
{
|
||||
"ServiceProvider": "Github",
|
||||
"Repository": "<Link to Repo>"
|
||||
"Repository": "<Link to Repo>",
|
||||
"Description": [
|
||||
"line 1",
|
||||
"line 2"
|
||||
]
|
||||
}
|
||||
],
|
||||
],
|
||||
|
||||
// Social Links
|
||||
// must be a Name and Web link to an unauthenticated accessible websites.
|
||||
|
||||
5
ExtensiblePortfolioSite/libman.json
Normal file
5
ExtensiblePortfolioSite/libman.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"defaultProvider": "cdnjs",
|
||||
"libraries": []
|
||||
}
|
||||
@ -1,18 +1,230 @@
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
background: url(/img/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
background-color: rgba(10, 10, 10, .9);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
nav {
|
||||
min-height: 5em;
|
||||
}
|
||||
|
||||
nav a.navbar-brand {
|
||||
font-size: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
nav a.nav-link {
|
||||
font-size: 1.5em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
body .page-contents,
|
||||
main,
|
||||
main .text-center {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body .page-contents {
|
||||
min-height: calc(100%-10em);
|
||||
}
|
||||
|
||||
.footer {
|
||||
min-height: 1em;
|
||||
margin-bottom: 0.25em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
max-width: 100vw;
|
||||
border-top: solid 2px var(--bs-gray-700)!important;
|
||||
padding: 0.75em 18em;
|
||||
}
|
||||
|
||||
#copyright-disclaimer {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: var(--bs-gray-600);
|
||||
}
|
||||
|
||||
main,
|
||||
main .text-center {
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
main .text-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.description span {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.repo-container {
|
||||
border: solid 1px #444;
|
||||
border-radius: .25em;
|
||||
width: 81.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.repo {
|
||||
min-height: 16em;
|
||||
width: 16em;
|
||||
max-width: 16em;
|
||||
border: solid 1px var(--bs-gray-600);
|
||||
border-radius: .25em;
|
||||
margin: .125em;
|
||||
padding: 0 .25em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.repo .repo-title span {
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.repo .repo-description {
|
||||
font-size: 1.25em;
|
||||
min-height: 3em;
|
||||
}
|
||||
|
||||
.repo .repo-description + .popout {
|
||||
display: none;
|
||||
background-color: rgba(10, 10, 10, .85);
|
||||
color: var(--bs-gray-400);
|
||||
margin-top: 4em;
|
||||
margin-left: 0;
|
||||
width: 15.5em;
|
||||
min-height: 4em;
|
||||
padding: .5em;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.repo .repo-description:hover + .popout {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.repo .commit {
|
||||
margin-top: .25em;
|
||||
border: solid 1px var(--bs-gray-200);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
min-height: 4em;
|
||||
}
|
||||
|
||||
.repo .commit .commit-author {
|
||||
margin-left: .25em;
|
||||
clip-path: circle();
|
||||
max-height: 3.5em;
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
.repo .commit .commit-info .commit-title,
|
||||
.repo .commit .commit-info .commit-description {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
.repo .commit .popout {
|
||||
display: none;
|
||||
background-color: rgba(25, 25, 25, .85);
|
||||
color: var(--bs-gray-400);
|
||||
margin-top: 2em;
|
||||
margin-left: 12em;
|
||||
padding: .5em;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.repo .commit:hover .popout {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.repo .repo-footer {
|
||||
margin-top: auto;
|
||||
margin-bottom: .25em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.repo .repo-footer .repo-link {
|
||||
margin-left: .25em;
|
||||
font-size: 1.3em;
|
||||
color: var(--bs-blue);
|
||||
}
|
||||
|
||||
.repo .repo-footer .repo-icon {
|
||||
margin-left: auto;
|
||||
max-width: 2.5em;
|
||||
}
|
||||
|
||||
.popout .popout-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.eps-lineclamp-1 {
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1; /* number of lines to show */
|
||||
line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.eps-lineclamp-2 {
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2; /* number of lines to show */
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
margin-top: 6em;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.links a {
|
||||
display: block;
|
||||
padding: 0 3em;
|
||||
color: var(--bs-gray-400);
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.links vr {
|
||||
border-right: solid 1px var(--bs-gray-500);
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
.about-me .about-me-container {
|
||||
margin: 0 1em;
|
||||
padding: 0 1em;
|
||||
border-left: solid 1px var(--bs-gray-700);
|
||||
border-right: solid 1px var(--bs-gray-700);
|
||||
}
|
||||
BIN
ExtensiblePortfolioSite/wwwroot/img/background.jpg
Normal file
BIN
ExtensiblePortfolioSite/wwwroot/img/background.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 159 KiB |
1
ExtensiblePortfolioSite/wwwroot/img/email.svg
Normal file
1
ExtensiblePortfolioSite/wwwroot/img/email.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><path fill="#eee" d="M118.64 21.538L60 67.974 1.368 21.538zm0 66.472L83.37 60.002l35.27-28.005zM1.21 31.998l35.265 28.005L1.21 88.01z"/><path fill="#ccc" d="M76.912 64.975L60.08 78.252 43.248 64.975 1.368 98.01h117.42z"/></svg>
|
||||
|
After Width: | Height: | Size: 289 B |
BIN
ExtensiblePortfolioSite/wwwroot/img/logos/github/Dark-64px.png
Normal file
BIN
ExtensiblePortfolioSite/wwwroot/img/logos/github/Dark-64px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
ExtensiblePortfolioSite/wwwroot/img/logos/github/Light-64px.png
Normal file
BIN
ExtensiblePortfolioSite/wwwroot/img/logos/github/Light-64px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
1
ExtensiblePortfolioSite/wwwroot/img/phone.svg
Normal file
1
ExtensiblePortfolioSite/wwwroot/img/phone.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><path fill="#eee" d="M118.27 98.503v-.026s-22.666-22.64-22.68-22.65a4.54 4.54 0 0 0-6.44.01L78.72 86.315c-4.056 4.057-9.286.457-19.325-7.73-6.642-5.415-14.284-12.698-20.91-20.91-4.65-5.76-8.762-11.81-4.514-16.057.01-.01 10.48-10.45 10.48-10.46l.01-.022c1.88-1.878 1.698-4.755-.02-6.472v-.026L21.1 1.33c-1.797-1.796-4.67-1.756-6.44.013L4.15 11.853C-.18 17.273-9.803 43.1 31.452 85.387c43.46 44.55 71.505 35.02 76.333 29.994 0 0 10.5-10.37 10.5-10.38l.008-.02c1.88-1.88 1.69-4.76-.02-6.48z"/></svg>
|
||||
|
After Width: | Height: | Size: 558 B |
5
ExtensiblePortfolioSite/wwwroot/img/user.svg
Normal file
5
ExtensiblePortfolioSite/wwwroot/img/user.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="600" fill="#eee">
|
||||
<circle cx="300" cy="230" r="115" />
|
||||
<circle cx="300" cy="550" r="205" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 274 B |
File diff suppressed because one or more lines are too long
33
GithubPlugin/GithubCommit.cs
Normal file
33
GithubPlugin/GithubCommit.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using ExtensiblePortfolioSite.SDK.Git;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GithubPlugin
|
||||
{
|
||||
public class GithubCommit : ICommit
|
||||
{
|
||||
[JsonIgnore]
|
||||
public IReadOnlyCollection<string> ModifiedFiles { get; internal set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IRepository? Repository { get; internal set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IGitProvider? Provider { get; internal set; }
|
||||
|
||||
[JsonPropertyName("sha")]
|
||||
public string? Hash { get; private set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string? Description { get; private set; }
|
||||
|
||||
public GitReference GetReference()
|
||||
{
|
||||
return new GitReference(GitReferenceKind.Commit, $"{Repository.Owner}/{Repository.Name}/{Hash}");
|
||||
}
|
||||
}
|
||||
}
|
||||
13
GithubPlugin/GithubPlugin.csproj
Normal file
13
GithubPlugin/GithubPlugin.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EPS.SDK\EPS.SDK.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
147
GithubPlugin/GithubProvider.cs
Normal file
147
GithubPlugin/GithubProvider.cs
Normal file
@ -0,0 +1,147 @@
|
||||
using ExtensiblePortfolioSite.SDK.Git;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace GithubPlugin
|
||||
{
|
||||
[GitProvider("github.com")]
|
||||
public class GithubProvider : IGitProvider
|
||||
{
|
||||
private HttpClient httpClient = new HttpClient();
|
||||
|
||||
private Regex userPattern = new Regex("^(http(s)*:\\/\\/)(www\\.)*(github\\.com\\/[A-z]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private Regex repoPattern = new Regex("^(http(s)*:\\/\\/)(www\\.)*(github\\.com\\/[A-z]+\\/[A-z]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public Dictionary<string, GithubUser> Users = new();
|
||||
public Dictionary<string, GithubRepo> Repositories = new();
|
||||
|
||||
public GithubProvider()
|
||||
{
|
||||
this.httpClient.BaseAddress = new("https://api.github.com/");
|
||||
this.httpClient.DefaultRequestHeaders.Add("User-Agent", "KoromaruKoruko");
|
||||
this.httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer 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");
|
||||
}
|
||||
|
||||
public IGitObject GetByReference(GitReference Reference)
|
||||
{
|
||||
switch(Reference.Kind)
|
||||
{
|
||||
case GitReferenceKind.User:
|
||||
if(TryGetUserByName(Reference.ReferenceString, out IUser? user))
|
||||
return user!;
|
||||
else
|
||||
return null;
|
||||
case GitReferenceKind.Repository:
|
||||
{
|
||||
if (TryGetRepositoryByName(
|
||||
Reference.ReferenceString.Split('/')[0], Reference.ReferenceString.Split('/')[1], out IRepository? repo))
|
||||
return repo!;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
case GitReferenceKind.Commit:
|
||||
{
|
||||
if (TryGetRepositoryByName(
|
||||
Reference.ReferenceString.Split('/')[0], Reference.ReferenceString.Split('/')[1], out IRepository? repo))
|
||||
{
|
||||
if (repo!.TryGetCommitByRef(Reference.ReferenceString.Split('/')[2], out ICommit? commit))
|
||||
return commit!;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool TryGetRepositoryByName(string Username, string RepositoryName, out IRepository? Repository)
|
||||
{
|
||||
if (TryGetUserByName(Username, out IUser? User))
|
||||
return TryGetRepositoryByName(User!, RepositoryName, out Repository);
|
||||
Repository = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetRepositoryByName(IUser User, string RepositoryName, out IRepository? Repository)
|
||||
{
|
||||
if(User.GetType() == typeof(GithubUser))
|
||||
{
|
||||
if (Repositories.TryGetValue(RepositoryName, out GithubRepo? _repo))
|
||||
{
|
||||
Repository = _repo;
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
var response = httpClient.GetAsync($"repos/{User.Name}/{RepositoryName}").Result;
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Repository = null;
|
||||
return false;
|
||||
}
|
||||
GithubRepo tempRepo = JsonSerializer.Deserialize<GithubRepo>(response.Content.ReadAsStream())!;
|
||||
tempRepo.Provider = this;
|
||||
tempRepo.Owner = User;
|
||||
Repository = tempRepo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Repository = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetUserByName(string Username, out IUser? User)
|
||||
{
|
||||
if(Users.TryGetValue(Username, out GithubUser? _user))
|
||||
{
|
||||
User = _user;
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
var response = httpClient.GetAsync($"users/{Username}").Result;
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
User = null;
|
||||
return false;
|
||||
}
|
||||
GithubUser tempUser = JsonSerializer.Deserialize<GithubUser>(response.Content.ReadAsStream())!;
|
||||
tempUser.Provider = this;
|
||||
User = tempUser;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetRepositoryByURL(Uri RepoUrl, out IRepository? Repository)
|
||||
{
|
||||
if (repoPattern.IsMatch(RepoUrl.OriginalString))
|
||||
{
|
||||
var split = RepoUrl.OriginalString.Split("://")[1].Split('/');
|
||||
return TryGetRepositoryByName(split[1], split[2], out Repository);
|
||||
} else
|
||||
{
|
||||
Repository = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetUserByURL(Uri UserProfile, out IUser? User)
|
||||
{
|
||||
if (userPattern.IsMatch(UserProfile.OriginalString))
|
||||
{
|
||||
var split = UserProfile.OriginalString.Split("://")[1].Split('/');
|
||||
return TryGetUserByName(split[1], out User);
|
||||
}
|
||||
else
|
||||
{
|
||||
User = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public HttpResponseMessage GetAPIResource(string resourceLocation)
|
||||
{
|
||||
return httpClient.GetAsync(resourceLocation).Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
GithubPlugin/GithubRepo.cs
Normal file
106
GithubPlugin/GithubRepo.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using ExtensiblePortfolioSite.SDK.Git;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GithubPlugin
|
||||
{
|
||||
public class GithubRepo : IRepository
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IUser Owner { get; internal set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IGitProvider Provider { get; internal set; }
|
||||
|
||||
public ICommit? GetCommit(uint HeadOffset = 0)
|
||||
{
|
||||
var response = Provider.GetAPIResource($"repos/{Owner.Name}/{Name}/commits");
|
||||
if(response.IsSuccessStatusCode)
|
||||
{
|
||||
JsonDocument json = JsonDocument.Parse(response.Content.ReadAsStream());
|
||||
JsonElement commitObject = json.RootElement.EnumerateArray().Skip((int)HeadOffset).First();
|
||||
GithubCommit commit = JsonSerializer.Deserialize<GithubCommit>(commitObject.GetProperty("commit"))!;
|
||||
commit.Provider = Provider;
|
||||
commit.Repository = this;
|
||||
List<string> tempFiles = new List<string>();
|
||||
JsonElement files = commitObject.GetProperty("files");
|
||||
foreach(JsonElement file in files.EnumerateArray())
|
||||
{
|
||||
tempFiles.Add(file.GetProperty("filename").GetString()!);
|
||||
}
|
||||
commit.ModifiedFiles = tempFiles;
|
||||
return commit;
|
||||
} else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommit? GetCommitByRef(string reference)
|
||||
{
|
||||
var response = Provider.GetAPIResource($"repos/{Owner.Name}/{Name}/commits/{reference}");
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
JsonDocument json = JsonDocument.Parse(response.Content.ReadAsStream());
|
||||
JsonElement commitObject = json.RootElement;
|
||||
GithubCommit commit = JsonSerializer.Deserialize<GithubCommit>(commitObject.GetProperty("commit"))!;
|
||||
commit.Provider = Provider;
|
||||
commit.Repository = this;
|
||||
List<string> tempFiles = new List<string>();
|
||||
JsonElement files = commitObject.GetProperty("files");
|
||||
foreach (JsonElement file in files.EnumerateArray())
|
||||
{
|
||||
tempFiles.Add(file.GetProperty("filename").GetString()!);
|
||||
}
|
||||
commit.ModifiedFiles = tempFiles;
|
||||
return commit;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public GitReference GetReference()
|
||||
{
|
||||
return new GitReference(GitReferenceKind.Repository, $"{Owner}/{Name}");
|
||||
}
|
||||
|
||||
public bool TryGetCommit(uint HeadOffset, out ICommit? Commit)
|
||||
{
|
||||
var commit = GetCommit(HeadOffset);
|
||||
if (commit != null)
|
||||
{
|
||||
Commit = commit;
|
||||
return true;
|
||||
}
|
||||
|
||||
Commit = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetCommitByRef(string Reference, out ICommit? Commit)
|
||||
{
|
||||
var commit = GetCommitByRef(Reference);
|
||||
if (commit != null)
|
||||
{
|
||||
Commit = commit;
|
||||
return true;
|
||||
}
|
||||
|
||||
Commit = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
GithubPlugin/GithubUser.cs
Normal file
47
GithubPlugin/GithubUser.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using ExtensiblePortfolioSite.SDK.Git;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GithubPlugin
|
||||
{
|
||||
public class GithubUser : IUser
|
||||
{
|
||||
[JsonPropertyName("login")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public int Identifier { get; private set; }
|
||||
|
||||
[JsonPropertyName("avatar_url")]
|
||||
public string AvatarURL { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IGitProvider Provider { get; internal set; }
|
||||
|
||||
public GitReference GetReference()
|
||||
{
|
||||
return new GitReference(GitReferenceKind.User, $"{Name}");
|
||||
}
|
||||
|
||||
public IEnumerable<IRepository> GetUserRepositories()
|
||||
{
|
||||
var response = Provider.GetAPIResource($"users/{Name}/repos");
|
||||
if(response.IsSuccessStatusCode)
|
||||
{
|
||||
JsonDocument json = JsonDocument.Parse(response.Content.ReadAsStream());
|
||||
List<IRepository> ret = new List<IRepository>(json.RootElement.GetArrayLength());
|
||||
foreach(JsonElement repo in json.RootElement.EnumerateArray())
|
||||
{
|
||||
ret.Add(JsonSerializer.Deserialize<GithubRepo>(repo)!);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return new List<IRepository>();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
GithubPlugin/Properties/AssemblyInfo.cs
Normal file
3
GithubPlugin/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
using ExtensiblePortfolioSite.SDK.Plugins;
|
||||
|
||||
[assembly: EPSPlugin("Github", false, 1, 0)]
|
||||
Loading…
Reference in New Issue
Block a user