1+ using System . Collections . Generic ;
2+ using System . Globalization ;
13using System . IO ;
24using System . Linq ;
35using System . Text ;
46using System . Xml ;
7+ using CsvHelper ;
58using Geta . NotFoundHandler . Admin . Pages . Geta . NotFoundHandler . Admin . Components . Card ;
69using Geta . NotFoundHandler . Admin . Pages . Geta . NotFoundHandler . Admin . Infrastructure ;
710using Geta . NotFoundHandler . Core . Redirects ;
@@ -20,15 +23,21 @@ public class AdministerModel : PageModel
2023 private readonly IRedirectsService _redirectsService ;
2124 private readonly ISuggestionService _suggestionService ;
2225 private readonly RedirectsXmlParser _redirectsXmlParser ;
26+ private readonly RedirectsCsvParser _redirectsCsvParser ;
27+ private readonly RedirectsTxtParser _redirectsTxtParser ;
2328
2429 public AdministerModel (
2530 IRedirectsService redirectsService ,
2631 ISuggestionService suggestionService ,
27- RedirectsXmlParser redirectsXmlParser )
32+ RedirectsXmlParser redirectsXmlParser ,
33+ RedirectsCsvParser redirectsCsvParser ,
34+ RedirectsTxtParser redirectsTxtParser )
2835 {
2936 _redirectsService = redirectsService ;
3037 _suggestionService = suggestionService ;
3138 _redirectsXmlParser = redirectsXmlParser ;
39+ _redirectsCsvParser = redirectsCsvParser ;
40+ _redirectsTxtParser = redirectsTxtParser ;
3241 }
3342
3443 [ BindProperty ( SupportsGet = true ) ]
@@ -46,162 +55,135 @@ public AdministerModel(
4655 public IActionResult OnPostDeleteAllIgnoredSuggestions ( )
4756 {
4857 var count = _redirectsService . DeleteAllIgnored ( ) ;
49- Message = $ "All { count } ignored suggestions permanently removed";
50- CardType = CardType . Success ;
5158
52- return RedirectToPage ( new {
53- Message ,
54- CardType
55- } ) ;
59+ return BuildResponse ( $ "All { count } ignored suggestions permanently removed", CardType . Success ) ;
5660 }
5761
5862 public IActionResult OnPostDeleteAllSuggestions ( )
5963 {
6064 _suggestionService . DeleteAll ( ) ;
61- Message = "Suggestions successfully deleted" ;
62- CardType = CardType . Success ;
6365
64- return RedirectToPage ( new
65- {
66- Message ,
67- CardType
68- } ) ;
66+ return BuildResponse ( "Suggestions successfully deleted" , CardType . Success ) ;
6967 }
7068
7169 public IActionResult OnPostDeleteAllRedirects ( )
7270 {
7371 _redirectsService . DeleteAll ( ) ;
74- Message = "Redirects successfully deleted" ;
75- CardType = CardType . Success ;
7672
77- return RedirectToPage ( new
78- {
79- Message ,
80- CardType
81- } ) ;
73+ return BuildResponse ( "Redirects successfully deleted" , CardType . Success ) ;
8274 }
8375
8476 public IActionResult OnPostDeleteSuggestions ( )
8577 {
8678 if ( ! ModelState . IsValid ) return Page ( ) ;
8779
8880 _suggestionService . Delete ( DeleteSuggestions . MaxErrors , DeleteSuggestions . MinimumDays ) ;
89- Message = "Suggestions successfully deleted" ;
90- CardType = CardType . Success ;
9181
92- return RedirectToPage ( new
93- {
94- Message ,
95- CardType
96- } ) ;
82+ return BuildResponse ( "Suggestions successfully deleted" , CardType . Success ) ;
9783 }
9884
9985 public IActionResult OnPostImportRedirects ( )
10086 {
101- if ( ImportFile == null || ! ImportFile . IsXml ( ) )
87+ if ( ImportFile == null )
10288 {
103- Message = "The uploaded file is not a valid XML file. Please upload a valid XML file." ;
104- CardType = CardType . Warning ;
105-
106- return RedirectToPage ( new
107- {
108- Message ,
109- CardType
110- } ) ;
89+ return BuildResponse ( "The uploaded file is not a valid XML or CSV file. Please upload a valid XML/CSV file." ,
90+ CardType . Warning ) ;
11191 }
11292
113- var redirects = _redirectsXmlParser . LoadFromStream ( ImportFile . OpenReadStream ( ) ) ;
114-
115- if ( redirects . Any ( ) )
93+ if ( ImportFile . IsXml ( ) )
11694 {
117- _redirectsService . AddOrUpdate ( redirects ) ;
118- Message = $ "{ redirects . Count ( ) } urls successfully imported.";
119- CardType = CardType . Success ;
95+ return ProcessFile ( _redirectsXmlParser ) ;
12096 }
121- else
97+
98+ if ( ImportFile . IsCsv ( ) )
12299 {
123- Message = "No redirects could be imported" ;
124- CardType = CardType . Warning ;
100+ return ProcessFile ( _redirectsCsvParser ) ;
125101 }
126102
127- return RedirectToPage ( new
128- {
129- Message ,
130- CardType
131- } ) ;
103+ return BuildResponse ( "The uploaded file is not a valid. Please upload a file." ,
104+ CardType . Warning ) ;
132105 }
133106
134107 public IActionResult OnPostImportDeletedRedirects ( )
135108 {
136109 if ( ImportFile == null || ! ImportFile . IsTxt ( ) )
137110 {
138- Message = "The uploaded file is not a valid TXT file. Please upload a valid TXT file." ;
139- CardType = CardType . Warning ;
140-
141- return RedirectToPage ( new
142- {
143- Message ,
144- CardType
145- } ) ;
111+ return BuildResponse ( "The uploaded file is not a valid TXT file. Please upload a valid TXT file." , CardType . Warning ) ;
146112 }
147113
148- var redirects = ReadDeletedRedirectsFromImportFile ( ) ;
114+ return ProcessFile ( _redirectsTxtParser ) ;
115+ }
149116
150- if ( redirects . Any ( ) )
117+ public IActionResult OnPostExportRedirects ( string typeId )
118+ {
119+ if ( string . IsNullOrEmpty ( typeId ) )
151120 {
152- _redirectsService . AddOrUpdate ( redirects ) ;
153- Message = $ "{ redirects . Count ( ) } urls successfully imported.";
154- CardType = CardType . Success ;
121+ return BuildResponse ( "Failed to Export" , CardType . Warning ) ;
155122 }
156- else
123+
124+ var redirects = _redirectsService . GetSaved ( ) . ToList ( ) ;
125+
126+ if ( ! redirects . Any ( ) )
157127 {
158- Message = "No redirects could be imported" ;
159- CardType = CardType . Warning ;
128+ return BuildResponse ( "Nothing to Export" , CardType . Warning ) ;
160129 }
161130
162- return RedirectToPage ( new
131+ return typeId . ToLower ( ) switch
163132 {
164- Message ,
165- CardType
166- } ) ;
133+ "xml" => ExportAsXml ( redirects ) ,
134+ "csv" => ExportAsCsv ( redirects ) ,
135+ _ => BuildResponse ( "Failed to export. Unsupported export type" , CardType . Warning )
136+ } ;
167137 }
168138
169- public IActionResult OnPostExportRedirects ( )
139+ private IActionResult ExportAsXml ( List < CustomRedirect > redirects )
170140 {
171- var redirects = _redirectsService . GetSaved ( ) . ToList ( ) ;
172141 var document = _redirectsXmlParser . Export ( redirects ) ;
173142
174- var memoryStream = new MemoryStream ( ) ;
175- var writer = new XmlTextWriter ( memoryStream , Encoding . UTF8 )
176- {
177- Formatting = Formatting . Indented
178- } ;
143+ using var memoryStream = new MemoryStream ( ) ;
144+ using var writer = new XmlTextWriter ( memoryStream , Encoding . UTF8 ) { Formatting = Formatting . Indented } ;
179145 document . WriteTo ( writer ) ;
180146 writer . Flush ( ) ;
181147 memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
182148
183- return File ( memoryStream , "text/xml" , "customRedirects.xml" ) ;
149+ return File ( memoryStream . ToArray ( ) , "text/xml" , "customRedirects.xml" ) ;
184150 }
185151
186- private CustomRedirectCollection ReadDeletedRedirectsFromImportFile ( )
152+ private IActionResult ExportAsCsv ( List < CustomRedirect > redirects )
187153 {
188- var redirects = new CustomRedirectCollection ( ) ;
189- using var streamReader = new StreamReader ( ImportFile . OpenReadStream ( ) ) ;
190- while ( streamReader . Peek ( ) >= 0 )
154+ var documents = _redirectsCsvParser . Export ( redirects ) ;
155+
156+ using var memoryStream = new MemoryStream ( ) ;
157+ using ( var tw = new StreamWriter ( memoryStream , leaveOpen : true ) )
158+ using ( var csv = new CsvWriter ( tw , CultureInfo . InvariantCulture ) )
191159 {
192- var url = streamReader . ReadLine ( ) ;
193- if ( ! string . IsNullOrEmpty ( url ) )
194- {
195- redirects . Add ( new CustomRedirect
196- {
197- OldUrl = url ,
198- NewUrl = string . Empty ,
199- State = ( int ) RedirectState . Deleted
200- } ) ;
201- }
160+ csv . WriteRecords ( documents ) ;
161+ }
162+
163+ memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
164+ return File ( memoryStream . ToArray ( ) , "text/csv" , "customRedirects.csv" ) ;
165+ }
166+
167+ private IActionResult BuildResponse ( string message , CardType cardType )
168+ {
169+ Message = message ;
170+ CardType = cardType ;
171+
172+ return RedirectToPage ( new { Message , CardType } ) ;
173+ }
174+
175+ private IActionResult ProcessFile ( IRedirectsParser parser )
176+ {
177+ var redirects = parser . LoadFromStream ( ImportFile . OpenReadStream ( ) ) ;
178+
179+ if ( redirects . Any ( ) )
180+ {
181+ _redirectsService . AddOrUpdate ( redirects ) ;
182+
183+ return BuildResponse ( $ "{ redirects . Count ( ) } urls successfully imported.", CardType . Success ) ;
202184 }
203185
204- return redirects ;
186+ return BuildResponse ( "No redirects could be imported" , CardType . Warning ) ;
205187 }
206188}
207189
0 commit comments