Browse Source

Ported existing projects to Asp.Net Core (Except ServerMaint)

core
Teknikode 4 years ago
parent
commit
5eb45263d9
  1. 10
      .editorconfig
  2. 155
      .gitignore
  3. 8
      Configuration/ApiConfig.cs
  4. 7
      Configuration/BlogConfig.cs
  5. 54
      Configuration/Config.cs
  6. 17
      Configuration/Configuration.csproj
  7. 9
      Configuration/ContactConfig.cs
  8. 0
      Configuration/DatabaseConfig.cs
  9. 8
      Configuration/EmailAccount.cs
  10. 7
      Configuration/EmailConfig.cs
  11. 8
      Configuration/GitConfig.cs
  12. 8
      Configuration/IRCConfig.cs
  13. 7
      Configuration/LoggingConfig.cs
  14. 8
      Configuration/PasteConfig.cs
  15. 8
      Configuration/PiwikConfig.cs
  16. 6
      Configuration/PodcastConfig.cs
  17. 7
      Configuration/ShortenerConfig.cs
  18. 8
      Configuration/StatsConfig.cs
  19. 6
      Configuration/StreamConfig.cs
  20. 3
      Configuration/UploadConfig.cs
  21. 7
      Configuration/UserConfig.cs
  22. 7
      Configuration/VaultConfig.cs
  23. 2
      GitVersionConfig.yaml
  24. 9
      Logging/LogMessage.cs
  25. 161
      Logging/Logger.cs
  26. 17
      Logging/LoggerExtensions.cs
  27. 30
      Logging/LoggerProvider.cs
  28. 14
      Logging/Logging.csproj
  29. 126
      MailService/HMailService.cs
  30. 27
      MailService/IMailService.cs
  31. 29
      MailService/MailService.cs
  32. 19
      MailService/MailService.csproj
  33. 173
      MailService/MysqlDatabase.cs
  34. BIN
      MailService/lib/Teknik.hMailServer.dll
  35. 13
      Piwik/Piwik.csproj
  36. 96
      Piwik/Reporting.cs
  37. 93
      Piwik/Tracking.cs
  38. 0
      Piwik/VisitorData.cs
  39. 141
      Teknik.sln
  40. 54
      Teknik/App_Start/BundleConfig.cs
  41. 51
      Teknik/App_Start/CustomRazorViewEngine.cs
  42. 17
      Teknik/App_Start/FilterConfig.cs
  43. 23
      Teknik/App_Start/RouteConfig.cs
  44. 101
      Teknik/App_Start/SubdomainRoute.cs
  45. 154
      Teknik/App_Start/SubdomainRouteExtension.cs
  46. 70
      Teknik/Areas/API/APIAreaRegistration.cs
  47. 13
      Teknik/Areas/API/Controllers/APIController.cs
  48. 246
      Teknik/Areas/API/Controllers/APIv1Controller.cs
  49. 9
      Teknik/Areas/API/Models/APIv1PasteModel.cs
  50. 5
      Teknik/Areas/API/Models/APIv1UploadModel.cs
  51. 36
      Teknik/Areas/API/Views/web.config
  52. 30
      Teknik/Areas/About/AboutAreaRegistration.cs
  53. 16
      Teknik/Areas/About/Controllers/AboutController.cs
  54. 4
      Teknik/Areas/About/ViewModels/AboutViewModel.cs
  55. 14
      Teknik/Areas/About/Views/About/Index.cshtml
  56. 36
      Teknik/Areas/About/Views/web.config
  57. 30
      Teknik/Areas/Abuse/AbuseAreaRegistration.cs
  58. 14
      Teknik/Areas/Abuse/Controllers/AbuseController.cs
  59. 1
      Teknik/Areas/Abuse/Views/Abuse/Index.cshtml
  60. 3
      Teknik/Areas/Abuse/Views/_ViewStart.cshtml
  61. 36
      Teknik/Areas/Abuse/Views/web.config
  62. 36
      Teknik/Areas/Accounts/ResourceOwnerPasswordValidator.cs
  63. 77
      Teknik/Areas/Admin/AdminAreaRegistration.cs
  64. 67
      Teknik/Areas/Admin/Controllers/AdminController.cs
  65. 2
      Teknik/Areas/Admin/Views/Admin/Dashboard.cshtml
  66. 2
      Teknik/Areas/Admin/Views/Admin/UploadResult.cshtml
  67. 12
      Teknik/Areas/Admin/Views/Admin/UploadSearch.cshtml
  68. 12
      Teknik/Areas/Admin/Views/Admin/UserInfo.cshtml
  69. 2
      Teknik/Areas/Admin/Views/Admin/UserResult.cshtml
  70. 2
      Teknik/Areas/Admin/Views/Admin/UserResults.cshtml
  71. 12
      Teknik/Areas/Admin/Views/Admin/UserSearch.cshtml
  72. 3
      Teknik/Areas/Admin/Views/_ViewStart.cshtml
  73. 36
      Teknik/Areas/Admin/Views/web.config
  74. 74
      Teknik/Areas/Blog/BlogAreaRegistration.cs
  75. 224
      Teknik/Areas/Blog/Controllers/BlogController.cs
  76. 2
      Teknik/Areas/Blog/Models/BlogPost.cs
  77. 20
      Teknik/Areas/Blog/Models/BlogPostTag.cs
  78. 18
      Teknik/Areas/Blog/ViewModels/BlogViewModel.cs
  79. 3
      Teknik/Areas/Blog/ViewModels/CommentViewModel.cs
  80. 10
      Teknik/Areas/Blog/ViewModels/CreatePostViewModel.cs
  81. 10
      Teknik/Areas/Blog/ViewModels/EditPostViewModel.cs
  82. 6
      Teknik/Areas/Blog/ViewModels/PostViewModel.cs
  83. 32
      Teknik/Areas/Blog/Views/Blog/Blog.cshtml
  84. 2
      Teknik/Areas/Blog/Views/Blog/Comment.cshtml
  85. 2
      Teknik/Areas/Blog/Views/Blog/Comments.cshtml
  86. 42
      Teknik/Areas/Blog/Views/Blog/EditPost.cshtml
  87. 42
      Teknik/Areas/Blog/Views/Blog/NewPost.cshtml
  88. 2
      Teknik/Areas/Blog/Views/Blog/Post.cshtml
  89. 2
      Teknik/Areas/Blog/Views/Blog/Posts.cshtml
  90. 26
      Teknik/Areas/Blog/Views/Blog/ViewPost.cshtml
  91. 3
      Teknik/Areas/Blog/Views/_ViewStart.cshtml
  92. 36
      Teknik/Areas/Blog/Views/web.config
  93. 44
      Teknik/Areas/Contact/ContactAreaRegistration.cs
  94. 52
      Teknik/Areas/Contact/Controllers/ContactController.cs
  95. 19
      Teknik/Areas/Contact/Views/Contact/Index.cshtml
  96. 3
      Teknik/Areas/Contact/Views/_ViewStart.cshtml
  97. 36
      Teknik/Areas/Contact/Views/web.config
  98. 17
      Teknik/Areas/Dev/Controllers/DevController.cs
  99. 31
      Teknik/Areas/Dev/DevAreaRegistration.cs
  100. 3
      Teknik/Areas/Dev/Views/_ViewStart.cshtml
  101. Some files were not shown because too many files have changed in this diff Show More

