Vereinsmeisterschaften  22aa7800eae54b428d40e835886cefe1fdefdfdf
This is a software that can be used to manage the internal competition of the swimming club Illertissen called "Vereinsmeisterschaften".
Loading...
Searching...
No Matches
DocumentService.cs
1using Xceed.Words.NET;
9
11{
16 {
17 private const string _tempFolderName = "temp";
18
19 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
21 private IWorkspaceService _workspaceService;
22 private readonly IEnumerable<IDocumentStrategy> _documentStrategies;
23 private IDocumentFileConverterSelector _documentFileConverterSelector;
24
31 public DocumentService(IWorkspaceService workspaceService, IEnumerable<IDocumentStrategy> documentStrategies, IDocumentFileConverterSelector documentFileConverterSelector)
32 {
33 _workspaceService = workspaceService;
34 _documentStrategies = documentStrategies;
35 _documentFileConverterSelector = documentFileConverterSelector;
36 }
37
38 private IDocumentStrategy getDocumentStrategy(DocumentCreationTypes type)
39 => _documentStrategies.FirstOrDefault(s => s.DocumentType == type) ?? throw new InvalidOperationException($"No strategy found for {type}");
40
44 public string PlaceholderMarker
45 => _workspaceService?.Settings?.GetSettingValue<string>(WorkspaceSettings.GROUP_DOCUMENT_CREATION, WorkspaceSettings.SETTING_DOCUMENT_CREATION_PLACEHOLDER_MARKER) ?? string.Empty;
46
47 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
48
55 public Task<(int, string)> CreateDocument(DocumentCreationTypes documentType, bool createPdf = true)
56 {
57 return Task.Run(() =>
58 {
59 int numCreatedPages = 0;
60
61 string documentOutputFolder = GetDocumentPathAbsolute(WorkspaceSettings.SETTING_DOCUMENT_CREATION_OUTPUT_FOLDER, _workspaceService);
62 if (!Directory.Exists(documentOutputFolder))
63 {
64 Directory.CreateDirectory(documentOutputFolder);
65 }
66
67 IDocumentStrategy documentStrategy = getDocumentStrategy(documentType);
68 string documentTemplate = documentStrategy.TemplatePath;
69 if (Path.GetExtension(documentTemplate) != ".docx")
70 {
71 throw new InvalidOperationException($"Document template \"{documentTemplate}\" is not a .docx file.");
72 }
73
74 // Create the output file name. The TemplateFileNamePostfixReplaceStr is created based on the filter.
75 string outputFileNameDocx = Path.GetFileNameWithoutExtension(documentTemplate);
76 string templateFileNamePostfix = _workspaceService?.Settings?.GetSettingValue<string>(WorkspaceSettings.GROUP_DOCUMENT_CREATION, WorkspaceSettings.SETTING_DOCUMENT_CREATION_TEMPLATE_FILENAME_POSTFIX) ?? string.Empty;
77 string templateFileNamePostfixReplaceStr = documentStrategy.TemplateFileNamePostfixReplaceStr;
78 if (outputFileNameDocx.Contains(templateFileNamePostfix))
79 {
80 outputFileNameDocx = outputFileNameDocx.Replace(templateFileNamePostfix, templateFileNamePostfixReplaceStr);
81 }
82 else
83 {
84 outputFileNameDocx += templateFileNamePostfixReplaceStr;
85 }
86 outputFileNameDocx += ".docx";
87 string outputFile = Path.Combine(documentOutputFolder, outputFileNameDocx);
88
89 // Collect all items used to create the document
90 object[] items = documentStrategy.GetItems();
91
92 string placeholderMarker = PlaceholderMarker;
93
94 // Decide whether to create multiple pages or not
95 if (documentStrategy.CreateMultiplePages)
96 {
97 // Create a temp folder to store all pages as single documents
98 string tempFolder = Path.Combine(documentOutputFolder, _tempFolderName);
99 try
100 {
101 // Delete temp folder and all files in it
102 if (Directory.Exists(tempFolder))
103 {
104 Directory.Delete(tempFolder, true);
105 }
106 Directory.CreateDirectory(tempFolder);
107
108 if (items != null && items.Length > 0)
109 {
110 foreach (object multiplePagesObj in items)
111 {
112 // Create the filename for the temporary file containing one page of the final multi pages document. Make sure the postfix number always contain an equal number of digits (prefixed by 0). This is important later for Directory.GetFiles() ordering.
113 string outputFileMulti = Path.Combine(tempFolder, Path.GetFileNameWithoutExtension(documentTemplate).Replace(templateFileNamePostfix, "") + $"_{numCreatedPages:0000}.docx");
114
115 DocXPlaceholderHelper.TablePlaceholders tablePlaceholders = documentStrategy.ResolveTablePlaceholders(items);
116 if (tablePlaceholders != null) { DocXPlaceholderHelper.ReplaceTablePlaceholders(documentTemplate, outputFileMulti, tablePlaceholders, placeholderMarker); }
117
118 DocXPlaceholderHelper.TextPlaceholders textPlaceholders = documentStrategy.ResolveTextPlaceholders(multiplePagesObj);
119 if (textPlaceholders != null) { DocXPlaceholderHelper.ReplaceTextPlaceholders(tablePlaceholders == null ? documentTemplate : outputFileMulti, outputFileMulti, textPlaceholders, placeholderMarker); }
120
121 insertAlwaysSupportedPlaceholderValues(outputFileMulti, outputFileMulti);
122
123 numCreatedPages++;
124 }
125
126 // Combine all docx files in the temp folder into one docx file
127 string[] files = Directory.GetFiles(tempFolder);
128 if (files.Length > 0)
129 {
130 // Copy the first document as the base for the output file
131 File.Copy(files[0], outputFile, true);
132 using (DocX document = DocX.Load(outputFile))
133 {
134 // Append all other documents to the first one
135 for (int i = 1; i < files.Length; i++)
136 {
137 using (DocX tempDocument = DocX.Load(files[i]))
138 {
139 document.InsertDocument(tempDocument, true);
140 }
141 }
142 document.Save();
143 }
144 }
145 }
146 }
147 catch (Exception)
148 {
149 throw;
150 }
151 finally
152 {
153 // Delete temp folder and all files in it
154 if (Directory.Exists(tempFolder))
155 {
156 Directory.Delete(tempFolder, true);
157 }
158 }
159 }
160 else
161 {
162 // Create a single page document
163 string inputFile = documentTemplate;
164
165 DocXPlaceholderHelper.TablePlaceholders tablePlaceholders = documentStrategy.ResolveTablePlaceholders(items);
166 if (tablePlaceholders != null)
167 {
168 DocXPlaceholderHelper.ReplaceTablePlaceholders(inputFile, outputFile, tablePlaceholders, placeholderMarker);
169 inputFile = outputFile;
170 }
171
172 foreach (object item in items)
173 {
174 DocXPlaceholderHelper.TextPlaceholders textPlaceholders = documentStrategy.ResolveTextPlaceholders(item);
175 if (textPlaceholders != null)
176 {
177 DocXPlaceholderHelper.ReplaceTextPlaceholders(inputFile, outputFile, textPlaceholders, placeholderMarker);
178 inputFile = outputFile;
179 }
180 }
181 insertAlwaysSupportedPlaceholderValues(outputFile, outputFile);
182
183 numCreatedPages = 1; // We created one page for the document
184 }
185
186 DocumentCreationFileTypes fileTypes = _workspaceService?.Settings?.GetSettingValue<DocumentCreationFileTypes>(WorkspaceSettings.GROUP_DOCUMENT_CREATION, WorkspaceSettings.SETTING_DOCUMENT_CREATION_FILE_TYPES) ?? DocumentCreationFileTypes.DOCX_AND_PDF;
187
188 string returnFilePath = outputFile;
189
190 // Create PDF if requested and file type is PDF or DOCX_AND_PDF
191 if (createPdf && (fileTypes == DocumentCreationFileTypes.PDF || fileTypes == DocumentCreationFileTypes.DOCX_AND_PDF))
192 {
193 returnFilePath = convertToPdf(outputFile);
194 }
195
196 // Delete the .docx file if file type is PDF
197 if (fileTypes == DocumentCreationFileTypes.PDF)
198 {
199 if (File.Exists(outputFile))
200 {
201 File.Delete(outputFile);
202 }
203 }
204
205 return (numCreatedPages, returnFilePath);
206 });
207 }
208
209 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
210
211 #region Helper methods
212
219 public static string GetDocumentPathAbsolute(string documentCreationSettingKey, IWorkspaceService workspaceService)
220 {
221 string path = workspaceService?.Settings?.GetSettingValue<string>(WorkspaceSettings.GROUP_DOCUMENT_CREATION, documentCreationSettingKey) ?? string.Empty;
222 path = FilePathHelper.MakePathAbsolute(path, workspaceService?.PersistentPath);
223 return path;
224 }
225
231 private void insertAlwaysSupportedPlaceholderValues(string templateFile, string outputFile)
232 {
233 // Make sure to have logic here for all values in DocumentStrategyBase<TData>.AlwaysSupportedPlaceholderKeys
234
235 ushort competitionYear = _workspaceService?.Settings?.GetSettingValue<ushort>(WorkspaceSettings.GROUP_GENERAL, WorkspaceSettings.SETTING_GENERAL_COMPETITIONYEAR) ?? 0;
236 DateTime competitionDate = _workspaceService?.Settings?.GetSettingValue<DateTime>(WorkspaceSettings.GROUP_GENERAL, WorkspaceSettings.SETTING_GENERAL_COMPETITIONDATE) ?? DateTime.Today;
237 string appVersion = System.Reflection.Assembly.GetEntryAssembly().GetName().Version?.ToString() ?? "?";
238 string workspacePath = _workspaceService?.PersistentPath ?? string.Empty;
239
240 DocXPlaceholderHelper.TextPlaceholders textPlaceholders = new DocXPlaceholderHelper.TextPlaceholders();
241 foreach (string placeholder in Placeholders.Placeholders_CompetitionYear) { textPlaceholders.Add(placeholder, competitionYear.ToString()); }
242 foreach (string placeholder in Placeholders.Placeholders_CompetitionDate) { textPlaceholders.Add(placeholder, competitionDate.ToShortDateString()); }
243 foreach (string placeholder in Placeholders.Placeholders_AppVersion) { textPlaceholders.Add(placeholder, appVersion); }
244 foreach (string placeholder in Placeholders.Placeholders_WorkspacePath) { textPlaceholders.Add(placeholder, workspacePath); }
245
246 DocXPlaceholderHelper.ReplaceTextPlaceholders(templateFile, outputFile, textPlaceholders, PlaceholderMarker);
247 }
248
254 private string convertToPdf(string docxFile)
255 {
256 // Convert the docx file to pdf
257 string outputFilePdf = docxFile.Replace(".docx", ".pdf");
258 File.Delete(outputFilePdf);
259
260 List<IDocumentFileConverter> ignoreConverters = new List<IDocumentFileConverter>();
261 IDocumentFileConverter converter = null;
262 bool conversionResult = false;
263 Exception firstException = null;
264 // Loop until no converter is found anymore or the conversion is finished.
265 do
266 {
267 converter = _documentFileConverterSelector.GetConverter(docxFile, ignoreConverters);
268 try
269 {
270 conversionResult = converter?.Convert(docxFile, outputFilePdf) ?? false;
271 }
272 catch(Exception ex)
273 {
274 if(firstException == null)
275 {
276 firstException = ex;
277 }
278 conversionResult = false;
279 }
280 if(!conversionResult)
281 {
282 ignoreConverters.Add(converter);
283 }
284 } while (converter != null && !conversionResult);
285
286 if(!conversionResult && firstException != null)
287 {
288 throw firstException;
289 }
290 return outputFilePdf;
291 }
292
293 #endregion
294
295 }
296}
Class to hold table placeholders and their list of values.
string PlaceholderMarker
Get the placeholder marker string used in the document templates.
DocumentService(IWorkspaceService workspaceService, IEnumerable< IDocumentStrategy > documentStrategies, IDocumentFileConverterSelector documentFileConverterSelector)
Constructor for the DocumentService.
static string GetDocumentPathAbsolute(string documentCreationSettingKey, IWorkspaceService workspaceService)
Get the absolute path for the requested document creation setting.
Task<(int, string)> CreateDocument(DocumentCreationTypes documentType, bool createPdf=true)
Create the document indicated by the document type.
void insertAlwaysSupportedPlaceholderValues(string templateFile, string outputFile)
Insert the values for the DocumentStrategyBase<TData>.AlwaysSupportedPlaceholderKeys into the templat...
string convertToPdf(string docxFile)
Convert a .docx file to a .pdf file using LibreOffice.
Interface for a service used to create documents like certificates or start lists.
Interface for a service used to manage a workspace.
WorkspaceSettings Settings
Settings for the current workspace.
bool Convert(string inputFile, string outputFile)
Convert a document.
Interface for document strategies that define how to create and collect data for different types of d...
DocXPlaceholderHelper.TextPlaceholders ResolveTextPlaceholders(object item=null)
Resolve text placeholders for the given item.
string TemplateFileNamePostfixReplaceStr
Use this string instead of the template file name postfix during document creation.
bool CreateMultiplePages
Gets a value indicating whether this strategy supports creating multiple pages in the document.
DocXPlaceholderHelper.TablePlaceholders ResolveTablePlaceholders(object[] items)
Resolve table placeholders for the given items.
object[] GetItems()
Retrieves the items that will be used to create the document.
string TemplatePath
Gets the path to the template used for creating the document.
DocumentCreationTypes
Different types of documents that can be created.
DocumentCreationFileTypes
Different file types of documents that can be created.