Skip to content

Commit 373b30b

Browse files
author
Zihlu Wang
committed
fix(webcal): Fix the issue that some system are not able to load the output ics format.
Closes #16
1 parent b2378df commit 373b30b

File tree

4 files changed

+96
-28
lines changed

4 files changed

+96
-28
lines changed

webcal/src/main/java/cn/org/codecrafters/webcal/WebCalendar.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
package cn.org.codecrafters.webcal;
1919

20+
import java.time.format.DateTimeFormatter;
2021
import java.util.ArrayList;
2122
import java.util.List;
23+
import java.util.Objects;
2224

2325
/**
2426
* {@code WebCalendar} class represents a web calendar in iCalendar format.
@@ -189,18 +191,22 @@ public WebCalendar addEvent(WebCalendarEvent event) {
189191
* @return the resolved iCalendar string
190192
*/
191193
public String resolve() {
192-
var events = new StringBuilder();
194+
var eventBuilder = new StringBuilder();
193195
if (!nodes.isEmpty()) {
194-
nodes.forEach(item ->
195-
events.append(item.setDomainName(domainName)
196-
.resolve()));
196+
for (var node : nodes) {
197+
if (Objects.isNull(node.getDomainName()) || node.getDomainName().isBlank()) {
198+
node.setDomainName(this.domainName);
199+
}
200+
201+
eventBuilder.append(node.resolve());
202+
}
197203
}
198204

199205
return "BEGIN:" + TAG + "\n" +
200206
"PRODID:-//" + companyName + "//" + productName + "//EN\n" +
201207
"VERSION:" + version + "\n" +
202208
"X-WR-CALNAME:" + name + "\n" +
203-
events + "\n" +
209+
eventBuilder + "\n" +
204210
"END:" + TAG;
205211
}
206212

webcal/src/main/java/cn/org/codecrafters/webcal/WebCalendarEvent.java

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
package cn.org.codecrafters.webcal;
1919

2020
import cn.org.codecrafters.webcal.config.Classification;
21+
import cn.org.codecrafters.webcal.config.Formatter;
2122