10
.editorconfig

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
indent_style = space
end_of_line = crlf
trim_trailing_whitespace = false
insert_final_newline = true
[*.cshtml]
indent_size = 4

155
.gitignore vendored

@ -4,26 +4,34 @@ @@ -4,26 +4,34 @@
# 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/
build/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Roslyn cache directories
*.ide/
# 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.*
#NUNIT
# NUNIT
*.VisualState.xml
TestResult.xml
@ -32,6 +40,11 @@ TestResult.xml @@ -32,6 +40,11 @@ TestResult.xml
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
@ -64,14 +77,18 @@ _Chutzpah* @@ -64,14 +77,18 @@ _Chutzpah*
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
@ -84,7 +101,7 @@ _ReSharper*/ @@ -84,7 +101,7 @@ _ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
@ -96,6 +113,7 @@ _TeamCity* @@ -96,6 +113,7 @@ _TeamCity*
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
@ -123,43 +141,63 @@ publish/ @@ -123,43 +141,63 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
# 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
# NuGet Packages Directory
packages/*
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
*.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
# Microsoft Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
bower_components/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
@ -184,26 +222,45 @@ UpgradeLog*.htm @@ -184,26 +222,45 @@ UpgradeLog*.htm
# Microsoft Fakes
FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
/Teknik/ConnectionStrings.config
/Teknik/App_Data/Config.json
/.vs/config/applicationhost.config
/Teknik/TransformWebConfig/assist/Web.config
/Teknik/Properties/PublishProfiles/IIS.pubxml
/Teknik/App_Data/ConnectionStrings.config
/Teknik/App_Data/Config.json.old
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
/Teknik/App_Data/MachineKey.config
/.vs/Teknik/v15/sqlite3/storage.ide
/.vs/Teknik/v15/sqlite3/storage.ide-wal
/.vs/Teknik/v15/sqlite3/storage.ide-shm
/.vs/Teknik/v15/sqlite3/db.lock
/.vs/Teknik/v15/sqlite3
/.vs/Teknik/v15/Server/sqlite3/storage.ide-wal
/.vs/Teknik/v15/Server/sqlite3/storage.ide-shm
/.vs/Teknik/v15/Server/sqlite3/storage.ide
/.vs/Teknik/v15/Server/sqlite3/db.lock
/.vs/Teknik/v15/Server/sqlite3
/.vs/Teknik/v15
/Teknik/App_Data/ConnectionStrings.config
/Teknik/App_Data/Config.json
/Teknik/appsettings.Production.json
/Teknik/appsettings.Development.json

8
Utilities/Configuration/ApiConfig.cs → Configuration/ApiConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class ApiConfig
{

7
Utilities/Configuration/BlogConfig.cs → Configuration/BlogConfig.cs

@ -1,9 +1,4 @@ @@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class BlogConfig
{

54
Utilities/Configuration/Config.cs → Configuration/Config.cs

@ -1,10 +1,7 @@ @@ -1,10 +1,7 @@
using Newtonsoft.Json;
using System;
using System.IO;
using System.Threading;
using System.Web;
using System.Web.Caching;
using Newtonsoft.Json;
using Teknik.Utilities;
using Teknik.Utilities.Cryptography;
namespace Teknik.Configuration
@ -12,9 +9,13 @@ namespace Teknik.Configuration @@ -12,9 +9,13 @@ namespace Teknik.Configuration
public class Config
{
private const string _ConfigCacheKey = "ConfigCache";
private const string _ConfigFileName = "Config.json";
private static Config _Config { get; set; }
private static string _FileHash { get; set; }
private ReaderWriterLockSlim _ConfigRWLock;
private ReaderWriterLockSlim _ConfigFileRWLock;
private JsonSerializerSettings _JsonSettings;
private bool _DevEnvironment;
@ -117,6 +118,8 @@ namespace Teknik.Configuration @@ -117,6 +118,8 @@ namespace Teknik.Configuration
public Config()
{
_ConfigRWLock = new ReaderWriterLockSlim();
_ConfigFileRWLock = new ReaderWriterLockSlim();
_JsonSettings = new JsonSerializerSettings();
_JsonSettings.Formatting = Formatting.Indented;
@ -168,39 +171,26 @@ namespace Teknik.Configuration @@ -168,39 +171,26 @@ namespace Teknik.Configuration
return JsonConvert.SerializeObject(config, Formatting.Indented);
}
public static Config Load()
{
HttpContext context = HttpContext.Current;
if (context != null)
_Config = (Config)context.Cache[_ConfigCacheKey];
if (_Config == null)
{
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
_Config = Load(path);
context?.Cache.Insert(_ConfigCacheKey, _Config, new CacheDependency(path));
}
return _Config;
}
public static Config Load(string path)
{
Config config = new Config();
if (!File.Exists(Path.Combine(path, "Config.json")))
string newHash = string.Empty;
string fullPath = Path.Combine(path, _ConfigFileName);
if (!File.Exists(fullPath))
{
Save(Path.Combine(path, "Config.json"), config);
Config config = new Config();
Save(fullPath, config);
}
else
newHash = MD5.FileHash(fullPath);
if (_Config == null || _FileHash == null || newHash != _FileHash)
{
string configContents = File.ReadAllText(Path.Combine(path, "Config.json"));
config = Deserialize(configContents);
string configContents = File.ReadAllText(fullPath);
_Config = Deserialize(configContents);
_FileHash = newHash;
}
return config;
}
public static void Save(Config config)
{
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
Save(Path.Combine(path, "Config.json"), config);
return _Config;
}
public static void Save(string path, Config config)

17
Configuration/Configuration.csproj

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>Teknik.Configuration</RootNamespace>
<AssemblyName>Teknik.Configuration</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Utilities\Utilities.csproj" />
</ItemGroup>
</Project>

9
Utilities/Configuration/ContactConfig.cs → Configuration/ContactConfig.cs

@ -1,11 +1,4 @@ @@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Mail;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class ContactConfig
{

0
Utilities/Configuration/DatabaseConfig.cs → Configuration/DatabaseConfig.cs

8
Utilities/Configuration/EmailAccount.cs → Configuration/EmailAccount.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class EmailAccount
{

7
Utilities/Configuration/EmailConfig.cs → Configuration/EmailConfig.cs

@ -1,9 +1,4 @@ @@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class EmailConfig
{

8
Utilities/Configuration/GitConfig.cs → Configuration/GitConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class GitConfig
{

8
Utilities/Configuration/IRCConfig.cs → Configuration/IRCConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class IRCConfig
{

7
Utilities/Configuration/LoggingConfig.cs → Configuration/LoggingConfig.cs

@ -1,9 +1,4 @@ @@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class LoggingConfig
{

8
Utilities/Configuration/PasteConfig.cs → Configuration/PasteConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class PasteConfig
{

8
Utilities/Configuration/PiwikConfig.cs → Configuration/PiwikConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class PiwikConfig
{

6
Utilities/Configuration/PodcastConfig.cs → Configuration/PodcastConfig.cs

@ -1,8 +1,4 @@ @@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.IO;
namespace Teknik.Configuration
{

7
Utilities/Configuration/ShortenerConfig.cs → Configuration/ShortenerConfig.cs

@ -1,9 +1,4 @@ @@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class ShortenerConfig
{

8
Utilities/Configuration/StatsConfig.cs → Configuration/StatsConfig.cs

@ -1,10 +1,4 @@ @@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class StatsConfig
{

6
Utilities/Configuration/StreamConfig.cs → Configuration/StreamConfig.cs

@ -1,8 +1,4 @@ @@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Teknik.Configuration
{

3
Utilities/Configuration/UploadConfig.cs → Configuration/UploadConfig.cs

@ -1,8 +1,5 @@ @@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
{

7
Utilities/Configuration/UserConfig.cs → Configuration/UserConfig.cs

@ -1,10 +1,3 @@ @@ -1,10 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Teknik.Utilities;
namespace Teknik.Configuration
{
public class UserConfig

7
Utilities/Configuration/VaultConfig.cs → Configuration/VaultConfig.cs

@ -1,9 +1,4 @@ @@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Teknik.Configuration
namespace Teknik.Configuration
{
public class VaultConfig
{

2
GitVersionConfig.yaml

@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
assembly-versioning-scheme: MajorMinorPatch
next-version: 2.0.6

9
Utilities/Logging/LogMessage.cs → Logging/LogMessage.cs

@ -1,8 +1,5 @@ @@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using System;
using Teknik.Utilities;
namespace Teknik.Logging
@ -21,7 +18,7 @@ namespace Teknik.Logging @@ -21,7 +18,7 @@ namespace Teknik.Logging
public void SetDefaults()
{
Level = LogLevel.Info;
Level = LogLevel.Information;
EntryDate = DateTime.Now;
Message = string.Empty;
Exception = null;

161
Logging/Logger.cs

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using Teknik.Configuration;
using Teknik.Utilities;
namespace Teknik.Logging
{
public class Logger : ILogger
{
private static readonly object Locker = new object();
private readonly string _name;
private readonly Config _config;
public Logger(string name, Config config)
{
_name = name;
_config = config;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
return;
// write an entry to the logs
LogMessage log = new LogMessage();
log.Level = logLevel;
log.Message = formatter(state, exception);
log.Exception = exception;
WriteLogMessage(log);
}
public bool IsEnabled(LogLevel logLevel)
{
if (_config.LoggingConfig.Enabled)
{
// Do we want to write a log for this level? (Default to Error)
LogLevel minLogLevel = LogLevel.Error;
Enum.TryParse(_config.LoggingConfig.LogLevel, out minLogLevel);
if (logLevel >= minLogLevel)
return true;
}
return false;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
private void WriteLogMessage(LogMessage log)
{
try
{
// Lock the file processing so only 1 thread is working on the log file at a time
lock (Locker)
{
if (!Directory.Exists(_config.LoggingConfig.OutputDirectory))
{
Directory.CreateDirectory(_config.LoggingConfig.OutputDirectory);
}
// Get current log file
string fileName = Constants.LOG_FILE_NAME_PREFIX + Constants.LOG_FILE_EXT;
string logFile = Path.Combine(_config.LoggingConfig.OutputDirectory, fileName);
if (File.Exists(logFile))
{
// File already exists, so lets see if we need to rotate it
if (_config.LoggingConfig.RotateLogs)
{
FileInfo info = new FileInfo(logFile);
if (_config.LoggingConfig.MaxSize < info.Length && _config.LoggingConfig.MaxSize > 0)
{
// File is too large, so let's create a new name for it based on todays date
string newFileName = Constants.LOG_FILE_NAME_PREFIX + "_" + DateTime.Now.ToString("yyyyMMdd") + Constants.LOG_FILE_EXT;
newFileName = FileHelper.MakeUniqueFilename(newFileName, _config.LoggingConfig.OutputDirectory);
string newLog = Path.Combine(_config.LoggingConfig.OutputDirectory, newFileName);
// Move the current file to the new file
File.Move(logFile, newLog);
}
// Make sure we have less than the max number of logs
List<string> totalFiles = Directory.GetFiles(_config.LoggingConfig.OutputDirectory, string.Format("{0}*{1}", Constants.LOG_FILE_NAME_PREFIX, Constants.LOG_FILE_EXT), SearchOption.TopDirectoryOnly).ToList();
if (totalFiles.Count + 1 > _config.LoggingConfig.MaxCount && _config.LoggingConfig.MaxCount > 0)
{
// We will have too many logs, so let's remove the last one
totalFiles.Sort();
string fileToRemove = totalFiles[totalFiles.Count - 1];
File.Delete(fileToRemove);
}
}
}
// We have rotated if needed, so let's write the entry
File.AppendAllText(logFile, log.ToString() + Environment.NewLine);
}
}
catch (Exception) { } // If we throw when writing the log, still try to send the email if needed
try
{
// Send Email Message if enabled
if (_config.LoggingConfig.SendEmail)
{
// Do we want to send an email for this level? (Default to error)
LogLevel minEmailLevel = LogLevel.Error;
Enum.TryParse(_config.LoggingConfig.EmailLevel, out minEmailLevel);
if (log.Level >= minEmailLevel)
{
string subject = string.Format("{0} Log Message", log.Level);
string message = "Message: " + log.Message;
if (log.Exception != null)
{
message += Environment.NewLine + Environment.NewLine + "Exception: " + log.Exception.GetFullMessage(true, true);
}
SendErrorEmail(subject, message);
}
}
}
catch (Exception)
{
// Can't do anything about it. :/
}
}
private void SendErrorEmail(string subject, string message)
{
try
{
// Let's also email the message to support
SmtpClient client = new SmtpClient();
client.Host = _config.LoggingConfig.SenderAccount.Host;
client.Port = _config.LoggingConfig.SenderAccount.Port;
client.EnableSsl = _config.LoggingConfig.SenderAccount.SSL;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = true;
client.Credentials = new System.Net.NetworkCredential(_config.LoggingConfig.SenderAccount.Username, _config.LoggingConfig.SenderAccount.Password);
client.Timeout = 5000;
MailMessage mail = new MailMessage(_config.LoggingConfig.SenderAccount.EmailAddress, _config.LoggingConfig.RecipientEmailAddress);
mail.Subject = subject;
mail.Body = message;
mail.BodyEncoding = UTF8Encoding.UTF8;
mail.DeliveryNotificationOptions = DeliveryNotificationOptions.Never;
client.Send(mail);
}
catch (Exception ex) { /* don't handle something in the handler */
}
}
}
}

