Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,65 @@ dist

# TernJS port file
.tern-port

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets

# SQL Server files
*.mdf
*.ldf
108 changes: 108 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;

namespace src
{
class Program
{
static readonly HttpClient httpClient = new HttpClient();

public static async Task<int> Main(string[] args)
{
int returnValue = 0;
using (var host = CreateHostBuilder(args).Build())
{
host.Services.GetService<DiagnosticTimer>().Restart();
using (var scope = host.Services.CreateScope())
{
await host.StartAsync();
InitializeMapping(scope);
/* TODO: Code Goes Here */
RecordsProcessor recordsProcessor = scope.ServiceProvider.GetService<RecordsProcessor>();
recordsProcessor.SetClientProperties(httpClient);
/* TODO: Retry to get token */
var token = await recordsProcessor.UserLoginAsync(httpClient);
/* TODO: Retry to get results */
returnValue = await recordsProcessor.ProcessRecords(httpClient, token);
await host.StopAsync();
}
await Console.Out.WriteLineAsync($"FinishTime: {host.Services.GetService<DiagnosticTimer>().FinishTime()}");
}
return returnValue;
}

internal static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
var switchMapping = new Dictionary<string, string>
{
{ "-g", "GenerateReportOnly" },
{ "--generate-report-only", "GenerateReportOnly" },
{ "-pw", "ApiPassword" },
{ "-api-password", "ApiPassword" }
};

config.AddCommandLine(args, switchMapping);
})
.ConfigureServices((hostContext, services) =>
{
/*
* The next four code statements are equivalent to the line
* `services.AddHydrogenApplication<AppStartupModule<IdentityNameProvider>>();`
* in a Web Startup.cs file.
* */
services.Configure<MapperConfigurationExpression>(options =>
options.AddMaps(new[] {
typeof(AppMappingModule).Assembly,
typeof(OrganizationMappingModule).Assembly
}));

services.RegisterModule(module:
new LogicDependencyModule<AppDataInitializer,
EmailTransmitter,
IdentityProvider>()
);

/* Organization mapping and module dependencies */
services.RegisterModule(module:
new OrganizationDependencyModule<OrganizationDbContext>()
);

var configuration = hostContext.Configuration;
services.Configure<AppOptions>(configuration);
services.Configure<HydrogenOrganizationalOptions>(configuration);
services.Configure<HydrogenEntityFrameworkOptions>(configuration);
services.Configure<HydrogenEmailOptions>(configuration);
services.AddOptions();

// Register identity
services.AddScoped<IIdentityProvider<string>, IdentityProvider>();
services.AddScoped<IIdentityProvider<KeyPerson>, KeyPersonIdentityProvider>();
services.AddScoped<IIdentityProvider<BasicPerson>, BasicPersonIdentityProvider>();
services.AddScoped<IRootDirectoryProvider, RootDirectoryProvider>();

// Other dependencies
services.AddScoped<IFileManager, FileManager>();
services.AddScoped<IDirectoryManager, DirectoryManager>();
services.AddScoped<IRootDirectoryProvider>(s =>
{
return new RootDirectoryProvider()
{
Path = Directory.GetCurrentDirectory()
};
});
services.AddScoped<SmtpClient>();

services.AddScoped<DiagnosticTimer>();
services.AddScoped<RecordsProcessor>();

services.AddSingleton<DiagnosticTimer>();
});

internal static void InitializeMapping(IServiceScope scope)
{
var options = scope.ServiceProvider.GetService<IOptions<MapperConfigurationExpression>>();
Mapper.Initialize(options.Value);
}
}
}
48 changes: 48 additions & 0 deletions src/VBrick.ConsoleApp/AppOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Text;