23+
import java.text.MessageFormat;
2224
import java.time.Duration;
2325
import java.time.LocalDateTime;
24-
import java.time.format.DateTimeFormatter;
26+
import java.time.ZoneId;
2527
import java.util.Arrays;
2628
import java.util.Collection;
2729
import java.util.Optional;
@@ -257,30 +259,34 @@ public WebCalendarEvent setTimezone(String timezone) {
257259
*/
258260
@Override
259261
public String resolve() {
260-
return "\nBEGIN:" + TAG + "\n" +
261-
"UID:" + Optional.ofNullable(uid).orElse(UUID.randomUUID().toString()) + "@" + domainName + "\n" +
262-
Optional.ofNullable(summary).map((item) -> "SUMMARY:" + item + "\n").orElse("") +
263-
"DTSTART" + Optional.ofNullable(timezone).map(item -> ";TZID=" + item).orElse("") + ":" + start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\n" +
262+
var now = LocalDateTime.now().atZone(ZoneId.systemDefault());
263+
return MessageFormat.format("""
264+
BEGIN:{0}
265+
UID:{1}
266+
DTSTAMP:{2}
267+
DTSTART:{3}
268+
DURATION:PT{6}S
269+
{4}{5}{7}{8}{9}{10}{11}{12}
270+
END:{0}""",
271+
TAG, // 0 - tag
272+
Optional.ofNullable(uid).orElse(UUID.randomUUID().toString()) + "@" + domainName, // 1 - uid
273+
now.format(Formatter.getUtcDatetimeFormatter()), // 2 - dtstamp
274+
start.atZone(ZoneId.systemDefault()).format(Formatter.getUtcDatetimeFormatter()), // 3 - start time
275+
Optional.ofNullable(summary).map((item) -> "\nSUMMARY:" + item).orElse(""), // 4 - summary
264276
Optional.ofNullable(categories)
265-
.map((item) -> {
266-
if (!item.isEmpty()) {
267-
return "CATEGORIES:" + resolveCategories() + "\n";
268-
}
269-
return null;
270-
}).orElse("") +
277+
.map((item) -> !item.isEmpty() ? "\nCATEGORIES:" + resolveCategories() : null).orElse(""), // 5 - categories
271278
Optional.ofNullable(duration)
272-
.map((item) -> "DURATION:PT" + item.getSeconds() + "S\n").orElse("") +
273-
Optional.ofNullable(end)
274-
.map((item) -> "DTEND" + Optional.ofNullable(timezone).map(tz -> ";TZID=" + tz).orElse("") + ":" +
275-
end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\n").orElse("") +
276-
Optional.ofNullable(classification)
277-
.map((item) -> "CLASS:" + item.name() + "\n").orElse("") +
278-
Optional.ofNullable(comment).map((item) -> "COMMENT:" + item + "\n").orElse("") +
279-
Optional.ofNullable(description).map((item) -> "DESCRIPTION:" + item + "\n").orElse("") +
280-
Optional.ofNullable(location).map((item) -> "LOCATION:" + item + "\n").orElse("") +
281-
Optional.ofNullable(percentComplete).map((item) -> "PERCENT-COMPLETE:" + item + "\n").orElse("") +
282-
Optional.ofNullable(priority).map((item) -> "PRIORITY:" + item + "\n").orElse("") +
283-
"END:" + TAG + "\n";
279+
.map((_duration) -> String.valueOf(_duration.getSeconds()))
280+
.orElse(Optional.ofNullable(end)
281+
.map((_end) -> String.valueOf(Duration.between(_end, start).getSeconds()))
282+
.orElse("0")), // 6 - duration
283+
Optional.ofNullable(classification).map((_classification) -> "\nCLASS:" + _classification + "\n").orElse(""), /* 7 - classification */
284+
Optional.ofNullable(comment).map((_comment) -> "\nCOMMENT:" + _comment + "\n").orElse(""), /* 8 - comment */
285+
Optional.ofNullable(location).map((_location) -> "\nLOCATION:" + _location).orElse("") /* 9 - location */,
286+
Optional.ofNullable(percentComplete).map((_percentComplete) -> "\nPERCENT-COMPLETE:" + _percentComplete).orElse("") /* 10 = percentComplete */,
287+
Optional.ofNullable(description).map((_description) -> "\nDESCRIPTION:" + _description).orElse("") /* 11 - description */,
288+
Optional.ofNullable(priority).map((_priority) -> "\nPRIORITY:" + _priority).orElse("") /* 12 - priority */
289+
);
284290
}
285291

286292
}

webcal/src/main/java/cn/org/codecrafters/webcal/WebCalendarNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ public WebCalendarNode setDomainName(String domainName) {
9090
return this;
9191
}
9292

93+
public String getDomainName() {
94+
return this.domainName;
95+
}
96+
9397
/**
9498
* Resolve the list of categories into a comma-separated string.
9599
*
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2023 CodeCraftersCN.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package cn.org.codecrafters.webcal.config;
19+
20+
import java.time.ZoneOffset;
21+
import java.time.format.DateTimeFormatter;
22+
import java.util.Objects;
23+
24+
/**
25+
* DatetimeFormatters
26+
*
27+
* @author Zihlu Wang
28+
* @since 21 Sept, 2023
29+
*/
30+
public final class Formatter {
31+
32+
public static DateTimeFormatter getUtcDatetimeFormatter() {
33+
if (Objects.isNull(utcDateTimeFormatter)) {
34+
utcDateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'").withZone(ZoneOffset.UTC);
35+
}
36+
37+
return utcDateTimeFormatter;
38+
}
39+
40+
// public static DateTimeFormatter getLocalDatetimeFormatter() {
41+
// if (Objects.isNull(localDatetimeFormatter)) {
42+
// localDatetimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss");
43+
// }
44+
//
45+
// return localDatetimeFormatter;
46+
// }
47+
48+
private static DateTimeFormatter utcDateTimeFormatter;
49+
50+
// private static DateTimeFormatter localDatetimeFormatter;
51+
52+
}

0 commit comments

Comments
 (0)