17
Logging/LoggerExtensions.cs

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using Teknik.Configuration;
namespace Teknik.Logging
{
public static class LoggerExtensions
{
public static ILoggerFactory AddLogger(this ILoggerFactory loggerFactory, Config config)
{
loggerFactory.AddProvider(new LoggerProvider(config));
return loggerFactory;
}
}
}

30
Logging/LoggerProvider.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using Teknik.Configuration;
namespace Teknik.Logging
{
public class LoggerProvider : ILoggerProvider
{
private readonly Config _config;
private readonly ConcurrentDictionary<string, Logger> _loggers = new ConcurrentDictionary<string, Logger>();
public LoggerProvider(Config config)
{
_config = config;
}
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName, name => new Logger(name, _config));
}
public void Dispose()
{
_loggers.Clear();
}
}
}

14
Logging/Logging.csproj

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>Teknik.Logging</AssemblyName>
<RootNamespace>Teknik.Logging</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Configuration\Configuration.csproj" />
<ProjectReference Include="..\Utilities\Utilities.csproj" />
</ItemGroup>
</Project>

126
MailService/HMailService.cs

@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Teknik.MailService
{
public class HMailService : MailService
{
private readonly hMailServer.Application _App;
private string _Username { get; set; }
private string _Password { get; set; }
private string _Domain { get; set; }
private string _CounterServer { get; set; }
private string _CounterDatabase { get; set; }
private string _CounterUsername { get; set; }
private string _CounterPassword { get; set; }
private int _CounterPort { get; set; }
public HMailService(string username, string password, string domain, string counterServer, string counterDatabase, string counterUsername, string counterPassword, int counterPort)
{
_Username = username;
_Password = password;
_Domain = domain;
_CounterServer = counterServer;
_CounterDatabase = counterDatabase;
_CounterUsername = counterUsername;
_CounterPassword = counterPassword;
_CounterPort = counterPort;
_App = InitApp();
}
public override void CreateAccount(string username, string password, int size)
{
var domain = _App.Domains.ItemByName[_Domain];
var newAccount = domain.Accounts.Add();
newAccount.Address = username;
newAccount.Password = password;
newAccount.Active = true;
newAccount.MaxSize = size;
newAccount.Save();
}
public override bool AccountExists(string username)
{
try
{
GetAccount(username);
// We didn't error out, so the email exists
return true;
}
catch { }
return false;
}
public override void Delete(string username)
{
throw new NotImplementedException();
}
public override void Enable(string username)
{
EditActivity(username, true);
}
public override void Disable(string username)
{
EditActivity(username, false);
}
public override void EditActivity(string username, bool active)
{
var account = GetAccount(username);
account.Active = active;
account.Save();
}
public override void EditMaxEmailsPerDay(string username, int maxPerDay)
{
//We need to check the actual git database
MysqlDatabase mySQL = new MysqlDatabase(_CounterServer, _CounterDatabase, _CounterUsername, _CounterPassword, _CounterPort);
string sql = @"INSERT INTO mailcounter.counts (qname, lastdate, qlimit, count) VALUES ({1}, NOW(), {0}, 0)
ON DUPLICATE KEY UPDATE qlimit = {0}";
mySQL.Execute(sql, new object[] { maxPerDay, username });
}
public override void EditMaxSize(string username, int size)
{
var account = GetAccount(username);
account.MaxSize = size;
account.Save();
}
public override void EditPassword(string username, string password)
{
var account = GetAccount(username);
account.Password = password;
account.Save();
}
public override DateTime LastActive(string username)
{
var account = GetAccount(username);
return (DateTime)account.LastLogonTime;
}
private hMailServer.Application InitApp()
{
var app = new hMailServer.Application();
app.Connect();
app.Authenticate(_Username, _Password);
return app;
}
private hMailServer.Account GetAccount(string username)
{
var domain = _App.Domains.ItemByName[_Domain];
return domain.Accounts.ItemByAddress[username];
}
}
}

