| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 | 
							- using InABox.Clients;
 
- using InABox.Configuration;
 
- using InABox.Core.Postable;
 
- using System;
 
- using System.Collections.Generic;
 
- using System.Linq;
 
- using System.Reflection;
 
- using System.Text;
 
- namespace InABox.Core
 
- {
 
-     public interface IPosterEngine<TPostable>
 
-         where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
 
-     {
 
-         IPostResult<TPostable>? Process(IDataModel<TPostable> model);
 
-     }
 
-     public interface IPosterEngine<TPostable, TPoster, TSettings> : IPosterEngine<TPostable>
 
-         where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
 
-         where TPoster : IPoster<TPostable, TSettings>
 
-         where TSettings : PosterSettings, new()
 
-     {
 
-     }
 
-     internal static class PosterEngineUtils
 
-     {
 
-         private static Type[]? _posters;
 
-         public static Type GetPoster(Type TPoster)
 
-         {
 
-             _posters ??= CoreUtils.TypeList(
 
-                 AppDomain.CurrentDomain.GetAssemblies(),
 
-                 x => x.IsClass
 
-                     && !x.IsAbstract
 
-                     && !x.IsGenericType
 
-                     && x.HasInterface(typeof(IPoster<,>))
 
-             ).ToArray();
 
-             return _posters.Where(x => TPoster.IsAssignableFrom(x)).FirstOrDefault()
 
-                 ?? throw new Exception($"No poster of type {TPoster}.");
 
-         }
 
-     }
 
-     /// <summary>
 
-     /// A base class for all <see cref="IPosterEngine{TPostable}"/>. A concrete instance of this will be loaded by
 
-     /// <see cref="PosterUtils.Process{T}(IDataModel{T})"/>; a new instance is guaranteed to be created each time that method is called.
 
-     /// </summary>
 
-     /// <typeparam name="TPostable"></typeparam>
 
-     /// <typeparam name="TPoster"></typeparam>
 
-     /// <typeparam name="TSettings"></typeparam>
 
-     public abstract class PosterEngine<TPostable, TPoster, TSettings> : IPosterEngine<TPostable, TPoster, TSettings>
 
-         where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
 
-         where TPoster : class, IPoster<TPostable, TSettings>
 
-         where TSettings : PosterSettings, new()
 
-     {
 
-         protected TPoster Poster;
 
-         public PosterEngine()
 
-         {
 
-             Poster = CreatePoster();
 
-         }
 
-         private static readonly Type? PosterType = PosterEngineUtils.GetPoster(typeof(TPoster));
 
-         protected virtual TPoster CreatePoster()
 
-         {
 
-             var poster = (Activator.CreateInstance(PosterType!) as TPoster)!;
 
-             poster.Settings = GetSettings();
 
-             return poster;
 
-         }
 
-         private TSettings? _settings;
 
-         protected TSettings GetSettings()
 
-         {
 
-             _settings ??= PosterUtils.LoadPosterSettings<TPostable, TSettings>();
 
-             return _settings;
 
-         }
 
-         protected void SaveSettings(TSettings settings)
 
-         {
 
-             _settings = settings;
 
-             PosterUtils.SavePosterSettings<TPostable, TSettings>(_settings);
 
-         }
 
-         /// <summary>
 
-         /// Returns the <see cref="TSettings.Script"/>, if <see cref="TSettings.ScriptEnabled"/> is <see langword="true"/>;
 
-         /// otherwise, returns <see langword="null"/>.
 
-         /// </summary>
 
-         protected string? GetScript()
 
-         {
 
-             var settings = GetSettings();
 
-             return settings.ScriptEnabled ? settings.Script : null;
 
-         }
 
-         protected abstract IPostResult<TPostable> DoProcess(IDataModel<TPostable> model);
 
-         /// <summary>
 
-         /// Process the <paramref name="model"/> before loading;
 
-         /// </summary>
 
-         /// <param name="model"></param>
 
-         /// <returns><see langword="false"/> if the processing must be cancelled.</returns>
 
-         public abstract bool BeforePost(IDataModel<TPostable> model);
 
-         /// <summary>
 
-         /// Prior to saving the <typeparamref name="TPostable"/> entities, make any necessary changes to those entities.
 
-         /// This is only called if <see cref="Process(IDataModel{TPostable})"/> returned <see langword="true"/>.
 
-         /// </summary>
 
-         /// <param name="model"></param>
 
-         /// <param name="result">The result object returned by <see cref="DoProcess(IDataModel{TPostable})"/></param>
 
-         public abstract void AfterPost(IDataModel<TPostable> model, IPostResult<TPostable> result);
 
-         private static void SetFailed(IList<TPostable> entities)
 
-         {
 
-             foreach (var post in entities)
 
-             {
 
-                 post.PostedStatus = PostedStatus.PostFailed;
 
-                 post.PostedNote = "Post failed.";
 
-             }
 
-             new Client<TPostable>().Save(entities, "Post failed by user.");
 
-         }
 
-         public IPostResult<TPostable>? Process(IDataModel<TPostable> model)
 
-         {
 
-             if (!BeforePost(model))
 
-             {
 
-                 return null;
 
-             }
 
-             // Add posted flags; if the columns is null, then we don't need to worry, because it will be loaded.
 
-             model.GetColumns<TPostable>()?.Add(x => x.PostedStatus)
 
-                 .Add(x => x.Posted)
 
-                 .Add(x => x.PostedNote);
 
-             model.LoadModel();
 
-             var data = model.GetTable<TPostable>();
 
-             if (!data.Rows.Any())
 
-             {
 
-                 throw new EmptyPostException();
 
-             }
 
-             if(data.Rows.Any(x => x.Get<TPostable, PostedStatus>(x => x.PostedStatus) == PostedStatus.Posted))
 
-             {
 
-                 throw new RepostedException();
 
-             }
 
-             try
 
-             {
 
-                 var result = DoProcess(model);
 
-                 AfterPost(model, result);
 
-                 new Client<TPostable>().Save(result.PostedEntities, "Posted by user.");
 
-                 foreach (var (type, fragments) in result.Fragments)
 
-                 {
 
-                     Client.Create(type).Save(fragments.Cast<Entity>(), "");
 
-                 }
 
-                 return result;
 
-             }
 
-             catch (PostCancelledException)
 
-             {
 
-                 var entities = data.ToObjects<TPostable>().ToList();
 
-                 SetFailed(entities);
 
-                 throw;
 
-             }
 
-             catch(Exception e)
 
-             {
 
-                 Logger.Send(LogType.Error, "", $"Post Failed: {CoreUtils.FormatException(e)}");
 
-                 var entities = data.ToObjects<TPostable>().ToList();
 
-                 SetFailed(entities);
 
-                 throw;
 
-             }
 
-         }
 
-     }
 
- }
 
 
  |