dmdb/Program.cs

255 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using dezentrale.core;
using dezentrale.model;
using dezentrale.model.money;
using dezentrale.view;
/*
TODO
----
- Documentation
- ErrorLog for all errors
- frmMain: Menu option to miss an MV for selected/checked users
- FormMail: Add mail for automatic member type setting to "Foerdermitglied"
- FormMail: Membership type was changed manually
- FormMail: Cronjob found unassigned MoneyTransfers
- frmEditEntry: Optional (checkbox) request for a comment on data changes, when hitting OK
- frmMain: Indicator that the data was modified after import + messagebox to remind user to export on quitting.
- add "database changed since last import/export" warning (e.g. you forgot to push your changes)
- frmMain: Member List: Column "monthly fee", Column "Last payment", disabled by default
- Configuration window: MoneyTransferRegEx
- Bug: Generating testdata doesn't remove old xml files, thus the memberlist will be mixed after next restart
- Bug: Member list not reloaded after ProcessCSV (balance display is wrong)
- CronjobConfig
- CustomListView: implement generic filtering
- Improve import/export handling, e.g. check for newer database on program start
- Debt handling: Store explicit flags or status for "one month behind"
or "two months behind", in order to have an escalation chain
- PGP for mails
DONE
----
- Member: add database field for contact name e.g.: name <mail@example.com> filled with nickname by default
- Testmail feature for every member account
- 2019-12-04: frmProcessWithLog: Implementation for non-immediate GUI actions (process csv, cronjob, import/export) with background thread
- Bug: Database import fails on some PCs (seems that writing xml files during decompression is problematic)
*/
namespace dezentrale
{
public class Program
{
public static uint VersionNumber { get; private set; } = 0x20022500;
public static string VersionString { get; private set; } = $"{VersionNumber:x}";
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
public static string DmDirectory = Path.Combine(AppData, "dezentrale-members");
public static string ConfigFile = Path.Combine(DmDirectory, "configuration.xml");
public static Configuration config = new Configuration();
public static MemberList members = new MemberList();
public static bool MoneyTransfersLoaded { get { return moneyTransfers != null; } }
private static MoneyTransferList moneyTransfers = null;
public static MoneyTransferList MoneyTransfers
{
get
{
if (moneyTransfers != null) return moneyTransfers;
return moneyTransfers = MoneyTransferList.LoadFromFile();
}
}
public enum eMode
{
CommandLine = 0,
Gui = 1,
Cronjob = 2,
Export = 3,
Import = 4,
BankImport = 5,
}
public static eMode ProgramMode = eMode.Gui;
private static string csvInput = null;
public static int LoadFiles()
{
moneyTransfers = null;
try { Directory.CreateDirectory(DmDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating data directory:\n{ex.Message}"); return 1; }
try
{
config = (Configuration)XmlData.LoadFromFile(ConfigFile, typeof(Configuration));
}
catch (FileNotFoundException)
{
config.DbDirectory = Path.Combine(DmDirectory, Configuration.DefaultDbDirectory);
XmlData.SaveToFile(ConfigFile, config); Console.WriteLine("Created new configuration file.");
}
catch (Exception ex)
{
Console.WriteLine("Error while accessing program data:");
Console.WriteLine(ex.Message);
return 1;
}
try { Directory.CreateDirectory(config.DbDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating member data directory:\n{ex.Message}"); return 1; }
try
{
string[] memberFiles = Directory.GetFiles(config.DbDirectory, "member-*.xml");
//foreach (string s in memberFiles) Console.WriteLine(s);
members = MemberList.LoadFromFiles(memberFiles);
Console.WriteLine($"Loaded {members.Entries.Count} member entries");
}
catch (Exception ex)
{
Console.WriteLine("Error while loading member files:");
Console.WriteLine(ex.Message);
return 1;
}
return 0;
}
[STAThread]
static int Main(string[] args)
{
bool printHelp = false;
Console.WriteLine($"dezentrale-members, Version {VersionString}");
Console.WriteLine($"Working directory: {DmDirectory}");
List<string> clArgs = new List<string>();
foreach (string argIt in args)
{
string argn;
string argv;
if (argIt.Contains("="))
{
argn = argIt.Substring(0, argIt.IndexOf('='));
argv = argIt.Substring(argIt.IndexOf('=') + 1);
}
else
{
argn = argIt;
argv = "";
}
if (argn.StartsWith("-", StringComparison.InvariantCulture)) argn = argn.Substring(1);
if (argn.StartsWith("/", StringComparison.InvariantCulture) || argn.StartsWith("-", StringComparison.InvariantCulture)) argn = argn.Substring(1);
switch (argn.ToLower())
{
case "help": printHelp = true; break;
case "mode":
switch (argv.ToLower())
{
case "cl": ProgramMode = eMode.CommandLine; break;
case "gui": ProgramMode = eMode.Gui; break;
case "cronjob":
case "auto": ProgramMode = eMode.Cronjob; break;
case "export": ProgramMode = eMode.Export; break;
case "import": ProgramMode = eMode.Import; break;
case "bankimport": ProgramMode = eMode.BankImport; break;
default:
Console.WriteLine("Invalid mode.");
printHelp = true;
break;
}
Console.WriteLine($"Setting Mode to {ProgramMode}");
break;
case "csvinput":
csvInput = argv;
break;
default:
Console.WriteLine($"Invalid command({argn})");
printHelp = true;
break;
}
}
if (printHelp)
{
Console.WriteLine("command line arguments:");
Console.WriteLine("--help Display this help message");
Console.WriteLine("--mode=<mode> Starts the program in given mode. Supported modes are:");
Console.WriteLine(" cl (default) Manual/interactive use from command line.");
Console.WriteLine(" gui Start in GUI mode (not implemented yet)");
Console.WriteLine(" auto, cronjob Check and perform pending required membership actions");
Console.WriteLine();
return 1;
}
if(LoadFiles() != 0) return 1;
switch (ProgramMode)
{
case eMode.Gui:
frmMain w = new frmMain();
Application.Run(w);
break;
case eMode.CommandLine:
Console.WriteLine("Not implemented yet");
break;
case eMode.Cronjob:
Cronjob.Run();
break;
case eMode.Export:
{
ExportProcess export = new ExportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
OutputDir = Program.DmDirectory,
};
ConsoleLogger logger = new ConsoleLogger();
System.Threading.Thread t = logger.StartRunProcess(export);
if (t != null) t.Join();
else return 1;
//if (!config.ImportExport.Export(config.DbDirectory, DmDirectory)) return 1;
//if (!config.ImportExport.VerifyExport(config.DbDirectory, DmDirectory)) return 1;
if(logger.DialogResult != DialogResult.OK) return 1;
} break;
case eMode.Import:
{
ImportProcess import = new ImportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
InputDir = Program.DmDirectory,
};
ConsoleLogger logger = new ConsoleLogger();
System.Threading.Thread t = logger.StartRunProcess(import);
if (t != null) t.Join();
else return 1;
//frmProcessWithLog frmImport = new frmProcessWithLog(import, true);
//if (!config.ImportExport.Import(config.DbDirectory, DmDirectory))
//return 1;
if(logger.DialogResult != DialogResult.OK) return 1;
} break;
case eMode.BankImport:
if (string.IsNullOrEmpty(csvInput))
{
Console.WriteLine("You must provide an input file by using --csvinput=<file>");
return 1;
}
if (!ProcessCsv.ProcessCSV(csvInput))
return 1;
break;
}
return 0;
}
}
}