27
MailService/IMailService.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
using System;
namespace Teknik.MailService
{
public interface IMailService
{
bool AccountExists(string username);
DateTime LastActive(string username);
void CreateAccount(string username, string password, int size);
void EditActivity(string username, bool active);
void EditPassword(string username, string password);
void EditMaxSize(string username, int size);
void EditMaxEmailsPerDay(string username, int maxPerDay);
void Enable(string username);
void Disable(string username);
void Delete(string username);
}
}

29
MailService/MailService.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Teknik.MailService
{
public abstract class MailService : IMailService
{
public abstract void CreateAccount(string username, string password, int size);
public abstract bool AccountExists(string username);
public abstract void Delete(string username);
public abstract void Disable(string username);
public abstract void EditActivity(string username, bool active);
public abstract void EditMaxEmailsPerDay(string username, int maxPerDay);
public abstract void EditMaxSize(string username, int size);
public abstract void EditPassword(string username, string password);
public abstract void Enable(string username);
public abstract DateTime LastActive(string username);
}
}

19
MailService/MailService.csproj

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Teknik.MailService</AssemblyName>
<RootNamespace>Teknik.MailService</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.11" />
</ItemGroup>
<ItemGroup>
<Reference Include="Teknik.hMailServer">
<HintPath>lib\Teknik.hMailServer.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

