210409PX Many small improvements & changes:
Fixed FormMail not throwing an exception for failed sending Fixed MV List not refreshed after changes Added error handling to all places where FormMail.Send() is used Refactored MvInvitationProcess to SerialMailProcess<T> in order to be able to send multiple mails via a process window Some GUI changes to MV window Added code to start and finish a MV, added Textbox for entering AuthCodes Added a way to select/deselect entries by code in CustomListView
This commit is contained in:
parent
72f4b879e1
commit
3dcb107aae
126
core/Cronjob.cs
126
core/Cronjob.cs
|
@ -94,15 +94,22 @@ namespace dezentrale.core
|
|||
{
|
||||
//Send greetings mail,//send mail to vorstand
|
||||
m.StartLogEvent("Sending greetings", LogEvent.eEventType.Greetings, "automatic");
|
||||
FormMail
|
||||
tmp = FormMail.GenerateNewMemberWelcome().ReplaceReflect(m);
|
||||
LogSubEvent lse = tmp.Send();
|
||||
m.CurrentLog.SubEvents.Add(lse);
|
||||
if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to user failed");
|
||||
tmp = FormMail.GenerateNewMemberVorstand().ReplaceReflect(Program.config.VS).ReplaceReflect(m);
|
||||
lse = tmp.Send();
|
||||
m.CurrentLog.SubEvents.Add(lse);
|
||||
if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to vorstand failed");
|
||||
try
|
||||
{
|
||||
FormMail tmp = FormMail.GenerateNewMemberWelcome().ReplaceReflect(m);
|
||||
LogSubEvent lse = tmp.Send();
|
||||
m.CurrentLog.SubEvents.Add(lse);
|
||||
if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to user failed");
|
||||
} catch (Exception ex) { throw ex; }
|
||||
|
||||
try
|
||||
{
|
||||
FormMail tmp = FormMail.GenerateNewMemberVorstand().ReplaceReflect(Program.config.VS).ReplaceReflect(m);
|
||||
LogSubEvent lse = tmp.Send();
|
||||
m.CurrentLog.SubEvents.Add(lse);
|
||||
if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to vorstand failed");
|
||||
|
||||
} catch(Exception ex) { throw ex; }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -192,9 +199,22 @@ namespace dezentrale.core
|
|||
TimeSpan tsLastMail = ProgramStartTime.Subtract(m.LastCronjobReducedFeeMail);
|
||||
if (ts.TotalDays > 0 && ts.TotalDays > 6) //remind if late and max. once a week
|
||||
{
|
||||
m.StartLogEvent($"Reminder to hand in reduced fee prove", LogEvent.eEventType.EMail, "automatic");
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateReducedFeeReminder().Send(m));
|
||||
m.LastCronjobReducedFeeMail = ProgramStartTime;
|
||||
m.StartLogEvent($"Reminder to hand in reduced fee prove", LogEvent.eEventType.EMail, "automatic");
|
||||
LogSubEvent lse;
|
||||
try
|
||||
{
|
||||
lse = FormMail.GenerateReducedFeeReminder().Send(m);
|
||||
m.LastCronjobReducedFeeMail = ProgramStartTime;
|
||||
} catch(Exception ex)
|
||||
{
|
||||
lse = new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "CheckReducedFeeValidity",
|
||||
Details = $"Cannot send reminder mail: {ex.Message}"
|
||||
};
|
||||
}
|
||||
m.CurrentLog.SubEvents.Add(lse);
|
||||
m.SaveToFile();
|
||||
}
|
||||
}
|
||||
|
@ -283,8 +303,20 @@ namespace dezentrale.core
|
|||
if (sm != null)
|
||||
{
|
||||
FormMail above200 = FormMail.GenerateBalanceAbove200NotifySM().ReplaceReflect(m);
|
||||
above200.To = $"{sm.EMailName} <{sm.EMail}>";
|
||||
m.CurrentLog.SubEvents.Add(above200.Send());
|
||||
above200.To = $"{sm.EMailName} <{sm.EMail}>";
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(above200.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "(balance too high) Can't send Mail to Schatzmeister",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"(balance too high) Can't send Mail to Schatzmeiste: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
Console.WriteLine("ERROR: CheckBalance_PostDegrade: sm = null");
|
||||
|
@ -300,8 +332,20 @@ namespace dezentrale.core
|
|||
{
|
||||
if (!skipInsufficientNotify)
|
||||
{
|
||||
m.StartLogEvent($"Insufficient amount of payments #1", LogEvent.eEventType.EMail, "automatic");
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify1().Send(m));
|
||||
m.StartLogEvent($"Insufficient amount of payments #1", LogEvent.eEventType.EMail, "automatic");
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify1().Send(m));
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "Email notification error",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #1 notification: {ex.Message}");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -312,19 +356,61 @@ namespace dezentrale.core
|
|||
if(debtLevelDecrease)
|
||||
{
|
||||
m.StartLogEvent($"Insufficient amount of payments #2", LogEvent.eEventType.EMail, "automatic");
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify2().Send(m));
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify2().Send(m));
|
||||
} catch (Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "Email notification error",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #2 notification: {ex.Message}");
|
||||
}
|
||||
if (sm != null)
|
||||
{
|
||||
FormMail below2sm = FormMail.GenerateBalanceNegativeNotify2SM().ReplaceReflect(m);
|
||||
below2sm.To = $"{sm.EMailName} <{sm.EMail}>";
|
||||
m.CurrentLog.SubEvents.Add(below2sm.Send());
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(below2sm.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "Email notification error",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #2 SM notification: {ex.Message}");
|
||||
}
|
||||
} else
|
||||
Console.WriteLine("ERROR: CheckBalance_PostDegrade: sm = null");
|
||||
} else
|
||||
{
|
||||
m.StartLogEvent($"Deactivation (insufficient payment)", LogEvent.eEventType.Deactivation, "automatic");
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivation().ReplaceReflect(Program.config.VS).Send(m));
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivationVS().ReplaceReflect(Program.config.VS).Send(m));
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivation().ReplaceReflect(Program.config.VS).Send(m));
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error, Topic = "Email BalanceNegativeMemberDeactivation", Details = ex.Message,
|
||||
});
|
||||
}
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivationVS().ReplaceReflect(Program.config.VS).Send(m));
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error, Topic = "Email BalanceNegativeMemberDeactivationVS", Details = ex.Message,
|
||||
});
|
||||
}
|
||||
m.Status = Member.eStatus.Disabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using dezentrale.model;
|
||||
using dezentrale.model.money;
|
||||
|
||||
namespace dezentrale.core
|
||||
{
|
||||
//! \short Data provider for the MV invitation process
|
||||
public interface IMvInvitationData
|
||||
{
|
||||
/*List<Member> MemberList { get; set; }
|
||||
string DataTemplate { get; set; }
|
||||
IntermediateFormat DataFormat { get; set; }
|
||||
|
||||
string OutputDirectory { get; set; }
|
||||
string FileNamePattern { get; set; }
|
||||
DateTime StartDate { get; set; }
|
||||
DateTime EndDate { get; set; }
|
||||
string StartDateString { get; }
|
||||
string EndDateString { get; }
|
||||
bool SendEmail { get; set; }*/
|
||||
}
|
||||
|
||||
public class MvInvitationProcess : BackgroundProcess
|
||||
{
|
||||
private Mv mv= null;
|
||||
private List<MvInvitedMember> memberList = null;
|
||||
|
||||
public MvInvitationProcess(Mv mv, List<MvInvitedMember> memberList)
|
||||
{
|
||||
this.mv = mv;
|
||||
this.memberList = memberList;
|
||||
|
||||
Caption = "Send MV invitation E-Mails";
|
||||
Steps = (uint) memberList.Count; //number of members to contact
|
||||
}
|
||||
|
||||
//random string generation is borrowed from https://stackoverflow.com/questions/1344221
|
||||
private static Random random = new Random();
|
||||
private static string RandomString(int length)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
|
||||
//! \short Run MV invitation process
|
||||
//! \brief For each selected member, an E-Mail is generated and
|
||||
//! sent out, defined in @ref FormMail
|
||||
//! \return true if the generation was successful.
|
||||
protected override bool Run()
|
||||
{
|
||||
uint step = 0;
|
||||
|
||||
FormMail fm = new FormMail()
|
||||
{
|
||||
To = "{EMailName} <{EMail}>",
|
||||
Subject = mv.InviteHeadline,
|
||||
Body = mv.InviteBody,
|
||||
};
|
||||
fm = fm.ReplaceReflect(mv);
|
||||
|
||||
foreach (MvInvitedMember m in memberList)
|
||||
{
|
||||
step++;
|
||||
try
|
||||
{
|
||||
LogTarget.LogLine($"Processing member {m.Member.NumberString} - {m.Member.Nickname}...", LogEvent.ELogLevel.Info, "MvInvitationProcess");
|
||||
LogTarget.StepStarted(step, $"Sending mail for member {m.Member.Nickname}");
|
||||
|
||||
m.Member.StartLogEvent("MvInvitationProcess", LogEvent.eEventType.EMail, Program.config.LocalUser);
|
||||
m.AuthCode = RandomString(10);
|
||||
|
||||
|
||||
m.Member.CurrentLog.SubEvents.Add(fm.Send(m.Member));
|
||||
m.Member.SaveToFile();
|
||||
m.InvitationDate = DateTime.Now;
|
||||
m.Invited = true;
|
||||
|
||||
LogTarget.StepCompleted(step, $"Done with member {m.Member.Nickname}", true);
|
||||
|
||||
if (mv.Status == Mv.MvStatus.InPreparation)
|
||||
mv.Status = Mv.MvStatus.InvitationSent;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"Error while processing member {m.Member.Nickname}: {ex.Message}", LogEvent.ELogLevel.Error, "MvInvitationProcess");
|
||||
LogTarget.StepCompleted(step, $"Error while processing member {m.Member.Nickname}", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LogTarget.LogLine($"Done.", LogEvent.ELogLevel.Info, "MvInvitationProcess");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -184,7 +184,14 @@ namespace dezentrale.core
|
|||
|
||||
//send E-Mail
|
||||
m.StartLogEvent($"Payment receipts E-Mail ({data.StartDateString} ... {data.EndDateString})",LogEvent.eEventType.EMail, Program.config.LocalUser);
|
||||
LogSubEvent lse = receiptMail.Send(m, outputs);
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(receiptMail.Send(m, outputs));
|
||||
} catch(Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"Cannot send payment receipts E-Mail: {ex.Message}", LogEvent.ELogLevel.Error);
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
m.SaveToFile(true);
|
||||
}
|
||||
} else
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using dezentrale.model;
|
||||
|
||||
namespace dezentrale.core
|
||||
{
|
||||
public class SerialMailProcess<T> : BackgroundProcess
|
||||
{
|
||||
private FormMail fm = null;
|
||||
private List<T> entities = null;
|
||||
public List<T> EntitiesSuccessful { get; private set; } = new List<T>();
|
||||
public List<T> EntitiesFailed { get; private set; } = new List<T>();
|
||||
|
||||
private Func<FormMail, T, IProcessController, bool> customProcessor = null;
|
||||
|
||||
private void Init(FormMail fmArg, List<T> entitiesArg)
|
||||
{
|
||||
this.fm = fmArg;
|
||||
this.entities = entitiesArg;
|
||||
|
||||
Caption = "Send E-Mails";
|
||||
Steps = (uint)entities.Count; //number of members to contact
|
||||
}
|
||||
|
||||
public SerialMailProcess(FormMail fm, List<T> entities)
|
||||
{
|
||||
Init(fm, entities);
|
||||
}
|
||||
public SerialMailProcess(FormMail fm, List<T> entities, Func<FormMail, T, IProcessController, bool> customProcessor)
|
||||
{
|
||||
this.customProcessor = customProcessor;
|
||||
Init(fm, entities);
|
||||
}
|
||||
|
||||
|
||||
//! \short Run MV mail process
|
||||
//! \brief For each selected member, an E-Mail is generated and
|
||||
//! sent out, defined in @ref FormMail
|
||||
//! \return true if the generation was successful.
|
||||
protected override bool Run()
|
||||
{
|
||||
uint step = 0;
|
||||
|
||||
string tType = typeof(T).ToString();
|
||||
|
||||
foreach (T t in entities)
|
||||
{
|
||||
step++;
|
||||
try
|
||||
{
|
||||
LogTarget.LogLine($"Sending mail for {tType} ({t.ToString()})...", LogEvent.ELogLevel.Info, "SerialMailProcess");
|
||||
LogTarget.StepStarted(step, $"Sending mail for {tType} {t.ToString()}");
|
||||
|
||||
bool success = false;
|
||||
if(customProcessor == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fm.Send(t);
|
||||
success = true;
|
||||
} catch(Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"{ex.Message}", LogEvent.ELogLevel.Error, "SerialMailProcess");
|
||||
success = false;
|
||||
}
|
||||
} else
|
||||
{
|
||||
success = customProcessor(fm, t, LogTarget);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
EntitiesSuccessful.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTarget.LogLine($"Custom mail process for {tType} {t.ToString()} returned false", LogEvent.ELogLevel.Error, "SerialMailProcess");
|
||||
EntitiesFailed.Add(t);
|
||||
}
|
||||
|
||||
LogTarget.StepCompleted(step, $"Done with {tType} {t.ToString()}", true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"Error while processing {tType} {t.ToString()}: {ex.Message}", LogEvent.ELogLevel.Error, "SerialMailProcess");
|
||||
LogTarget.StepCompleted(step, $"Error while processing {tType} {t.ToString()}", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LogTarget.LogLine($"Done.", LogEvent.ELogLevel.Info, "SerialMailProcess");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -197,7 +197,7 @@
|
|||
<Compile Include="core\PaymentReceiptProcess.cs" />
|
||||
<Compile Include="core\ReplaceReflectEntity.cs" />
|
||||
<Compile Include="view\frmMv.cs" />
|
||||
<Compile Include="core\MvInvitationProcess.cs" />
|
||||
<Compile Include="core\SerialMailProcess.cs" />
|
||||
<Compile Include="model\Mv.cs" />
|
||||
<Compile Include="model\svg\SvgFile.cs" />
|
||||
<Compile Include="model\svg\SvgPath.cs" />
|
||||
|
|
|
@ -96,8 +96,11 @@ namespace dezentrale.model
|
|||
//client.Send(Program.config.Smtp.From, src.To, src.Subject, src.Body);
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FormMail.Send() Error:\n{ex.Message}\n");
|
||||
ret.Type = LogEvent.eEventType.Error;
|
||||
Console.WriteLine($"FormMail.Send() Error: {ex.Message}\n");
|
||||
if(ex.InnerException != null) Console.WriteLine($" inner exception: {ex.InnerException.Message}");
|
||||
|
||||
throw ex;
|
||||
//ret.Type = LogEvent.eEventType.Error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -580,6 +583,26 @@ namespace dezentrale.model
|
|||
+ "Dies ist eine automatisch generierte E-Mail.\n"
|
||||
+ "This is an auto-generated E-Mail.\n",
|
||||
};
|
||||
}
|
||||
|
||||
public static FormMail GenerateMvFinishedNotification()
|
||||
{
|
||||
return new FormMail()
|
||||
{
|
||||
To = "{EMailName} <{EMail}>",
|
||||
Subject = "Mitgliederversammlung beendet",
|
||||
Body = "Hallo {EMailName}!\n"
|
||||
+ "\n"
|
||||
+ "Danke für Deine Teilnahme an der Mitgliederversammlung!\n"
|
||||
+ "Die MV ging von {StartDateTime} bis {EndDateTime}.\n"
|
||||
+ "Folgende Einladung zur MV ist hinfällig:\n"
|
||||
+ "The following MV invitation is cancelled:\n"
|
||||
+ "Titel/Subject: \"{InviteHeadline}\"\n"
|
||||
+ "\n"
|
||||
+ "--\n"
|
||||
+ "Dies ist eine automatisch generierte E-Mail.\n"
|
||||
+ "This is an auto-generated E-Mail.\n",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,15 +212,29 @@ namespace dezentrale.model
|
|||
public void TestMail()
|
||||
{
|
||||
FormMail testMail = FormMail.GenerateTestmail();
|
||||
testMail.Send(this);
|
||||
try
|
||||
{
|
||||
testMail.Send(this);
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Cannot send mail to <{this.EMail}>: {ex.Message}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
public void AccountStatusMail(string user = null)
|
||||
{
|
||||
StartLogEvent("Member Status Mail", LogEvent.eEventType.EMail, user);
|
||||
FormMail accountStatusMail = FormMail.GenerateSingleMemberStatusReport();
|
||||
LogSubEvent lse = accountStatusMail.Send(this);
|
||||
CurrentLog.SubEvents.Add(lse);
|
||||
SaveToFile();
|
||||
try
|
||||
{
|
||||
CurrentLog.SubEvents.Add(accountStatusMail.Send(this));
|
||||
SaveToFile();
|
||||
} catch(Exception ex)
|
||||
{
|
||||
CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
SaveToFile();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyMoneyTransfer(MoneyTransfer t, string user = null)
|
||||
|
@ -274,18 +288,27 @@ namespace dezentrale.model
|
|||
+ $"accountBalance = {AccountBalanceString} (new)\n"
|
||||
+ $"Next payment for this member is due at {PaymentDueMonth}\n"
|
||||
+ "\n\n--\n(automatische mail)"
|
||||
};
|
||||
LogSubEvent lse = fm.Send();
|
||||
CurrentLog.SubEvents.Add(lse);
|
||||
//if(lse.Type == LogEvent.eEventType.Error) { }
|
||||
};
|
||||
try
|
||||
{
|
||||
CurrentLog.SubEvents.Add(fm.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paymentNotify)
|
||||
{
|
||||
FormMail notify = FormMail.GenerateMemberPaymentNotify(odd).ReplaceReflect(t);
|
||||
|
||||
LogSubEvent lse = notify.Send(this);
|
||||
CurrentLog.SubEvents.Add(lse);
|
||||
try
|
||||
{
|
||||
CurrentLog.SubEvents.Add(notify.Send(this));
|
||||
} catch(Exception ex)
|
||||
{
|
||||
CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
55
model/Mv.cs
55
model/Mv.cs
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using dezentrale.core;
|
||||
|
||||
|
@ -36,9 +37,13 @@ namespace dezentrale.model
|
|||
member = m;
|
||||
MemberNumber = m.Number;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Member.Number} ({Member.Nickname})";
|
||||
}
|
||||
}
|
||||
|
||||
public class Mv : XmlLog, IMvInvitationData
|
||||
public class Mv : XmlLog
|
||||
{
|
||||
public enum MvStatus
|
||||
{
|
||||
|
@ -51,18 +56,25 @@ namespace dezentrale.model
|
|||
|
||||
private MvStatus status = MvStatus.InPreparation;
|
||||
private DateTime eventDate;
|
||||
private DateTime startDateTime;
|
||||
private DateTime endDateTime;
|
||||
private string place = "";
|
||||
private string agenda = "";
|
||||
private string inviteHeadline = "";
|
||||
private string inviteBody = "";
|
||||
private string protocol = "";
|
||||
|
||||
|
||||
[XmlAttribute] public MvStatus Status { get { return status; } set { LogPropertyChange("Status", status, value); status = value; } }
|
||||
[XmlAttribute] public DateTime EventDate { get { return eventDate; } set { LogPropertyChange("EventDate", eventDate, value); eventDate = value; } }
|
||||
[XmlAttribute("Started")] public DateTime StartDateTime { get { return startDateTime; } set { LogPropertyChange("StartDateTime", startDateTime, value); startDateTime = value; } }
|
||||
[XmlAttribute("Ended")] public DateTime EndDateTime { get { return endDateTime; } set { LogPropertyChange("EndDateTime", endDateTime, value); endDateTime = value; } }
|
||||
[XmlElement] public string Place { get { return place; } set { LogPropertyChange("Place", place, value); place = value; } }
|
||||
[XmlElement] public string Agenda { get { return agenda; } set { LogPropertyChange("Agenda", agenda, value); agenda = value; } }
|
||||
[XmlElement] public string InviteHeadline { get { return inviteHeadline; } set { LogPropertyChange("InviteHeadline", inviteHeadline, value); inviteHeadline = value; } }
|
||||
[XmlElement] public string InviteBody { get { return inviteBody; } set { LogPropertyChange("InviteBody", inviteBody, value); inviteBody = value; } }
|
||||
[XmlElement] public List<MvInvitedMember> Members { get; set; } = new List<MvInvitedMember>();
|
||||
[XmlElement] public string Protocol { get { return protocol; } set { LogPropertyChange("Protocol", protocol, value); protocol = value; } }
|
||||
|
||||
[XmlElement] public List<Blob> Attachments { get; set; } = new List<Blob>();
|
||||
|
||||
|
@ -129,6 +141,47 @@ namespace dezentrale.model
|
|||
FinishLogEvent();
|
||||
}
|
||||
|
||||
//random string generation is borrowed from https://stackoverflow.com/questions/1344221
|
||||
private static Random random = new Random();
|
||||
private static string RandomString(int length)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
public SerialMailProcess<MvInvitedMember> GetInvitationMailProcess(List<MvInvitedMember> entities = null)
|
||||
{
|
||||
FormMail fm = (new FormMail()
|
||||
{
|
||||
To = "{EMailName} <{EMail}>",
|
||||
Subject = InviteHeadline,
|
||||
Body = InviteBody,
|
||||
}).ReplaceReflect(this);
|
||||
if (entities == null) entities = Members;
|
||||
|
||||
SerialMailProcess<MvInvitedMember> p =
|
||||
new SerialMailProcess<MvInvitedMember>(fm, entities,
|
||||
(FormMail f, MvInvitedMember m, IProcessController LogTarget) =>
|
||||
{
|
||||
m.Member.StartLogEvent("MV invitation mail", LogEvent.eEventType.EMail, Program.config.LocalUser);
|
||||
try
|
||||
{
|
||||
m.Member.CurrentLog.SubEvents.Add(f.Send(m.Member));
|
||||
m.Member.SaveToFile();
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.Member.CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email invitation failed", Details = ex.Message });
|
||||
m.Member.SaveToFile();
|
||||
LogTarget.LogLine(ex.Message, LogEvent.ELogLevel.Error, "SerialMailProcess::mv.invitation");
|
||||
return false;
|
||||
}
|
||||
m.InvitationDate = DateTime.Now;
|
||||
m.Invited = true;
|
||||
return true;
|
||||
});
|
||||
return p;
|
||||
}
|
||||
public FormMail GetInvitationMail(Member m = null, string authCode = null)
|
||||
{
|
||||
|
||||
|
|
|
@ -192,9 +192,10 @@ namespace dezentrale.view
|
|||
return lvi;
|
||||
}
|
||||
|
||||
public void AddEntry(T t) { this.Items.Add(UpdateLvi(new ListViewItem(), t)); }
|
||||
public void UpdateEntry(T t) { UpdateLvi(GetExistingLvi(t), t); }
|
||||
public void RemoveEntry(T t) { ListViewItem lvi = GetExistingLvi(t); if (lvi != null) this.Items.Remove(lvi); }
|
||||
public void AddEntry(T t) { this.Items.Add(UpdateLvi(new ListViewItem(), t)); }
|
||||
public void UpdateEntry(T t) { UpdateLvi(GetExistingLvi(t), t); }
|
||||
public void RemoveEntry(T t) { ListViewItem lvi = GetExistingLvi(t); if (lvi != null) this.Items.Remove(lvi); }
|
||||
public void DeSelectEntry(T t, bool sel = true) { ListViewItem lvi = GetExistingLvi(t); if (lvi != null) lvi.Selected = sel; }
|
||||
public T GetFirstSelectedItem()
|
||||
{
|
||||
if (this.SelectedItems.Count < 1) return null;
|
||||
|
@ -230,6 +231,14 @@ namespace dezentrale.view
|
|||
}
|
||||
return mi;
|
||||
}
|
||||
public void ClearMenuItems()
|
||||
{
|
||||
while(cm.MenuItems.Count > internalColumns)
|
||||
{
|
||||
cm.MenuItems.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadFromList(List<T> entries)
|
||||
{
|
||||
this.SuspendLayout();
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace dezentrale.view
|
|||
protected const int line = 20 + margin; //lineheight
|
||||
protected const int labelHeight = 14;
|
||||
protected const int labelOffs = 3;
|
||||
protected const int groupOffset = 10;
|
||||
|
||||
protected List<Button> buttons = new List<Button>();
|
||||
|
||||
|
|
|
@ -33,21 +33,21 @@ namespace dezentrale.view
|
|||
{
|
||||
Name = "inv",
|
||||
Display = "Invited",
|
||||
Width = 32, TextAlign = HorizontalAlignment.Right,
|
||||
Width = 48, TextAlign = HorizontalAlignment.Right,
|
||||
CustomToString = ( x => ((MvInvitedMember)x).InvitedString),
|
||||
},
|
||||
new ConfigLVDataHandler()
|
||||
{
|
||||
Name = "att",
|
||||
Display = "Invited",
|
||||
Width = 32, TextAlign = HorizontalAlignment.Right,
|
||||
Display = "Attended",
|
||||
Width = 61, TextAlign = HorizontalAlignment.Right,
|
||||
CustomToString = ( x => ((MvInvitedMember)x).AttendedString),
|
||||
},
|
||||
new ConfigLVDataHandler()
|
||||
{
|
||||
Name = "date",
|
||||
Display = "Date",
|
||||
Width = 130,
|
||||
Display = "InviteDate",
|
||||
Width = 88,
|
||||
CustomToString = ( x => (((MvInvitedMember)x).InvitationDate.Year > 1 ? ((MvInvitedMember)x).InvitationDate.ToString() : "-") ),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -229,6 +229,7 @@ namespace dezentrale.view
|
|||
this.Close();
|
||||
}
|
||||
lstMembers.LoadFromList(Program.members.Entries);
|
||||
lstMv.LoadFromList(Program.mvList.Entries);
|
||||
mtv.ClearList();
|
||||
}
|
||||
}
|
||||
|
@ -499,7 +500,13 @@ namespace dezentrale.view
|
|||
private void lstMembers_AccountStatusMail(object sender, EventArgs e)
|
||||
{
|
||||
Member m = lstMembers.GetFirstSelectedItem();
|
||||
m?.AccountStatusMail();
|
||||
try
|
||||
{
|
||||
m?.AccountStatusMail();
|
||||
} catch(Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Cannot send account status mail:\r\n{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void lstMembers_Edit(object sender, EventArgs e)
|
||||
|
|
339
view/frmMv.cs
339
view/frmMv.cs
|
@ -1,9 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using dezentrale.core;
|
||||
|
@ -20,7 +17,10 @@ namespace dezentrale.view
|
|||
public Mv mv { get; set; }
|
||||
private TabControl tabControl;
|
||||
|
||||
private TabPage tabInvitationSettings;
|
||||
//List with all members and invited yes|no
|
||||
private LvMvInvitations lvMvInvitations;
|
||||
|
||||
private TabPage tabInvitationSettings;
|
||||
//DateTime
|
||||
private DateTimePicker mvDate, mvTime;
|
||||
//Place
|
||||
|
@ -31,18 +31,42 @@ namespace dezentrale.view
|
|||
//Subject
|
||||
private TextBox tbInviteHeadline;
|
||||
private TextBox tbInviteBody;
|
||||
//List with all members and invited yes|no
|
||||
private LvMvInvitations lvMvInvitations;
|
||||
//Option to invite selected|all members
|
||||
private TabPage tabRunningMv;
|
||||
//List with invited members with authenticated status
|
||||
private Label lblAttendedStats;
|
||||
//Textbox to paste auth codes from the users
|
||||
private TextBox tbAuthCodePaste;
|
||||
private TextBox tbMvProtocol;
|
||||
//textbox to hold an external MV protocol URL and/or
|
||||
//[rich] textbox for MV protocol
|
||||
//Button to finish MV
|
||||
//MV attachments (e.g. finished PDF protocol)
|
||||
|
||||
private TabPage tabLog;
|
||||
|
||||
//! \brief Updates the stats labels for MV attend
|
||||
private void UpdateAttendedDisplay()
|
||||
{
|
||||
int att = 0;
|
||||
foreach(MvInvitedMember mvi in mv.Members)
|
||||
{
|
||||
if (mvi.AttendedMv) att++;
|
||||
}
|
||||
float percent;
|
||||
if (mv.Members.Count > 0)
|
||||
percent = ((float)att * (float)100 / (float)mv.Members.Count);
|
||||
else
|
||||
percent = 0;
|
||||
|
||||
lblAttendedStats.Text = $"{att} / {mv.Members.Count} ({Math.Floor(percent)} percent)";
|
||||
if(percent <= 50)
|
||||
{
|
||||
lblAttendedStats.BackColor = System.Drawing.Color.Orange;
|
||||
} else
|
||||
{
|
||||
lblAttendedStats.BackColor = System.Drawing.Color.LightGreen;
|
||||
}
|
||||
}
|
||||
//! \brief UpdateGui() will refresh the GUI components for this
|
||||
//! form according to the current MV state and visible
|
||||
//! GUI tab. Having this centralized in one function is
|
||||
|
@ -54,15 +78,23 @@ namespace dezentrale.view
|
|||
{
|
||||
ClearButtons();
|
||||
TabPage selectedTab = tabControl.SelectedTab;
|
||||
lvMvInvitations.ClearMenuItems();
|
||||
if(selectedTab == tabInvitationSettings)
|
||||
{
|
||||
bool enabled = (mv.Status == Mv.MvStatus.InPreparation || mv.Status == Mv.MvStatus.InvitationSent);
|
||||
Button btn;
|
||||
btn = AddButton("Invite selected", btnInviteSelected_Click); btn.Enabled = enabled;
|
||||
btn = AddButton("Invite all", btnInviteAll_Click); btn.Enabled = enabled;
|
||||
lvMvInvitations.AddMenuItem("Invite selected", btnInviteSelected_Click);
|
||||
lvMvInvitations.AddMenuItem("Invite all", btnInviteAll_Click);
|
||||
} else if(selectedTab == tabRunningMv)
|
||||
{
|
||||
|
||||
Button btn;
|
||||
btn = AddButton("Start MV", btnStartMv_Click); btn.Enabled = (mv.Status == Mv.MvStatus.InvitationSent);
|
||||
btn = AddButton("End MV", btnFinishMv_Click); btn.Enabled = (mv.Status == Mv.MvStatus.Started);
|
||||
lvMvInvitations.AddMenuItem("Check IN selected", btnCheckInSelected_Click);
|
||||
lvMvInvitations.AddMenuItem("Check OUT selected", btnCheckOutSelected_Click);
|
||||
UpdateAttendedDisplay();
|
||||
} else if(selectedTab == tabLog)
|
||||
{
|
||||
|
||||
|
@ -70,12 +102,15 @@ namespace dezentrale.view
|
|||
AddButton("Close", btnClose_Click);
|
||||
|
||||
|
||||
mvDate.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
mvTime.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
tbPlace.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
tbMvAgenda.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
tbInviteHeadline.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
tbInviteBody.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
mvDate.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
mvTime.Enabled = mv.Status == Mv.MvStatus.InPreparation;
|
||||
tbPlace.ReadOnly = mv.Status != Mv.MvStatus.InPreparation;
|
||||
tbMvAgenda.ReadOnly = mv.Status != Mv.MvStatus.InPreparation;
|
||||
tbInviteHeadline.ReadOnly= mv.Status != Mv.MvStatus.InPreparation;
|
||||
tbInviteBody.ReadOnly = mv.Status != Mv.MvStatus.InPreparation;
|
||||
|
||||
tbAuthCodePaste.ReadOnly = mv.Status != Mv.MvStatus.Started;
|
||||
tbMvProtocol.ReadOnly = mv.Status != Mv.MvStatus.Started;
|
||||
switch (mv.Status)
|
||||
{
|
||||
case Mv.MvStatus.InPreparation:
|
||||
|
@ -93,6 +128,11 @@ namespace dezentrale.view
|
|||
{
|
||||
UpdateMvData();
|
||||
|
||||
if(mv.Status != Mv.MvStatus.InPreparation && mv.Status != Mv.MvStatus.InvitationSent)
|
||||
{
|
||||
MessageBox.Show($"MV needs to be in one of these states to invite members:\r\n{Mv.MvStatus.InPreparation}, {Mv.MvStatus.InvitationSent}");
|
||||
return;
|
||||
}
|
||||
if (mvMembers == null || mvMembers.Count < 1)
|
||||
{
|
||||
MessageBox.Show("No members to invite!");
|
||||
|
@ -145,9 +185,20 @@ namespace dezentrale.view
|
|||
return;
|
||||
}
|
||||
//Spawn invitation process window and run process
|
||||
MvInvitationProcess invProcess = new MvInvitationProcess(mv, inv);
|
||||
|
||||
FormMail fm = (new FormMail()
|
||||
{
|
||||
To = "{EMailName} <{EMail}>",
|
||||
Subject = mv.InviteHeadline,
|
||||
Body = mv.InviteBody,
|
||||
}).ReplaceReflect(mv);
|
||||
|
||||
SerialMailProcess<MvInvitedMember> invProcess = mv.GetInvitationMailProcess(inv);
|
||||
frmProcessWithLog frmInvProcess = new frmProcessWithLog(invProcess, true);
|
||||
frmInvProcess.ShowDialog();
|
||||
if (mv.Status == Mv.MvStatus.InPreparation)
|
||||
mv.Status = Mv.MvStatus.InvitationSent;
|
||||
foreach (MvInvitedMember mvi in inv) lvMvInvitations.UpdateEntry(mvi);
|
||||
UpdateGui();
|
||||
}
|
||||
private void btnInviteSelected_Click(object sender, EventArgs e)
|
||||
|
@ -158,6 +209,74 @@ namespace dezentrale.view
|
|||
{
|
||||
DoInvitation(mv.Members);
|
||||
}
|
||||
private void btnStartMv_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (mv.Status != Mv.MvStatus.InvitationSent)
|
||||
{
|
||||
MessageBox.Show($"MV must be in state {Mv.MvStatus.InvitationSent}!");
|
||||
return;
|
||||
}
|
||||
DateTime now = DateTime.Now;
|
||||
DateTime evt = mv.EventDate;
|
||||
if(now.Year != evt.Year || now.Month != evt.Month || now.Day != evt.Day || evt.CompareTo(now) > 0)
|
||||
{
|
||||
MessageBox.Show("Today must have the same Date as announced in the EventDate, and Time has to be after the announced time.");
|
||||
return;
|
||||
}
|
||||
mv.Status = Mv.MvStatus.Started;
|
||||
mv.StartDateTime = now;
|
||||
|
||||
//Todo: init protocol with contents from invitation mail
|
||||
mv.Protocol = mv.AgendaNumberedString;
|
||||
tbMvProtocol.Text = mv.Protocol;
|
||||
MessageBox.Show("MV started.");
|
||||
UpdateGui();
|
||||
}
|
||||
private void btnFinishMv_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (mv.Status != Mv.MvStatus.Started)
|
||||
{
|
||||
MessageBox.Show($"MV must be in state {Mv.MvStatus.Started}!");
|
||||
return;
|
||||
}
|
||||
mv.Status = Mv.MvStatus.Ended;
|
||||
mv.EndDateTime = DateTime.Now;
|
||||
MessageBox.Show("MV ended");
|
||||
//Ask for sending end mail to attended users
|
||||
|
||||
UpdateGui();
|
||||
}
|
||||
|
||||
private void btnCheckInSelected_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (mv.Status != Mv.MvStatus.Started)
|
||||
{
|
||||
MessageBox.Show($"MV must be in state {Mv.MvStatus.Started}!");
|
||||
return;
|
||||
}
|
||||
//CheckIn(lvMvInvitations.GetSelectedItems());
|
||||
foreach (MvInvitedMember mvi in lvMvInvitations.GetSelectedItems())
|
||||
{
|
||||
mvi.AttendedMv = true;
|
||||
lvMvInvitations.UpdateEntry(mvi);
|
||||
}
|
||||
UpdateAttendedDisplay();
|
||||
}
|
||||
private void btnCheckOutSelected_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (mv.Status != Mv.MvStatus.Started)
|
||||
{
|
||||
MessageBox.Show($"MV must be in state {Mv.MvStatus.Started}!");
|
||||
return;
|
||||
}
|
||||
//CheckIn(lvMvInvitations.GetSelectedItems());
|
||||
foreach (MvInvitedMember mvi in lvMvInvitations.GetSelectedItems())
|
||||
{
|
||||
mvi.AttendedMv = false;
|
||||
lvMvInvitations.UpdateEntry(mvi);
|
||||
}
|
||||
UpdateAttendedDisplay();
|
||||
}
|
||||
|
||||
|
||||
private void UpdateMvData()
|
||||
|
@ -171,101 +290,221 @@ namespace dezentrale.view
|
|||
mv.Agenda = tbMvAgenda.Text;
|
||||
mv.InviteHeadline = tbInviteHeadline.Text;
|
||||
mv.InviteBody = tbInviteBody.Text;
|
||||
|
||||
mv.Protocol = tbMvProtocol.Text;
|
||||
}
|
||||
|
||||
private void BuildPageInvitationSettings(Control parent)
|
||||
{
|
||||
parent.Controls.Add(new Label()
|
||||
SplitContainer sc = new SplitContainer()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
parent.Controls.Add(sc);
|
||||
GroupBox details = new GroupBox()
|
||||
{
|
||||
Text = "Invitation details",
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
sc.Panel1.Controls.Add(details);
|
||||
GroupBox mail = new GroupBox()
|
||||
{
|
||||
Text = "Invitation Mail",
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
sc.Panel2.Controls.Add(mail);
|
||||
|
||||
|
||||
details.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Event date+time:",
|
||||
Location = new Point(lm, 0 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 0 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
parent.Controls.Add(mvDate = new DateTimePicker()
|
||||
details.Controls.Add(mvDate = new DateTimePicker()
|
||||
{
|
||||
Location = new Point(lm + 113, 0 * line + tm),
|
||||
Location = new Point(lm + 113, 0 * line + tm + groupOffset),
|
||||
Width = 110,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
Format = DateTimePickerFormat.Short,
|
||||
});
|
||||
parent.Controls.Add(mvTime = new DateTimePicker()
|
||||
details.Controls.Add(mvTime = new DateTimePicker()
|
||||
{
|
||||
Location = new Point(lm + 243, 0 * line + tm),
|
||||
Location = new Point(lm + 243, 0 * line + tm + groupOffset),
|
||||
Width = 90,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
Format = DateTimePickerFormat.Time,
|
||||
});
|
||||
|
||||
parent.Controls.Add(new Label()
|
||||
details.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Place:",
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
parent.Controls.Add(tbPlace = new TextBox()
|
||||
details.Controls.Add(tbPlace = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 1 * line + tm),
|
||||
Width = 580,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
Location = new Point(lm + 113, 1 * line + tm + groupOffset),
|
||||
Width = details.ClientSize.Width - lm - 113 - groupOffset,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
});
|
||||
|
||||
parent.Controls.Add(new Label()
|
||||
details.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Agenda (one item per line, auto-numbered:",
|
||||
Location = new Point(lm, 2 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 2 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(320, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
parent.Controls.Add(tbMvAgenda = new TextBox()
|
||||
details.Controls.Add(tbMvAgenda = new TextBox()
|
||||
{
|
||||
Location = new Point(0, 3 * line + tm),
|
||||
Size = new Size(700, 160),
|
||||
Location = new Point(groupOffset, 3 * line + tm + groupOffset),
|
||||
Size = new Size(details.ClientSize.Width - 2 * groupOffset, details.ClientSize.Height - 3 * line - tm - 2 * groupOffset),
|
||||
Multiline = true,
|
||||
ScrollBars = ScrollBars.Both,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
});
|
||||
|
||||
parent.Controls.Add(new Label()
|
||||
mail.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Headline:",
|
||||
Location = new Point(lm, 10 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 0 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
parent.Controls.Add(tbInviteHeadline = new TextBox()
|
||||
mail.Controls.Add(tbInviteHeadline = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 10 * line + tm),
|
||||
Width = 580,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
Location = new Point(lm + 113, 0 * line + tm + groupOffset),
|
||||
Width = details.ClientSize.Width - lm - 113 - groupOffset,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
});
|
||||
|
||||
parent.Controls.Add(new Label()
|
||||
mail.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Invitation Body:",
|
||||
Location = new Point(lm, 11 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
parent.Controls.Add(tbInviteBody = new TextBox()
|
||||
mail.Controls.Add(tbInviteBody = new TextBox()
|
||||
{
|
||||
Location = new Point(0, 12 * line + tm),
|
||||
Size = new Size(700, 160),
|
||||
Location = new Point(groupOffset, 2 * line + tm + groupOffset),
|
||||
Size = new Size(details.ClientSize.Width - 2 * groupOffset, details.ClientSize.Height - 2 * line - tm - 2 * groupOffset),
|
||||
Multiline = true,
|
||||
ScrollBars = ScrollBars.Both,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
});
|
||||
}
|
||||
|
||||
private void BuildPageRunningMv(Control parent)
|
||||
{
|
||||
//input field to add auth codes
|
||||
|
||||
SplitContainer splitLR = new SplitContainer()
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
parent.Controls.Add(splitLR);
|
||||
//input field to add auth codes, with button
|
||||
SplitContainer splitL_UD = new SplitContainer()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
splitLR.Panel1.Controls.Add(splitL_UD);
|
||||
|
||||
GroupBox groupAttending = new GroupBox()
|
||||
{
|
||||
Text = "Attending members",
|
||||
Dock = DockStyle.Fill,
|
||||
Margin = new Padding(5),
|
||||
};
|
||||
splitL_UD.Panel1.Controls.Add(groupAttending);
|
||||
|
||||
GroupBox groupAttachments = new GroupBox()
|
||||
{
|
||||
Text = "Attachments",
|
||||
Dock = DockStyle.Fill,
|
||||
Margin = new Padding(5),
|
||||
};
|
||||
splitL_UD.Panel2.Controls.Add(groupAttachments);
|
||||
|
||||
GroupBox groupProtocol = new GroupBox()
|
||||
{
|
||||
Text = "MV protocol",
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
splitLR.Panel2.Controls.Add(groupProtocol);
|
||||
|
||||
|
||||
|
||||
|
||||
groupAttending.Controls.Add(new Label()
|
||||
{
|
||||
Text = "stats:",
|
||||
Location = new Point(lm, 0 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
groupAttending.Controls.Add(lblAttendedStats = new Label()
|
||||
{
|
||||
Text = "",
|
||||
Location = new Point(lm + 113, 0 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(110, labelHeight),
|
||||
});
|
||||
groupAttending.Controls.Add(new Label()
|
||||
{
|
||||
Text = "paste Auth Codes:",
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs + groupOffset),
|
||||
Size = new Size(160, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
|
||||
groupAttending.Controls.Add(tbAuthCodePaste = new TextBox()
|
||||
{
|
||||
Multiline = true,
|
||||
ScrollBars = ScrollBars.Both,
|
||||
Location = new Point(10, 2 * line + tm + groupOffset),
|
||||
Size = new Size(groupAttending.Width - 20, groupAttending.Height - 75),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
});
|
||||
tbAuthCodePaste.KeyPress += tbAuthCodePaste_KeyPress;
|
||||
|
||||
groupProtocol.Controls.Add(tbMvProtocol = new TextBox()
|
||||
{
|
||||
Multiline = true,
|
||||
ScrollBars = ScrollBars.Both,
|
||||
Location = new Point(10, 5 + groupOffset),
|
||||
Size = new Size(groupProtocol.Width - 20, groupProtocol.Height - 25),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
});
|
||||
}
|
||||
|
||||
private void tbAuthCodePaste_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (mv.Status != Mv.MvStatus.Started) return;
|
||||
if (e.KeyChar != 13) return;
|
||||
bool foundAuthCode = false;
|
||||
foreach(MvInvitedMember mvi in mv.Members)
|
||||
{
|
||||
if (tbAuthCodePaste.Text.Contains(mvi.AuthCode))
|
||||
{
|
||||
foundAuthCode = true;
|
||||
mvi.AttendedMv = true;
|
||||
//Add mvi to selection in list
|
||||
//lvMvInvitations.SelectedItems
|
||||
lvMvInvitations.DeSelectEntry(mvi, true);
|
||||
}
|
||||
}
|
||||
tbAuthCodePaste.Text = "";
|
||||
if(foundAuthCode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildLog(Control parent)
|
||||
{
|
||||
parent.Controls.Add(new LogView(mv.Log)
|
||||
|
@ -298,6 +537,7 @@ namespace dezentrale.view
|
|||
grpInvitations.Controls.Add(lvMvInvitations = new LvMvInvitations()
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
HideSelection = false,
|
||||
});
|
||||
split.Panel1.Controls.Add(grpInvitations);
|
||||
|
||||
|
@ -338,7 +578,7 @@ namespace dezentrale.view
|
|||
|
||||
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.Size = new System.Drawing.Size(742, 600);
|
||||
this.Size = new System.Drawing.Size(1200, 800);
|
||||
this.Text = "dezentrale-members :: MV administration";
|
||||
this.FormClosing += frmMv_Closing;
|
||||
BuildGui(this);
|
||||
|
@ -354,6 +594,7 @@ namespace dezentrale.view
|
|||
tbInviteHeadline.Text = mv.InviteHeadline;
|
||||
tbInviteBody.Text = mv.InviteBody;
|
||||
|
||||
tbMvProtocol.Text = mv.Protocol;
|
||||
UpdateGui();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue