using InABox.Core; using InABox.Core.Postable; using MYOB.AccountRight.SDK; using MYOB.AccountRight.SDK.Contracts; using MYOB.AccountRight.SDK.Services; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Windows; using System.Windows.Controls; namespace InABox.Poster.MYOB; public class MYOBConnectionData(ApiConfiguration configuration, CompanyFileService cfService, IOAuthKeyService authKey) { public ApiConfiguration Configuration { get; set; } = configuration; public CompanyFileService CompanyFileService { get; set; } = cfService; public CompanyFile? CompanyFile { get; set; } public CompanyFileCredentials? CompanyFileCredentials { get; set; } public CompanyFileWithResources? ActiveCompanyFile { get; set; } public IOAuthKeyService AuthKey { get; set; } = authKey; } public abstract partial class MYOBPosterEngine : PosterEngine, TSettings>, IGlobalSettingsPosterEngine, MYOBGlobalPosterSettings> where TPostable : Entity, IPostable, IRemotable, IPersistent, new() where TSettings : MYOBPosterSettings, new() { internal static readonly string DEV_KEY = "f3b27f88-2ef9-4d8e-95c1-d0a045d0afee"; internal static readonly string SECRET_KEY = "ksm0e8yo6oumcPb63A8cduaN"; internal const string AUTH_URL = "https://secure.myob.com/oauth2/account/authorize"; internal const string AUTH_SCOPE = "CompanyFile"; internal const string REDIRECT_URL = "http://desktop"; private static MYOBConnectionData? _connectionData; private MYOBGlobalPosterSettings GetGlobalSettings() => (this as IGlobalSettingsPosterEngine, MYOBGlobalPosterSettings>).GetGlobalSettings(); public override bool BeforePost(IDataModel model) { return Poster.BeforePost(model); } public static bool GetAuthorisationCode(IApiConfiguration config, out string? code) { var url = $"{AUTH_URL}?client_id={config.ClientId}&redirect_uri={HttpUtility.UrlEncode(config.RedirectUrl)}&scope={AUTH_SCOPE}&response_type=code"; var window = new Window { Width = 800, Height = 600, Title = "Sign in to MYOB" }; string? resultCode = null; var browser = new System.Windows.Forms.WebBrowser(); browser.DocumentTitleChanged += (o, e) => { var htmlText = browser.DocumentText; if(htmlText is not null) { var match = CodeRegex().Match(htmlText); if (match.Success) { resultCode = match.Groups[1].Value; window.DialogResult = true; window.Close(); } } }; browser.Navigate(url); window.Content = browser; if(window.ShowDialog() == true) { code = resultCode; return true; } else { code = null; return false; } } private static MYOBConnectionData GetConnectionData() { if(_connectionData is MYOBConnectionData data) { return data; } var configuration = new ApiConfiguration(DEV_KEY, SECRET_KEY, REDIRECT_URL); var authService = new OAuthService(configuration); if(!GetAuthorisationCode(configuration, out var code)) { throw new PostCancelledException(); } if(code is null) { throw new PostFailedMessageException("No authorisation code was received."); } var keystore = new SimpleOAuthKeyService { OAuthResponse = authService.GetTokens(code) }; var cfService = new CompanyFileService(configuration, null, keystore); _connectionData = new MYOBConnectionData(configuration, cfService, keystore); return _connectionData; } protected override IPostResult DoProcess(IDataModel model) { var data = GetConnectionData(); var globalSettings = GetGlobalSettings(); if(data.CompanyFile is null || data.CompanyFile.Id != globalSettings.CompanyFileID) { if(globalSettings.CompanyFileID == Guid.Empty) { throw new PostFailedMessageException("No CompanyFileID has been set."); } else if(globalSettings.CompanyFileUserID.IsNullOrWhiteSpace() || globalSettings.CompanyFilePassword.IsNullOrWhiteSpace()) { throw new PostFailedMessageException("CompanyFile credentials have not been set."); } var companyFile = data.CompanyFileService.GetRange().FirstOrDefault(x => x.Id == globalSettings.CompanyFileID); var fileCredentials = new CompanyFileCredentials(globalSettings.CompanyFileUserID, globalSettings.CompanyFilePassword); data.CompanyFile = companyFile; data.CompanyFileCredentials = fileCredentials; data.ActiveCompanyFile = data.CompanyFileService.Get(companyFile, fileCredentials); } Poster.ConnectionData = data; return Poster.Process(model); } public override void AfterPost(IDataModel model, IPostResult result) { } [GeneratedRegex("code=(.*)<")] private static partial Regex CodeRegex(); }