173
MailService/MysqlDatabase.cs

@ -0,0 +1,173 @@ @@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Threading;
using MySql.Data.MySqlClient;
namespace Teknik.MailService
{
public class MysqlDatabase
{
public event EventHandler<string> MysqlErrorEvent;
private bool Connected { get; set; }
private MySqlConnection Connection { get; set; }
private ReaderWriterLockSlim DatabaseLock { get; set; }
public MysqlDatabase(string server, string database, string username, string password, int port)
{
Connected = false;
Connection = null;
DatabaseLock = new ReaderWriterLockSlim();
Connect(server, database, username, password, port);
}
public List<Dictionary<string, object>> Query(string query, params object[] args)
{
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
if (Connected)
{
DatabaseLock.EnterWriteLock();
MySqlCommand cmd = PrepareQuery(query, args);
try
{
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Dictionary<string, object> row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
{
row.Add(reader.GetName(i), reader.GetValue(i));
}
rows.Add(row);
}
reader.Close();
}
catch (MySqlException exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
catch (Exception exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
DatabaseLock.ExitWriteLock();
}
return rows;
}
public object ScalarQuery(string query, params object[] args)
{
if (Connected)
{
DatabaseLock.EnterWriteLock();
MySqlCommand cmd = PrepareQuery(query, args);
object result = null;
try
{
result = cmd.ExecuteScalar();
}
catch (MySqlException exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
catch (Exception exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
DatabaseLock.ExitWriteLock();
return result;
}
return null;
}
public void Execute(string query, params object[] args)
{
if (Connected)
{
DatabaseLock.EnterWriteLock();
MySqlCommand cmd = PrepareQuery(query, args);
try
{
int result = cmd.ExecuteNonQuery();
}
catch (MySqlException exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
catch (Exception exception)
{
if (MysqlErrorEvent != null)
{
MysqlErrorEvent(this, exception.Message);
}
}
DatabaseLock.ExitWriteLock();
}
}
private void Connect(string server, string database, string username, string password, int port)
{
if (Connection == null)
{
if (!string.IsNullOrEmpty(server) && !string.IsNullOrEmpty(database) && !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
{
string strCon = string.Format("Server={0}; database={1}; user={2}; password={3}; port={4}; charset=utf8; Allow Zero Datetime=true;", server, database, username, password, port);
Connection = new MySqlConnection(strCon);
try
{
Connection.Open();
Connected = true;
}
catch (MySqlException ex)
{
Connected = false;
}
}
}
}
private void Disconnect()
{
if (Connection != null && Connected)
{
Connected = false;
Connection.Close();
}
}
private MySqlCommand PrepareQuery(string query, object[] args)
{
if (Connected)
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = Connection;
for (int i = 0; i < args.Length; i++)
{
string param = "{" + i + "}";
string paramName = "@DBVar_" + i;
query = query.Replace(param, paramName);
cmd.Parameters.AddWithValue(paramName, args[i]);
}
cmd.CommandText = query;
return cmd;
}
return null;
}
}
}

BIN
MailService/lib/Teknik.hMailServer.dll

Binary file not shown.

13
Piwik/Piwik.csproj

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>Teknik.Piwik</AssemblyName>
<RootNamespace>Teknik.Piwik</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Configuration\Configuration.csproj" />
</ItemGroup>
</Project>

96
Piwik/Reporting.cs

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Teknik.Configuration;
namespace Teknik.Piwik
{
public static class Reporting
{
public static List<VisitorData> GetVisitSummaryByDays(Config config, int days)
{
List<VisitorData> visitorData = new List<VisitorData>();
try
{
if (config.PiwikConfig.Enabled)
{
//PiwikAnalytics.URL = config.PiwikConfig.API;
//VisitsSummary visitSummary = new VisitsSummary();
//visitSummary.setTokenAuth(config.PiwikConfig.TokenAuth);
//Hashtable results = visitSummary.Get(
// config.PiwikConfig.SiteId,
// PiwikPeriod.DAY,
// RelativeRangeDate.LAST(days)
// );
//foreach (string period in results.Keys)
//{
// // Create a new object to return
// VisitorData data = new VisitorData();
// // Set Period Date
// DateTime date = new DateTime(1900, 1, 1);
// DateTime.TryParse(period, out date);
// data.Date = date;
// // Pull Out Data
// if (results[period].GetType() == typeof(Hashtable))
// {
// Hashtable result = (Hashtable) results[period];
// int UniqueVisitors = 0;
// int.TryParse(result["nb_uniq_visitors"].ToString(), out UniqueVisitors);
// data.UniqueVisitors = UniqueVisitors;
// int visits = 0;
// int.TryParse(result[VisitsSummary.NB_VISITS].ToString(), out visits);
// data.Visits = visits;
// int VisitsConverted = 0;
// int.TryParse(result[VisitsSummary.NB_VISITS_CONVERTED].ToString(), out VisitsConverted);
// data.VisitsConverted = VisitsConverted;
// int Actions = 0;
// int.TryParse(result[VisitsSummary.NB_ACTIONS].ToString(), out Actions);
// data.Actions = Actions;
// decimal ActionsPerVisit = 0;
// decimal.TryParse(result[VisitsSummary.NB_ACTIONS_PER_VISIT].ToString(), out ActionsPerVisit);
// data.ActionsPerVisit = ActionsPerVisit;
// int MaxActions = 0;
// int.TryParse(result[VisitsSummary.MAX_ACTIONS].ToString(), out MaxActions);
// data.MaxActions = MaxActions;
// int BounceCount = 0;
// int.TryParse(result[VisitsSummary.BOUNCE_COUNT].ToString(), out BounceCount);
// data.BounceCount = BounceCount;
// data.BounceRate = result[VisitsSummary.BOUNCE_RATE].ToString();
// int AverageTimeOnSite = 0;
// int.TryParse(result[VisitsSummary.AVG_TIME_ON_SITE].ToString(), out AverageTimeOnSite);
// data.AverageTimeOnSite = AverageTimeOnSite;
// int VisitLengthTotal = 0;
// int.TryParse(result[VisitsSummary.SUM_VISIT_LENGTH].ToString(), out VisitLengthTotal);
// data.VisitLengthTotal = VisitLengthTotal;
// }
// visitorData.Add(data);
//}
}
}
catch (Exception ex)
{
}
return visitorData;
}
}
}

93
Piwik/Tracking.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
using System;
using System.Web;
using Teknik.Configuration;
using Teknik.Utilities;
namespace Teknik.Piwik
{
public static class Tracking
{
public static void TrackPageView(Config config, string title, string sub, string clientIp, string url, string urlReferrer, string userAgent, int pixelWidth, int pixelHeight, bool hasCookies, string acceptLang, bool hasJava)
{
try
{
if (config.PiwikConfig.Enabled)
{
if (config.DevEnvironment)
{
sub = "dev - " + sub;
}
//PiwikTracker.URL = config.PiwikConfig.Url;
//PiwikTracker tracker = new PiwikTracker(config.PiwikConfig.SiteId, config.PiwikConfig.Url);
//// Set Request Info
//tracker.setIp(clientIp);
//tracker.setTokenAuth(config.PiwikConfig.TokenAuth);
//tracker.setUserAgent(userAgent);
//// Set browser info
//tracker.setResolution(pixelWidth, pixelHeight);
//tracker.setBrowserHasCookies(hasCookies);
//if (!string.IsNullOrEmpty(acceptLang))
// tracker.setBrowserLanguage(acceptLang);
//tracker.setPlugins(new BrowserPlugins {java = hasJava});
//// Get Referral
//if (!string.IsNullOrEmpty(urlReferrer))
// tracker.setUrlReferrer(urlReferrer);
//if (!string.IsNullOrEmpty(url))
// tracker.setUrl(url);
//// Send the tracking request
//tracker.doTrackPageView(string.Format("{0}/{1}", sub, title));
}
}
catch (Exception ex)
{
}
}
public static void TrackDownload(Config config, string userAgent, string clientIp, string url, string urlReferrer)
{
//TrackAction(config. PiwikTracker.ActionType.download, userAgent, clientIp, url, urlReferrer);
}
public static void TrackLink(Config config, string userAgent, string clientIp, string url, string urlReferrer)
{
//TrackAction(config.PiwikTracker.ActionType.link, userAgent, clientIp, url, urlReferrer);
}
//private static void TrackAction(Config config, PiwikTracker.ActionType type, string userAgent, string clientIp, string url, string urlReferrer)
//{
// try
// {
// if (config.PiwikConfig.Enabled)
// {
// PiwikTracker tracker = new PiwikTracker(config.PiwikConfig.SiteId, config.PiwikConfig.Url);
// tracker.setUserAgent(userAgent);
// tracker.setIp(clientIp);
// tracker.setTokenAuth(config.PiwikConfig.TokenAuth);
// // Get Referral
// if (!string.IsNullOrEmpty(urlReferrer))
// tracker.setUrlReferrer(urlReferrer);
// if (!string.IsNullOrEmpty(url))
// tracker.setUrl(url);
// tracker.doTrackAction(url, type);
// }
// }
// catch (Exception ex)
// {
// }
//}
}
}

0
Utilities/Piwik/VisitorData.cs → Piwik/VisitorData.cs

141
Teknik.sln

@ -1,125 +1,62 @@ @@ -1,125 +1,62 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.15
VisualStudioVersion = 15.0.27512.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Teknik", "Teknik\Teknik.csproj", "{B20317CD-76C6-4A7B-BCE1-E4BEF8E4F964}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Teknik", "Teknik\Teknik.csproj", "{1E52F0D0-9E89-4022-A905-C685EF3564E1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{725ABF52-FD44-4682-81BB-D93598787643}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
GitVersionConfig.yaml = GitVersionConfig.yaml
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerMaint", "ServerMaint\ServerMaint.csproj", "{E08975F9-1B84-41B0-875A-CEC9778C4F9E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{783361EC-DCD6-4A34-8479-5476DF752C34}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utilities", "Utilities\Utilities\Utilities.csproj", "{F45DE6FC-3754-4954-A20A-4277362CC6C1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Configuration", "Configuration\Configuration.csproj", "{7A1F40CA-7C37-4B7B-973A-CDCDD424F31F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Utilities\Logging\Logging.csproj", "{77E865FD-F08B-4F07-9676-BC2FDCC7244C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utilities", "Utilities\Utilities.csproj", "{DD521101-7F10-407A-9788-49283D946FDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piwik", "Utilities\Piwik\Piwik.csproj", "{C492C2C6-D45A-498B-84A2-6D4C8BF9DE77}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging", "Logging\Logging.csproj", "{3CAB11F5-9B07-4D17-BB00-725149087AB0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Configuration", "Utilities\Configuration\Configuration.csproj", "{F0DA1B67-AF92-4B4A-8669-7E81645FF996}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikStreaming", "TeknikStreaming\TeknikStreaming.csproj", "{7695CE9A-A0DB-4D73-BC9B-2206481F0254}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FAC9FE6E-9AA9-45AD-AA72-40DDF7DC44C6}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C208CBF0-078E-409D-A433-DC1BC15248CE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtilitiesTests", "UtilitiesTests\UtilitiesTests.csproj", "{88DEB506-3F7E-4B39-8264-861976DC7434}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Piwik", "Piwik\Piwik.csproj", "{F8823907-092C-4055-9F8E-D6756793C24A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikTests", "TeknikTests\TeknikTests.csproj", "{9D7A805E-2629-476E-B36A-040AD332C7DC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MailService", "MailService\MailService.csproj", "{03636C30-DA61-4307-8934-2FCC3BAC3255}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B20317CD-76C6-4A7B-BCE1-E4BEF8E4F964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B20317CD-76C6-4A7B-BCE1-E4BEF8E4F964}.Debug|Any CPU.Build.0 = Debug|Any CPU