namespace VBrick.ConsoleApp
{
/// <summary>
/// Class used with <see cref="IOptions{TOptions}"/> to extract
/// settings from an appsettings.json file.
/// </summary>
public class AppOptions
{
/// <summary>
/// Base address for the VBrick server
/// </summary>
public string ApiBaseAddress { get; set; }
/// <summary>
/// VBrick account to use against API
/// </summary>
public string ApiUsername { get; set; }
/// <summary>
/// VBrick password.
/// This should be passed by console argument.
/// For Visual Studio, this can be added by right-clicking the Console Project,
/// Properties > Debug tab then adding the string -pw "YOUR_PASSWORD" to the arguments.
/// </summary>
public string ApiPassword { get; set; }
/// <summary>
/// HttpClient timeout, in seconds
/// </summary>
public int ApiClientTimeout { get; set; }
/// <summary>
/// When hooked up to a database, the limit to which to add records
/// before flushing to the database.
///
/// For example, Entity Framework Core
/// can add records via a DbSet Add, then call SaveAsync() to flush the
/// results to the database.
/// </summary>
public int BulkLimit { get; set; }
/// <summary>
/// When hooked up to a database, informs the console application
/// not to write to the database but write instead to the logger.
/// </summary>
public bool? GenerateReportOnly { get; set; }
}
}
62 changes: 62 additions & 0 deletions src/VBrick.ConsoleApp/Models/VideoReport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
using VBrick.ConsoleApp.Processing;

namespace VBrick.ConsoleApp.Models
{
public class VideoReport
{
/// <summary>
/// Primary key for storing record into database
/// </summary>
[JsonIgnore]
public Guid Id { get; set; }
[JsonPropertyName("videoId")]
public Guid VideoId { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("username")]
public string Username { get; set; }
[JsonPropertyName("firstName")]
public string FirstName { get; set; }
[JsonPropertyName("lastName")]
public string LastName { get; set; }
[JsonPropertyName("emailAddress")]
public string EmailAddress { get; set; }
[JsonIgnore]
public string DepartmentOrSector { get; set; }
[JsonIgnore]
public string Group { get; set; }
[JsonIgnore]
public string Section { get; set; }
[JsonPropertyName("completed")]
public bool Completed { get; set; }
[JsonPropertyName("zone")]
public string Zone { get; set; }
[JsonPropertyName("device")]
public string Device { get; set; }
[JsonPropertyName("browser")]
public string Browser { get; set; }
[JsonPropertyName("userDeviceType")]
public string UserDeviceType { get; set; }
[JsonPropertyName("playbackUrl")]
public string PlaybackUrl { get; set; }
[JsonPropertyName("dateViewed")]
[JsonConverter(typeof(DateTimeOffsetJsonConverter))]
public DateTimeOffset DateViewed { get; set; }
[JsonPropertyName("viewingTime")]
[JsonConverter(typeof(TimeSpanJsonConverter))]
public TimeSpan ViewingTime { get; set; }
[JsonPropertyName("viewingStartTime")]
public DateTimeOffset ViewingStartTime { get; set; }
[JsonPropertyName("viewingEndTime")]
public DateTimeOffset ViewingEndTime { get; set; }

public override string ToString()
{
return String.Format("{{\"Id\":\"{0}\", \"Title\":\"{1}\", \"DateViewed\":\"{2}\"}}", this.Id, this.Title, this.DateViewed.ToString("O"));
}
}
}
35 changes: 35 additions & 0 deletions src/VBrick.ConsoleApp/Processing/DateTimeOffsetJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Reference
* https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-core-3-1#sample-basic-converter
* */
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace VBrick.ConsoleApp.Processing
{
/// <summary>
/// Converts between a DateTimeOffset and a specific date string format.
/// </summary>
public class DateTimeOffsetJsonConverter : JsonConverter<DateTimeOffset>
{
private const string DATE_FORMAT = "MM/dd/yyyy HH:mm:ss";

public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
DateTimeOffset.ParseExact(reader.GetString(),
DATE_FORMAT, CultureInfo.InvariantCulture);

public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue.ToString(
DATE_FORMAT, CultureInfo.InvariantCulture));
}
}
35 changes: 35 additions & 0 deletions src/VBrick.ConsoleApp/Processing/TimeSpanJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Reference
* https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-core-3-1#sample-basic-converter
* */
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace VBrick.ConsoleApp.Processing
{
/// <summary>
/// Converts between a TimeSpan and a specific time string format.
/// </summary>
public class TimeSpanJsonConverter : JsonConverter<TimeSpan>
{
private const string TIME_FORMAT = "c";

public override TimeSpan Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
TimeSpan.ParseExact(reader.GetString(),
TIME_FORMAT, CultureInfo.InvariantCulture);

public override void Write(
Utf8JsonWriter writer,
TimeSpan timeSpanValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(timeSpanValue.ToString(
TIME_FORMAT, CultureInfo.InvariantCulture));
}
}
Loading