Merge branch 'master' of https://github.com/DreamExposure/DisCal-Discord-Bot into feature/rsvp-role

This commit is contained in:
NovaFox161
2021-03-21 09:21:09 -05:00
34 changed files with 2251 additions and 1556 deletions
@@ -2,7 +2,8 @@ package org.dreamexposure.discal.client.calendar;
import com.google.api.services.calendar.model.AclRule;
import com.google.api.services.calendar.model.Calendar;
import discord4j.common.util.Snowflake;
import discord4j.core.event.domain.message.MessageCreateEvent;
import org.dreamexposure.discal.client.message.CalendarMessageFormatter;
import org.dreamexposure.discal.client.message.Messages;
import org.dreamexposure.discal.core.calendar.CalendarAuth;
@@ -13,15 +14,12 @@ import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.calendar.PreCalendar;
import org.dreamexposure.discal.core.wrapper.google.AclRuleWrapper;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import discord4j.common.util.Snowflake;
import discord4j.core.event.domain.message.MessageCreateEvent;
import reactor.core.publisher.Mono;
/**
* Created by Nova Fox on 1/4/2017.
* Website: www.cloudcraftgaming.com
@@ -129,7 +127,7 @@ public class CalendarCreator {
final int credId = new Random().nextInt(CalendarAuth.credentialsCount());
if (!pre.getEditing()) {
return CalendarWrapper.createCalendar(calendar, credId)
return CalendarWrapper.createCalendar(calendar, credId, settings.getGuildID())
.flatMap(confirmed -> {
final CalendarData data = new CalendarData(
settings.getGuildID(),
@@ -47,7 +47,7 @@ public class EventCreator {
if (!this.hasPreEvent(settings.getGuildID())) {
return DatabaseManager.getCalendar(settings.getGuildID(), 1) //TODO: handle multiple calendars
.flatMap(calData -> {
final PreEvent event = new PreEvent(settings.getGuildID());
final PreEvent event = new PreEvent(settings.getGuildID(), calData.getCalendarNumber());
this.events.add(event);
return CalendarWrapper.getCalendar(calData)
@@ -67,7 +67,7 @@ public class EventCreator {
if (!this.hasPreEvent(settings.getGuildID())) {
return DatabaseManager.getCalendar(settings.getGuildID(), 1) //TODO: handle multiple calendars
.flatMap(calData -> {
final PreEvent event = new PreEvent(settings.getGuildID());
final PreEvent event = new PreEvent(settings.getGuildID(), calData.getCalendarNumber());
event.setSummary(summary);
this.events.add(event);
@@ -90,9 +90,8 @@ public class EventCreator {
if (!this.hasPreEvent(settings.getGuildID())) {
return DatabaseManager.getCalendar(settings.getGuildID(), 1) //TODO: handle multiple calendars
.flatMap(calData -> EventWrapper.getEvent(calData, eventId)
.flatMap(toCopy -> {
final PreEvent event = new PreEvent(settings.getGuildID(), toCopy);
.flatMap(toCopy -> PreEvent.copy(settings.getGuildID(), toCopy, calData))
.flatMap(event -> {
this.events.add(event);
return CalendarWrapper.getCalendar(calData)
@@ -112,8 +111,8 @@ public class EventCreator {
if (!this.hasPreEvent(settings.getGuildID())) {
return DatabaseManager.getCalendar(settings.getGuildID(), 1) //TODO: handle multiple calendars
.flatMap(calData -> EventWrapper.getEvent(calData, eventId)
.flatMap(toEdit -> {
final PreEvent event = new PreEvent(settings.getGuildID(), toEdit);
.flatMap(toEdit -> PreEvent.copy(settings.getGuildID(), toEdit, calData))
.flatMap(event -> {
event.setEditing(true);
this.events.add(event);
@@ -15,9 +15,9 @@ import org.dreamexposure.discal.core.utils.ImageUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.function.Consumer;
import javax.annotation.Nullable;
@@ -35,21 +35,20 @@ import reactor.function.TupleUtils;
*/
@SuppressWarnings("MagicNumber")
public class EventMessageFormatter {
@Deprecated
public static Mono<Consumer<EmbedCreateSpec>> getEventEmbed(final Event event, final GuildSettings settings) {
public static Mono<Consumer<EmbedCreateSpec>> getEventEmbed(Event event, int calNum, GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> sDate = getHumanReadableDate(event.getStart(), false, settings);
final Mono<String> sTime = getHumanReadableTime(event.getStart(), false, settings);
final Mono<String> eDate = getHumanReadableDate(event.getEnd(), false, settings);
final Mono<String> eTime = getHumanReadableTime(event.getEnd(), false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
Mono<EventData> data = DatabaseManager.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData())
.cache();
Mono<String> sDate = getHumanReadableDate(event.getStart(), calNum, false, settings);
Mono<String> sTime = getHumanReadableTime(event.getStart(), calNum, false, settings);
Mono<String> eDate = getHumanReadableDate(event.getEnd(), calNum, false, settings);
Mono<String> eTime = getHumanReadableTime(event.getEnd(), calNum, false, settings);
Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
final Mono<String> timezone = DatabaseManager.getMainCalendar(settings.getGuildID())
.flatMap(d -> CalendarWrapper.getCalendar(d))
Mono<String> timezone = DatabaseManager.getCalendar(settings.getGuildID(), calNum)
.flatMap(CalendarWrapper::getCalendar)
.map(com.google.api.services.calendar.model.Calendar::getTimeZone)
.defaultIfEmpty("Error/Unknown");
@@ -80,12 +79,20 @@ public class EventMessageFormatter {
}
spec.addField(Messages.getMessage("Embed.Event.Info.Description", settings), description, false);
}
//Start time
spec.addField(Messages.getMessage("Embed.Event.Info.StartDate", settings), startDate, true);
spec.addField(Messages.getMessage("Embed.Event.Info.StartTime", settings), startTime, true);
//Timezone so that start/end times are split up cleanly on discord
spec.addField(Messages.getMessage("Embed.Event.Info.TimeZone", settings), tz, false);
//End time
spec.addField(Messages.getMessage("Embed.Event.Info.EndDate", settings), endDate, true);
spec.addField(Messages.getMessage("Embed.Event.Info.EndTime", settings), endTime, true);
spec.addField(Messages.getMessage("Embed.Event.Info.TimeZone", settings), tz, true);
//Location handling
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
if (event.getLocation().length() > 300) {
final String location = event.getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
@@ -99,7 +106,7 @@ public class EventMessageFormatter {
spec.setFooter(Messages.getMessage("Embed.Event.Info.ID", "%id%", event.getId(), settings), null);
if (event.getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(event.getColorId()));
final EventColor ec = EventColor.Companion.fromId(Integer.parseInt(event.getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
@@ -107,145 +114,20 @@ public class EventMessageFormatter {
}));
}
public static Mono<Consumer<EmbedCreateSpec>> getEventEmbed(final Event event, final int calNum, final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> sDate = getHumanReadableDate(event.getStart(), calNum, false, settings);
final Mono<String> sTime = getHumanReadableTime(event.getStart(), calNum, false, settings);
final Mono<String> eDate = getHumanReadableDate(event.getEnd(), calNum, false, settings);
final Mono<String> eTime = getHumanReadableTime(event.getEnd(), calNum, false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
final Mono<String> timezone = DatabaseManager.getCalendar(settings.getGuildID(), calNum)
.flatMap(d -> CalendarWrapper.getCalendar(d))
.map(com.google.api.services.calendar.model.Calendar::getTimeZone)
.defaultIfEmpty("Error/Unknown");
return Mono.zip(guild, data, sDate, sTime, eDate, eTime, img, timezone)
.map(TupleUtils.function((g, ed, startDate, startTime, endDate, endTime, hasImg, tz) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite, g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
spec.setAuthor("DisCal", GlobalConst.discalSite, GlobalConst.iconUrl);
spec.setTitle(Messages.getMessage("Embed.Event.Info.Title", settings));
if (hasImg) {
spec.setImage(ed.getImageLink());
}
if (event.getSummary() != null) {
String summary = event.getSummary();
if (summary.length() > 250) {
summary = summary.substring(0, 250);
summary = summary + " (continues on Google Calendar View)";
}
spec.addField(Messages.getMessage("Embed.Event.Info.Summary", settings), summary, false);
}
if (event.getDescription() != null) {
String description = event.getDescription();
if (description.length() > 500) {
description = description.substring(0, 500);
description = description + " (continues on Google Calendar View)";
}
spec.addField(Messages.getMessage("Embed.Event.Info.Description", settings), description, false);
}
spec.addField(Messages.getMessage("Embed.Event.Info.StartDate", settings), startDate, true);
spec.addField(Messages.getMessage("Embed.Event.Info.StartTime", settings), startTime, true);
spec.addField(Messages.getMessage("Embed.Event.Info.EndDate", settings), endDate, true);
spec.addField(Messages.getMessage("Embed.Event.Info.EndTime", settings), endTime, true);
spec.addField(Messages.getMessage("Embed.Event.Info.TimeZone", settings), tz, true);
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
if (event.getLocation().length() > 300) {
final String location = event.getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), event.getLocation(), false);
}
}
//TODO: Add info on recurrence here.
spec.setUrl(event.getHtmlLink());
spec.setFooter(Messages.getMessage("Embed.Event.Info.ID", "%id%", event.getId(), settings), null);
if (event.getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(event.getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
}
}));
}
@Deprecated
public static Mono<Consumer<EmbedCreateSpec>> getCondensedEventEmbed(final Event event, final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> date = getHumanReadableDate(event.getStart(), false, settings);
final Mono<String> time = getHumanReadableTime(event.getStart(), false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
return Mono.zip(guild, data, time, date, img)
.map(TupleUtils.function((g, ed, startDate, startTime, hasImg) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite, g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
spec.setAuthor("DisCal", GlobalConst.discalSite, GlobalConst.iconUrl);
spec.setTitle(Messages.getMessage("Embed.Event.Condensed.Title", settings));
if (hasImg)
spec.setThumbnail(ed.getImageLink());
if (event.getSummary() != null) {
String summary = event.getSummary();
if (summary.length() > 250) {
summary = summary.substring(0, 250);
summary = summary + " (continues on Google Calendar View)";
}
spec.addField(Messages.getMessage("Embed.Event.Condensed.Summary", settings), summary, false);
}
spec.addField(Messages.getMessage("Embed.Event.Condensed.Date", settings), startDate, true);
spec.addField(Messages.getMessage("Embed.Event.Condensed.Time", settings), startTime, true);
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
if (event.getLocation().length() > 300) {
final String location = event.getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), event.getLocation(), false);
}
}
spec.addField(Messages.getMessage("Embed.Event.Condensed.ID", settings), event.getId(), false);
spec.setUrl(event.getHtmlLink());
if (event.getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(event.getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
}
}));
}
public static Mono<Consumer<EmbedCreateSpec>> getCondensedEventEmbed(final Event event, final int calNum, final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> date = getHumanReadableDate(event.getStart(), calNum, false, settings);
final Mono<String> time = getHumanReadableTime(event.getOriginalStartTime(), 1, false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
public static Mono<Consumer<EmbedCreateSpec>> getCondensedEventEmbed(Event event, int calNum,
GuildSettings settings) {
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
Mono<EventData> data = DatabaseManager.getEventData(settings.getGuildID(), event.getId())
.defaultIfEmpty(new EventData())
.cache();
Mono<String> date = getHumanReadableDate(event.getStart(), calNum, false, settings);
Mono<String> time = getHumanReadableTime(event.getStart(), 1, false, settings);
Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
return Mono.zip(guild, data, date, time, img)
.map(TupleUtils.function((g, ed, startData, startTime, hasImg) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite, g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
@@ -277,7 +159,7 @@ public class EventMessageFormatter {
spec.setUrl(event.getHtmlLink());
if (event.getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(event.getColorId()));
final EventColor ec = EventColor.Companion.fromId(Integer.parseInt(event.getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
@@ -285,14 +167,13 @@ public class EventMessageFormatter {
}));
}
public static Mono<Consumer<EmbedCreateSpec>> getPreEventEmbed(final PreEvent event, final int calNum,
final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<String> sDate = getHumanReadableDate(event.getStartDateTime(), calNum, false, settings);
final Mono<String> sTime = getHumanReadableTime(event.getStartDateTime(), calNum, false, settings);
final Mono<String> eDate = getHumanReadableDate(event.getEndDateTime(), calNum, false, settings);
final Mono<String> eTime = getHumanReadableTime(event.getEndDateTime(), calNum, false, settings);
final Mono<Boolean> img = Mono.justOrEmpty(event.getEventData()).filter(EventData::shouldBeSaved)
public static Mono<Consumer<EmbedCreateSpec>> getPreEventEmbed(PreEvent event, GuildSettings settings) {
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
Mono<String> sDate = getHumanReadableDate(event.getStartDateTime(), event.getCalNumber(), false, settings);
Mono<String> sTime = getHumanReadableTime(event.getStartDateTime(), event.getCalNumber(), false, settings);
Mono<String> eDate = getHumanReadableDate(event.getEndDateTime(), event.getCalNumber(), false, settings);
Mono<String> eTime = getHumanReadableTime(event.getEndDateTime(), event.getCalNumber(), false, settings);
Mono<Boolean> img = Mono.justOrEmpty(event.getEventData()).filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
@@ -335,9 +216,9 @@ public class EventMessageFormatter {
}
spec.addField(Messages.getMessage("Embed.Event.Pre.StartDate", settings), startDate, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.StartTime", settings), startTime, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.TimeZone", settings), event.getTimezone(), false);
spec.addField(Messages.getMessage("Embed.Event.Pre.EndDate", settings), endDate, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.EndTime", settings), endTime, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.TimeZone", settings), event.getTimezone(), true);
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
if (event.getLocation().length() > 300) {
@@ -355,120 +236,48 @@ public class EventMessageFormatter {
}));
}
@Deprecated
public static Mono<Consumer<EmbedCreateSpec>> getPreEventEmbed(final PreEvent event,
final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<String> sDate = getHumanReadableDate(event.getStartDateTime(), false, settings);
final Mono<String> sTime = getHumanReadableTime(event.getStartDateTime(), false, settings);
final Mono<String> eDate = getHumanReadableDate(event.getEndDateTime(), false, settings);
final Mono<String> eTime = getHumanReadableTime(event.getEndDateTime(), false, settings);
final Mono<Boolean> img = Mono.justOrEmpty(event.getEventData()).filter(EventData::shouldBeSaved)
public static Mono<Consumer<EmbedCreateSpec>> getEventConfirmationEmbed(EventCreatorResponse ecr, int calNum,
GuildSettings settings) {
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
Mono<EventData> data = DatabaseManager.getEventData(settings.getGuildID(), ecr.getEvent().getId())
.defaultIfEmpty(new EventData())
.cache();
Mono<String> date = getHumanReadableDate(ecr.getEvent().getStart(), calNum, false, settings);
Mono<String> time = getHumanReadableTime(ecr.getEvent().getStart(), calNum, false, settings);
Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
return Mono.zip(guild, sDate, sTime, eDate, eTime, img)
.map(TupleUtils.function((g, startDate, startTime, endDate, endTime, hasImg) -> spec -> {
return Mono.zip(guild, data, date, time, img)
.map(TupleUtils.function((g, ed, d, t, hasImg) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite, g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
spec.setAuthor(g.getName(), GlobalConst.discalSite,
g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
spec.setAuthor("DisCal", GlobalConst.discalSite, GlobalConst.iconUrl);
if (hasImg)
spec.setImage(event.getEventData().getImageLink());
if (event.getEditing())
spec.addField(Messages.getMessage("Embed.Event.Pre.Id", settings), event.getEventId(), false);
spec.setTitle(Messages.getMessage("Embed.Event.Confirm.Title", settings));
if (event.getSummary() != null) {
String summary = event.getSummary();
if (summary.length() > 250) {
summary = summary.substring(0, 250);
summary = summary + " (continues on Google Calendar View)";
}
spec.addField(Messages.getMessage("Embed.Event.Pre.Summary", settings), summary, false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Pre.Summary", settings), "NOT SET", true);
}
if (event.getDescription() != null) {
String description = event.getDescription();
if (description.length() > 500) {
description = description.substring(0, 500);
description = description + " (continues on Google Calendar View)";
}
spec.addField(Messages.getMessage("Embed.Event.Pre.Description", settings), description, false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Pre.Description", settings), "NOT SET", true);
}
if (event.getRecur()) {
spec.addField(Messages.getMessage("Embed.Event.Pre.Recurrence", settings), event.getRecurrence().toHumanReadable(), false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Pre.Recurrence", settings), "N/a", true);
}
spec.addField(Messages.getMessage("Embed.Event.Pre.StartDate", settings), startDate, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.StartTime", settings), startTime, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.EndDate", settings), endDate, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.EndTime", settings), endTime, true);
spec.addField(Messages.getMessage("Embed.Event.Pre.TimeZone", settings), event.getTimezone(), true);
if (hasImg) spec.setImage(ed.getImageLink());
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
if (event.getLocation().length() > 300) {
final String location = event.getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.ID", settings), ecr.getEvent().getId(), false);
spec.addField(Messages.getMessage("Embed.Event.Condensed.Date", settings), d, true);
spec.addField(Messages.getMessage("Embed.Event.Condensed.Time", settings), t, true);
if (ecr.getEvent().getLocation() != null && !"".equalsIgnoreCase(ecr.getEvent().getLocation())) {
if (ecr.getEvent().getLocation().length() > 300) {
final String location = ecr.getEvent().getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, false);
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), event.getLocation(), false);
}
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), "N/a", true);
}
spec.setFooter(Messages.getMessage("Embed.Event.Pre.Key", settings), null);
spec.setColor(event.getColor().asColor());
}));
}
@Deprecated
public static Mono<Consumer<EmbedCreateSpec>> getEventConfirmationEmbed(final EventCreatorResponse ecr,
final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), ecr.getEvent().getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> date = getHumanReadableDate(ecr.getEvent().getStart(), false, settings);
final Mono<String> time = getHumanReadableTime(ecr.getEvent().getStart(), false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
return Mono.zip(guild, data, date, time, img)
.map(TupleUtils.function((g, ed, d, t, hasImg) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite,
g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
spec.setAuthor("DisCal", GlobalConst.discalSite, GlobalConst.iconUrl);
spec.setTitle(Messages.getMessage("Embed.Event.Confirm.Title", settings));
if (hasImg)
spec.setImage(ed.getImageLink());
spec.addField(Messages.getMessage("Embed.Event.Confirm.ID", settings),
ecr.getEvent().getId(), false);
spec.addField(Messages.getMessage("Embed.Event.Confirm.Date", settings),
d, false);
if (ecr.getEvent().getLocation() != null && !"".equalsIgnoreCase(ecr.getEvent().getLocation())) {
if (ecr.getEvent().getLocation().length() > 300) {
final String location = ecr.getEvent().getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, true);
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), ecr.getEvent().getLocation(), true);
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings),
ecr.getEvent().getLocation(), false);
}
}
spec.setFooter(Messages.getMessage("Embed.Event.Confirm.Footer", settings), null);
spec.setUrl(ecr.getEvent().getHtmlLink());
if (ecr.getEvent().getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(ecr.getEvent().getColorId()));
final EventColor ec = EventColor.Companion.fromId(Integer.parseInt(ecr.getEvent().getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
@@ -476,147 +285,8 @@ public class EventMessageFormatter {
}));
}
public static Mono<Consumer<EmbedCreateSpec>> getEventConfirmationEmbed(final EventCreatorResponse ecr,
final int calNum,
final GuildSettings settings) {
final Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
final Mono<EventData> data = DatabaseManager
.getEventData(settings.getGuildID(), ecr.getEvent().getId())
.defaultIfEmpty(new EventData()).cache();
final Mono<String> date = getHumanReadableDate(ecr.getEvent().getStart(), calNum, false, settings);
final Mono<String> time = getHumanReadableTime(ecr.getEvent().getStart(), calNum, false, settings);
final Mono<Boolean> img = data.filter(EventData::shouldBeSaved)
.flatMap(d -> ImageUtils.validate(d.getImageLink(), settings.getPatronGuild()))
.defaultIfEmpty(false);
return Mono.zip(guild, data, date, time, img)
.map(TupleUtils.function((g, ed, d, t, hasImg) -> spec -> {
if (settings.getBranded())
spec.setAuthor(g.getName(), GlobalConst.discalSite,
g.getIconUrl(Image.Format.PNG).orElse(GlobalConst.iconUrl));
else
spec.setAuthor("DisCal", GlobalConst.discalSite, GlobalConst.iconUrl);
spec.setTitle(Messages.getMessage("Embed.Event.Confirm.Title", settings));
if (hasImg) {
spec.setImage(ed.getImageLink());
}
spec.addField(Messages.getMessage("Embed.Event.Confirm.ID", settings),
ecr.getEvent().getId(), false);
spec.addField(Messages.getMessage("Embed.Event.Confirm.Date", settings),
d, false);
if (ecr.getEvent().getLocation() != null && !"".equalsIgnoreCase(ecr.getEvent().getLocation())) {
if (ecr.getEvent().getLocation().length() > 300) {
final String location = ecr.getEvent().getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, true);
} else {
spec.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), ecr.getEvent().getLocation(), true);
}
}
spec.setFooter(Messages.getMessage("Embed.Event.Confirm.Footer", settings), null);
spec.setUrl(ecr.getEvent().getHtmlLink());
if (ecr.getEvent().getColorId() != null) {
final EventColor ec = EventColor.Companion.fromId(Integer.valueOf(ecr.getEvent().getColorId()));
spec.setColor(ec.asColor());
} else {
spec.setColor(GlobalConst.discalColor);
}
}));
}
@Deprecated
public static Mono<String> getHumanReadableDate(@Nullable final EventDateTime eventDateTime,
final boolean preEvent, final GuildSettings settings) {
return Mono.justOrEmpty(eventDateTime).flatMap(dateTime -> {
if (!preEvent) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.flatMap(data -> CalendarWrapper.getCalendar(data))
.map(com.google.api.services.calendar.model.Calendar::getTimeZone);
} else {
return Mono.just("UTC");
}
}
).map(ZoneId::of)
.map(tz -> {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy/MM/dd");
if (eventDateTime.getDateTime() != null) {
final long dateTime = eventDateTime.getDateTime().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
} else {
final long dateTime = eventDateTime.getDate().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
}
}).defaultIfEmpty("NOT SET");
}
public static Mono<String> getHumanReadableDate(@Nullable final EventDateTime eventDateTime,
final int calNum, final boolean preEvent,
final GuildSettings settings) {
return Mono.justOrEmpty(eventDateTime).flatMap(dateTime -> {
if (!preEvent) {
return DatabaseManager.getCalendar(settings.getGuildID(), calNum)
.flatMap(data -> CalendarWrapper.getCalendar(data))
.map(com.google.api.services.calendar.model.Calendar::getTimeZone);
} else {
return Mono.just("UTC");
}
}
).map(ZoneId::of)
.map(tz -> {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy/MM/dd");
if (eventDateTime.getDateTime() != null) {
final long dateTime = eventDateTime.getDateTime().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
} else {
final long dateTime = eventDateTime.getDate().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
}
}).defaultIfEmpty("NOT SET");
}
@Deprecated
public static Mono<String> getHumanReadableTime(@Nullable final EventDateTime eventDateTime,
final boolean preEvent, final GuildSettings settings) {
return Mono.justOrEmpty(eventDateTime).flatMap(dateTime -> {
if (!preEvent) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.flatMap(CalendarWrapper::getCalendar)
.map(com.google.api.services.calendar.model.Calendar::getTimeZone);
} else {
return Mono.just("UTC");
}
}
).map(ZoneId::of)
.map(tz -> {
DateTimeFormatter format;
if (settings.getTwelveHour()) format = DateTimeFormatter.ofPattern("hh:mm:ss a");
else format = DateTimeFormatter.ofPattern("HH:mm:ss");
if (eventDateTime.getDateTime() != null) {
final long dateTime = eventDateTime.getDateTime().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
} else {
final long dateTime = eventDateTime.getDate().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
}
}).defaultIfEmpty("NOT SET");
}
public static Mono<String> getHumanReadableTime(@Nullable final EventDateTime eventDateTime,
final int calNum, final boolean preEvent,
final GuildSettings settings) {
public static Mono<String> getHumanReadableDate(@Nullable EventDateTime eventDateTime, int calNum,
boolean preEvent, GuildSettings settings) {
return Mono.justOrEmpty(eventDateTime).flatMap(dateTime -> {
if (!preEvent) {
return DatabaseManager.getCalendar(settings.getGuildID(), calNum)
@@ -626,22 +296,47 @@ public class EventMessageFormatter {
return Mono.just("UTC");
}
}
).map(ZoneId::of)
.map(tz -> {
DateTimeFormatter format;
if (settings.getTwelveHour()) format = DateTimeFormatter.ofPattern("hh:mm:ss a");
else format = DateTimeFormatter.ofPattern("HH:mm:ss");
).map(ZoneId::of).map(tz -> {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy/MM/dd")
.withZone(tz);
if (eventDateTime.getDateTime() != null) {
final long dateTime = eventDateTime.getDateTime().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
if (eventDateTime.getDateTime() != null) { //Date with time
return format.format(Instant.ofEpochMilli(eventDateTime.getDateTime().getValue()));
} else { //Date only
Instant date = Instant.ofEpochMilli(eventDateTime.getDate().getValue())
.plus(1, ChronoUnit.DAYS);
return format.format(ldt);
return format.format(date);
}
}).defaultIfEmpty("NOT SET");
}
public static Mono<String> getHumanReadableTime(@Nullable EventDateTime eventDateTime, int calNum,
boolean preEvent, GuildSettings settings) {
return Mono.justOrEmpty(eventDateTime).flatMap(dateTime -> {
if (!preEvent) {
return DatabaseManager.getCalendar(settings.getGuildID(), calNum)
.flatMap(CalendarWrapper::getCalendar)
.map(com.google.api.services.calendar.model.Calendar::getTimeZone);
} else {
final long dateTime = eventDateTime.getDate().getValue();
final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTime), tz);
return format.format(ldt);
return Mono.just("UTC");
}
}).defaultIfEmpty("NOT SET");
}
).map(ZoneId::of).map(tz -> {
DateTimeFormatter format;
if (settings.getTwelveHour()) format = DateTimeFormatter.ofPattern("hh:mm:ss a").withZone(tz);
else format = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(tz);
if (eventDateTime.getDateTime() != null) { //Date with time
return format.format(Instant.ofEpochMilli(eventDateTime.getDateTime().getValue()));
} else { //Just date
// I guess just return 0 essentially?
Instant date = Instant.ofEpochMilli(eventDateTime.getDate().getValue())
.plus(1, ChronoUnit.DAYS);
//Go to beginning of day
return format.format(date.atZone(tz).truncatedTo(ChronoUnit.DAYS).toLocalDate().atStartOfDay());
}
}).defaultIfEmpty("NOT SET");
}
}
@@ -6,7 +6,6 @@ import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.command.CommandInfo;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.PermissionChecker;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
@@ -71,64 +70,64 @@ public class AddCalendarCommand implements Command {
*/
@Override
public Mono<Void> issueCommand(final String[] args, final MessageCreateEvent event, final GuildSettings settings) {
return Mono.just(settings)
.filter(s -> s.getDevGuild() || s.getPatronGuild())
.flatMap(s -> PermissionChecker.hasManageServerRole(event)
.filter(identity -> identity)
.flatMap(ignore -> {
if (args.length == 0) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.hasElement()
.flatMap(hasCal -> {
if (hasCal) {
return Messages.sendMessage(
Messages.getMessage("Creator.Calendar.HasCalendar", settings), event);
} else {
return GoogleExternalAuth.getAuth().requestCode(event, settings)
.then(Messages.sendMessage(
Messages.getMessage("AddCalendar.Start", settings), event));
}
});
} else if (args.length == 1) {
return DatabaseManager.getMainCalendar(settings.getGuildID()).flatMap(data -> {
if ("primary".equalsIgnoreCase(data.getCalendarAddress())) {
return Messages.sendMessage(Messages.getMessage("Creator.Calendar.HasCalendar", settings), event);
} else if ("N/a".equalsIgnoreCase(data.getEncryptedAccessToken())
&& "N/a".equalsIgnoreCase(data.getEncryptedRefreshToken())) {
return Messages.sendMessage(Messages.getMessage("AddCalendar.Select.NotAuth", settings), event);
} else {
return CalendarWrapper.getUsersExternalCalendars(data)
.flatMapMany(Flux::fromIterable)
.any(c -> !c.isDeleted() && c.getId().equals(args[0]))
.flatMap(valid -> {
if (valid) {
final CalendarData newData = new CalendarData(
data.getGuildId(), 1, args[0], args[0], true, 0,
data.getPrivateKey(), data.getEncryptedAccessToken(),
data.getEncryptedRefreshToken());
if (!(settings.getDevGuild() || settings.getPatronGuild())) {
return Messages.sendMessage(Messages.getMessage("Notification.Patron", settings), event).then();
}
//combine db calls and message send to be executed together async
final Mono<Boolean> calInsert = DatabaseManager.updateCalendar(newData);
final Mono<Message> sendMsg = Messages.sendMessage(
Messages.getMessage("AddCalendar.Select.Success", settings), event);
return PermissionChecker.hasManageServerRole(event).flatMap(hasManageRole -> {
if (!hasManageRole) {
return Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings), event);
}
return Mono.when(calInsert, sendMsg)
.thenReturn(GlobalConst.NOT_EMPTY);
} else {
return Messages.sendMessage(Messages
.getMessage("AddCalendar.Select.Failure.Invalid", settings), event);
}
});
}
});
} else {
//Invalid argument count...
return Messages.sendMessage(Messages.getMessage("AddCalendar.Specify", settings), event);
}
})
.switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings), event))
)
.switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Patron", settings), event))
.then();
if (args.length == 0) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.hasElement()
.flatMap(hasCal -> {
if (hasCal) {
return Messages.sendMessage(
Messages.getMessage("Creator.Calendar.HasCalendar", settings), event);
} else {
return GoogleExternalAuth.getAuth().requestCode(event, settings)
.then(Messages.sendMessage(
Messages.getMessage("AddCalendar.Start", settings), event));
}
});
} else if (args.length == 1) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.flatMap(data -> {
if (!"primary".equalsIgnoreCase(data.getCalendarAddress())) {
return Messages.sendMessage(Messages.getMessage("Creator.Calendar.HasCalendar", settings), event);
} else if ("N/a".equalsIgnoreCase(data.getEncryptedAccessToken())
&& "N/a".equalsIgnoreCase(data.getEncryptedRefreshToken())) {
return Messages.sendMessage(Messages.getMessage("AddCalendar.Select.NotAuth", settings), event);
} else {
return CalendarWrapper.getUsersExternalCalendars(data)
.flatMapMany(Flux::fromIterable)
.any(c -> !c.isDeleted() && c.getId().equals(args[0]))
.flatMap(valid -> {
if (valid) {
final CalendarData newData = new CalendarData(
data.getGuildId(), 1, args[0], args[0], true, 0,
data.getPrivateKey(), data.getEncryptedAccessToken(),
data.getEncryptedRefreshToken());
//combine db calls and message send to be executed together async
final Mono<Boolean> calInsert = DatabaseManager.updateCalendar(newData);
final Mono<Message> sendMsg = Messages.sendMessage(
Messages.getMessage("AddCalendar.Select.Success", settings), event);
return Mono.when(calInsert, sendMsg);
} else {
return Messages.sendMessage(Messages
.getMessage("AddCalendar.Select.Failure.Invalid", settings), event);
}
});
}
});
} else {
//Invalid argument count...
return Messages.sendMessage(Messages.getMessage("AddCalendar.Specify", settings), event);
}
}).then();
}
}
@@ -233,7 +233,7 @@ public class EventCommand implements Command {
final Mono<Void> deleteCreatorMessage = Messages.deleteMessage(pre.getCreatorMessage());
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages.getMessage("Creator.Event.AlreadyInit", settings), em, event))
.doOnNext(pre::setCreatorMessage);
} else if (!"primary".equalsIgnoreCase(calendarData.getCalendarAddress())) {
@@ -257,7 +257,7 @@ public class EventCommand implements Command {
final Mono<Void> deleteCreatorMessage = Messages.deleteMessage(pre.getCreatorMessage());
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages.getMessage("Creator.Event.AlreadyInit", settings), em, event))
.doOnNext(pre::setCreatorMessage);
} else if (!"primary".equalsIgnoreCase(calendarData.getCalendarAddress())) {
@@ -291,7 +291,7 @@ public class EventCommand implements Command {
final Mono<Void> deleteCreatorMessage = Messages.deleteMessage(pre.getCreatorMessage());
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages.getMessage("Creator.Event.AlreadyInit", settings), em, event))
.doOnNext(pre::setCreatorMessage);
} else if ("primary".equalsIgnoreCase(calendarData.getCalendarAddress())) {
@@ -345,7 +345,7 @@ public class EventCommand implements Command {
final Mono<Void> deleteCreatorMessage = Messages.deleteMessage(pre.getCreatorMessage());
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages
.getMessage("Creator.Event.Delete.Failure.Creator", settings), em, event))
.doOnNext(pre::setCreatorMessage);
@@ -379,7 +379,7 @@ public class EventCommand implements Command {
final Mono<Void> deleteCreatorMessage = Messages.deleteMessage(pre.getCreatorMessage());
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages.getMessage("Event.View.Creator.Confirm", settings), em, event))
.doOnNext(pre::setCreatorMessage);
} else if ("primary".equalsIgnoreCase(calendarData.getCalendarAddress())) {
@@ -421,7 +421,7 @@ public class EventCommand implements Command {
.flatMap(em -> Messages.sendMessage(msg, em, event));
} else {
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(),
.then(EventMessageFormatter.getPreEventEmbed(pre,
settings))
.flatMap(em -> Messages.sendMessage(
Messages.getMessage("Creator.Event.Confirm.Failure", settings), em, event))
@@ -431,7 +431,7 @@ public class EventCommand implements Command {
} else {
//Some values are unset, tell user.
return Mono.when(deleteUserMessage, deleteCreatorMessage)
.then(EventMessageFormatter.getPreEventEmbed(pre, calendarData.getCalendarNumber(), settings))
.then(EventMessageFormatter.getPreEventEmbed(pre, settings))
.flatMap(em -> Messages.sendMessage(Messages.getMessage("Creator.Event.NoRequired", settings), em, event))
.doOnNext(pre::setCreatorMessage);
}
@@ -1,5 +1,9 @@
package org.dreamexposure.discal.core.database;
import discord4j.common.util.Snowflake;
import io.r2dbc.pool.ConnectionPool;
import io.r2dbc.pool.ConnectionPoolConfiguration;
import io.r2dbc.spi.*;
import org.dreamexposure.discal.core.enums.announcement.AnnouncementModifier;
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType;
import org.dreamexposure.discal.core.enums.event.EventColor;
@@ -13,6 +17,8 @@ import org.dreamexposure.discal.core.object.event.EventData;
import org.dreamexposure.discal.core.object.event.RsvpData;
import org.dreamexposure.discal.core.object.web.UserAPIAccount;
import org.dreamexposure.novautils.database.DatabaseSettings;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;
import java.util.ArrayList;
import java.util.List;
@@ -21,26 +27,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import discord4j.common.util.Snowflake;
import io.r2dbc.pool.ConnectionPool;
import io.r2dbc.pool.ConnectionPoolConfiguration;
import io.r2dbc.spi.Connection;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryOptions;
import io.r2dbc.spi.Result;
import io.r2dbc.spi.ValidationDepth;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;
import static io.r2dbc.spi.ConnectionFactoryOptions.DATABASE;
import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER;
import static io.r2dbc.spi.ConnectionFactoryOptions.HOST;
import static io.r2dbc.spi.ConnectionFactoryOptions.PASSWORD;
import static io.r2dbc.spi.ConnectionFactoryOptions.PORT;
import static io.r2dbc.spi.ConnectionFactoryOptions.PROTOCOL;
import static io.r2dbc.spi.ConnectionFactoryOptions.SSL;
import static io.r2dbc.spi.ConnectionFactoryOptions.USER;
import static io.r2dbc.spi.ConnectionFactoryOptions.*;
/**
* Created by Nova Fox on 11/10/17.
@@ -241,7 +228,7 @@ public class DatabaseManager {
final String update = "UPDATE " + table
+ " SET CALENDAR_NUMBER = ?, CALENDAR_ID = ?,"
+ " CALENDAR_ADDRESS = ?, EXTERNAL = ?, CREDENTIAL_ID = ?,"
+ " PRIVATE_KEY = ?, ACCESS_TOKEN = ?, REFRESH TOKEN = ?"
+ " PRIVATE_KEY = ?, ACCESS_TOKEN = ?, REFRESH_TOKEN = ?"
+ " WHERE GUILD_ID = ?";
return connect(master, c -> Mono.from(c.createStatement(update)
@@ -261,7 +248,8 @@ public class DatabaseManager {
} else {
final String insertCommand = "INSERT INTO " + table
+ "(GUILD_ID, CALENDAR_NUMBER, CALENDAR_ID, " +
"CALENDAR_ADDRESS, EXTERNAL, CREDENTIAL_ID)" + " VALUES (?, ?, ?, ?, ?, ?)";
"CALENDAR_ADDRESS, EXTERNAL, CREDENTIAL_ID, " +
"PRIVATE_KEY, ACCESS_TOKEN, REFRESH_TOKEN)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
return connect(master, c -> Mono.from(c.createStatement(insertCommand)
.bind(0, calData.getGuildId().asString())
@@ -270,6 +258,9 @@ public class DatabaseManager {
.bind(3, calData.getCalendarAddress())
.bind(4, calData.getExternal())
.bind(5, calData.getCredentialId())
.bind(6, calData.getPrivateKey())
.bind(7, calData.getEncryptedAccessToken())
.bind(8, calData.getEncryptedRefreshToken())
.execute())
).flatMap(res -> Mono.from(res.getRowsUpdated()))
.hasElement()
@@ -1061,12 +1052,11 @@ public class DatabaseManager {
return connect(master, c -> {
final String announcementTableName = String.format("%sannouncements", settings.getPrefix());
final String query = "DELETE FROM " + announcementTableName + " WHERE EVENT_ID = ? AND " +
"GUILD_ID = ? AND ANNOUNCEMENT_TYPE = ?";
"GUILD_ID = ?";
return Mono.from(c.createStatement(query)
.bind(0, eventId)
.bind(1, guildId.asString())
.bind(2, AnnouncementType.SPECIFIC.name())
.execute());
}).flatMapMany(Result::getRowsUpdated)
.then(Mono.just(true))
@@ -1,15 +1,13 @@
package org.dreamexposure.discal.core.utils;
import com.google.api.services.calendar.model.Event;
import discord4j.common.util.Snowflake;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.enums.event.EventColor;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.event.EventData;
import org.dreamexposure.discal.core.object.event.PreEvent;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Mono;
/**
@@ -18,27 +16,20 @@ import reactor.core.publisher.Mono;
* For Project: DisCal-Discord-Bot
*/
public class EventUtils {
@Deprecated
public static Mono<Boolean> deleteEvent(final GuildSettings settings, final String eventId) {
return DatabaseManager.getMainCalendar(settings.getGuildID())
.flatMap(data ->
EventWrapper.deleteEvent(data, eventId)
.then(Mono.when(
DatabaseManager.deleteAnnouncementsForEvent(settings.getGuildID(), eventId),
DatabaseManager.deleteEventData(eventId))
).thenReturn(true)
).defaultIfEmpty(false);
}
public static Mono<Boolean> deleteEvent(final GuildSettings settings, final int calNumber, final String eventId) {
return DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
.flatMap(data ->
EventWrapper.deleteEvent(data, eventId)
.then(Mono.when(
DatabaseManager.deleteAnnouncementsForEvent(settings.getGuildID(), eventId),
DatabaseManager.deleteEventData(eventId))
).thenReturn(true)
.flatMap(success -> {
if (success) {
return Mono.when(
DatabaseManager.deleteAnnouncementsForEvent(settings.getGuildID(), eventId),
DatabaseManager.deleteEventData(eventId)
).thenReturn(true);
} else {
return Mono.just(false);
}
})
).defaultIfEmpty(false);
}
@@ -59,9 +50,9 @@ public class EventUtils {
).switchIfEmpty(Mono.just(false));
}
public static Mono<PreEvent> copyEvent(final Snowflake guildId, final Event event) {
public static Mono<PreEvent> copyEvent(final Snowflake guildId, final Event event, int calNum) {
return DatabaseManager.getEventData(guildId, event.getId())
.flatMap(data -> Mono.just(new PreEvent(guildId))
.flatMap(data -> Mono.just(new PreEvent(guildId, calNum))
.doOnNext(p -> p.setEventData(data))
.doOnNext(p -> p.setSummary(event.getSummary()))
.doOnNext(p -> p.setDescription(event.getDescription()))
@@ -72,7 +63,7 @@ public class EventUtils {
else
p.setColor(EventColor.NONE);
})
).switchIfEmpty(Mono.just(new PreEvent(guildId))
).switchIfEmpty(Mono.just(new PreEvent(guildId, calNum))
.doOnNext(p -> p.setEventData(new EventData()))
.doOnNext(p -> p.setSummary(event.getSummary()))
.doOnNext(p -> p.setDescription(event.getDescription()))
@@ -5,54 +5,85 @@ import com.google.api.services.calendar.model.Event;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.enums.event.EventColor;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.event.EventData;
import org.dreamexposure.discal.core.object.event.Recurrence;
import org.json.JSONObject;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import reactor.core.publisher.Mono;
public class JsonUtils {
public static String getJsonResponseMessage(final String msg) {
return "{\"message\": \"" + msg + "\"}";
}
//TODO: rewrite to non-blocking
public static JSONObject convertEventToJson(final Event event, final GuildSettings settings) {
final JSONObject json = new JSONObject();
public static Mono<JSONObject> convertEventToJson(Event event, ZoneId tz, GuildSettings settings) {
return Mono.just(new JSONObject()).flatMap(json -> {
json.put("event_id", event.getId());
if (event.getStart().getDateTime() != null)
json.put("epoch_start", event.getStart().getDateTime().getValue());
else {
Long start = Instant.ofEpochMilli(event.getStart().getDate().getValue())
.plus(1, ChronoUnit.DAYS)
.atZone(tz)
.truncatedTo(ChronoUnit.DAYS)
.toLocalDate()
.atStartOfDay()
.atZone(tz)
.toInstant()
.toEpochMilli();
json.put("event_id", event.getId());
json.put("epoch_start", event.getStart().getDateTime().getValue());
json.put("epoch_end", event.getEnd().getDateTime().getValue());
json.put("epoch_start", start);
}
//These 3 are optional values
if (event.getSummary() != null)
json.put("summary", event.getSummary());
if (event.getDescription() != null)
json.put("description", event.getDescription());
if (event.getLocation() != null)
json.put("location", event.getLocation());
if (event.getEnd().getDateTime() != null)
json.put("epoch_end", event.getEnd().getDateTime().getValue());
else {
Long end = Instant.ofEpochMilli(event.getEnd().getDate().getValue())
.plus(1, ChronoUnit.DAYS)
.atZone(tz)
.truncatedTo(ChronoUnit.DAYS)
.toLocalDate()
.atStartOfDay()
.atZone(tz)
.toInstant()
.toEpochMilli();
json.put("is_parent", !(event.getId().contains("_")));
json.put("epoch_end", end);
}
json.put("color", EventColor.Companion.fromNameOrHexOrId(event.getColorId()).name());
//These 3 are optional values
if (event.getSummary() != null)
json.put("summary", event.getSummary());
if (event.getDescription() != null)
json.put("description", event.getDescription());
if (event.getLocation() != null)
json.put("location", event.getLocation());
if (event.getRecurrence() != null && !event.getRecurrence().isEmpty()) {
json.put("recur", true);
final Recurrence r = Recurrence.Companion.fromRRule(event.getRecurrence().get(0));
json.put("is_parent", !(event.getId().contains("_")));
final JSONObject recurrence = new JSONObject();
recurrence.put("frequency", r.getFrequency().name());
recurrence.put("count", r.getCount());
recurrence.put("interval", r.getInterval());
if (event.getColorId() != null)
json.put("color", EventColor.Companion.fromNameOrHexOrId(event.getColorId()).name());
else
json.put("color", EventColor.NONE.name());
json.put("recurrence", recurrence); //Optional
} else
json.put("recur", false);
if (event.getRecurrence() != null && !event.getRecurrence().isEmpty()) {
json.put("recur", true);
final Recurrence r = Recurrence.Companion.fromRRule(event.getRecurrence().get(0));
final EventData ed = DatabaseManager.getEventData(settings.getGuildID(), event.getId()).block();
json.put("recurrence", JsonUtil.INSTANCE.encodeToJSON(Recurrence.class, r)); //Optional
json.put("rrule", r.toRRule());
} else
json.put("recur", false);
//Event image is also optional
if (ed != null && ed.getImageLink() != null)
json.put("image", ed.getImageLink());
return json;
return DatabaseManager.getEventData(settings.getGuildID(), event.getId())
.filter(ed -> !ed.getImageLink().isEmpty())
.doOnNext(ed -> json.put("image", ed.getImageLink()))
.thenReturn(json)
.defaultIfEmpty(json);
});
}
}
@@ -1,5 +1,6 @@
package org.dreamexposure.discal.core.utils;
import com.google.api.client.util.DateTime;
import com.google.api.services.calendar.model.Event;
import org.dreamexposure.discal.core.database.DatabaseManager;
@@ -10,6 +11,9 @@ import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.TimeZone;
@@ -67,7 +71,12 @@ public class TimeUtils {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss");
sdf.setTimeZone(timezone);
final Date endDate = sdf.parse(endRaw);
final Date startDate = new Date(event.getStartDateTime().getDateTime().getValue());
final Date startDate;
if (event.getStartDateTime().getDateTime() != null)
startDate = new Date(event.getStartDateTime().getDateTime().getValue());
else
startDate = new Date(event.getStartDateTime().getDate().getValue());
return endDate.before(startDate);
} catch (final ParseException e) {
@@ -83,7 +92,13 @@ public class TimeUtils {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss");
sdf.setTimeZone(timezone);
final Date startDate = sdf.parse(startRaw);
final Date endDate = new Date(event.getEndDateTime().getDateTime().getValue());
Date endDate;
if (event.getEndDateTime().getDateTime() != null)
endDate = new Date(event.getEndDateTime().getDateTime().getValue());
else
endDate = new Date(event.getEndDateTime().getDate().getValue());
return startDate.after(endDate);
} catch (final ParseException e) {
@@ -92,4 +107,17 @@ public class TimeUtils {
}
return false;
}
public static DateTime doTimeShiftBullshit(DateTime original, ZoneId tz) {
return new DateTime(Instant.ofEpochMilli(original.getValue())
.plus(1, ChronoUnit.DAYS)
.atZone(tz)
.truncatedTo(ChronoUnit.DAYS)
.toLocalDate()
.atStartOfDay()
.atZone(tz)
.toInstant()
.toEpochMilli()
);
}
}
@@ -1,19 +1,18 @@
package org.dreamexposure.discal.core.wrapper.google;
import com.google.api.services.calendar.model.AclRule;
import org.dreamexposure.discal.core.calendar.CalendarAuth;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
public class AclRuleWrapper {
public static Mono<AclRule> insertRule(final AclRule rule, final CalendarData data) {
public static Mono<AclRule> insertRule(AclRule rule, CalendarData data) {
return CalendarAuth.getCalendarService(data)
.flatMap(service -> Mono.fromCallable(() ->
service.acl()
.insert(data.getCalendarId(), rule)
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic()))
.onErrorResume(e -> Mono.empty());
@@ -2,51 +2,53 @@ package org.dreamexposure.discal.core.wrapper.google;
import com.google.api.services.calendar.model.Calendar;
import com.google.api.services.calendar.model.CalendarListEntry;
import discord4j.common.util.Snowflake;
import org.dreamexposure.discal.core.calendar.CalendarAuth;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.IOException;
import java.util.List;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
public class CalendarWrapper {
public static Mono<Calendar> createCalendar(final Calendar calendar, final int credId) {
public static Mono<Calendar> createCalendar(Calendar calendar, int credId, Snowflake guildId) {
return CalendarAuth.getCalendarService(credId)
.flatMap(service -> Mono.fromCallable(() ->
service.calendars()
.insert(calendar)
.setQuotaUser(guildId.asString())
.execute()
).subscribeOn(Schedulers.boundedElastic()))
.onErrorResume(e -> Mono.empty());
}
public static Mono<Calendar> updateCalendar(final Calendar calendar, final CalendarData calData) {
public static Mono<Calendar> updateCalendar(Calendar calendar, CalendarData calData) {
return CalendarAuth.getCalendarService(calData)
.flatMap(service -> Mono.fromCallable(() ->
service.calendars()
.update(calendar.getId(), calendar)
.setQuotaUser(calData.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic()))
.onErrorResume(e -> Mono.empty());
}
public static Mono<Calendar> getCalendar(final CalendarData data) {
public static Mono<Calendar> getCalendar(CalendarData data) {
return CalendarAuth.getCalendarService(data)
.flatMap(service -> Mono.fromCallable(() ->
service.calendars()
.get(data.getCalendarAddress())
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic()))
.doOnError(e -> LogFeed.log(LogObject.forException("Get Cal Failure", e, CalendarWrapper.class)))
.onErrorResume(e -> Mono.empty());
}
public static Mono<Void> deleteCalendar(final CalendarData data) {
public static Mono<Void> deleteCalendar(CalendarData data) {
return Mono.just(data)
.filter(cd -> !cd.getExternal())
.filter(cd -> !"primary".equalsIgnoreCase(cd.getCalendarAddress()))
@@ -54,6 +56,7 @@ public class CalendarWrapper {
CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() -> service.calendars()
.delete(cd.getCalendarAddress())
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic())
)
@@ -68,6 +71,7 @@ public class CalendarWrapper {
service.calendarList()
.list()
.setMinAccessRole("writer")
.setQuotaUser(calData.getGuildId().asString())
.execute()
.getItems()
).subscribeOn(Schedulers.boundedElastic()))
@@ -1,30 +1,31 @@
package org.dreamexposure.discal.core.wrapper.google;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpStatusCodes;
import com.google.api.client.util.DateTime;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.Event;
import org.dreamexposure.discal.core.calendar.CalendarAuth;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.utils.GlobalConst;
import java.util.List;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.util.List;
@SuppressWarnings("DuplicatedCode")
public class EventWrapper {
public static Mono<Event> createEvent(final CalendarData data, final Event event) {
public static Mono<Event> createEvent(CalendarData data, Event event) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events()
.insert(data.getCalendarId(), event)
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(GoogleJsonResponseException.class, e -> {
@@ -52,11 +53,12 @@ public class EventWrapper {
).onErrorResume(e -> Mono.empty());
}
public static Mono<Event> updateEvent(final CalendarData data, final Event event) {
public static Mono<Event> updateEvent(CalendarData data, Event event) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events()
.update(data.getCalendarId(), event.getId(), event)
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(GoogleJsonResponseException.class, e -> {
@@ -83,18 +85,18 @@ public class EventWrapper {
).onErrorResume(e -> Mono.empty());
}
public static Mono<Event> getEvent(final CalendarData data, final String id) {
public static Mono<Event> getEvent(CalendarData data, String id) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events()
.get(data.getCalendarAddress(), id)
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(e -> Mono.empty()); //Can ignore this, the event just doesn't exist.
}
public static Mono<List<Event>> getEvents(final CalendarData data, final int amount,
final long start) {
public static Mono<List<Event>> getEvents(CalendarData data, int amount, long start) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events().list(data.getCalendarId())
@@ -103,13 +105,13 @@ public class EventWrapper {
.setOrderBy("startTime")
.setSingleEvents(true)
.setShowDeleted(false)
.setQuotaUser(data.getGuildId().asString())
.execute().getItems()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(e -> Mono.empty());
}
public static Mono<List<Event>> getEvents(final CalendarData data, final Calendar service, final int amount,
final long start) {
public static Mono<List<Event>> getEvents(CalendarData data, Calendar service, int amount, long start) {
return Mono.fromCallable(() ->
service.events().list(data.getCalendarId())
.setMaxResults(amount)
@@ -117,6 +119,7 @@ public class EventWrapper {
.setOrderBy("startTime")
.setSingleEvents(true)
.setShowDeleted(false)
.setQuotaUser(data.getGuildId().asString())
.execute().getItems()
).subscribeOn(Schedulers.boundedElastic())
.onErrorResume(e -> Mono.empty());
@@ -132,13 +135,13 @@ public class EventWrapper {
.setOrderBy("startTime")
.setSingleEvents(true)
.setShowDeleted(false)
.setQuotaUser(data.getGuildId().asString())
.execute().getItems()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(e -> Mono.empty());
}
public static Mono<List<Event>> getEvents(final CalendarData data, final long start,
final long end) {
public static Mono<List<Event>> getEvents(CalendarData data, long start, long end) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events().list(data.getCalendarId())
@@ -147,17 +150,29 @@ public class EventWrapper {
.setOrderBy("startTime")
.setSingleEvents(true)
.setShowDeleted(false)
.setQuotaUser(data.getGuildId().asString())
.execute().getItems()
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(e -> Mono.empty());
}
public static Mono<Void> deleteEvent(final CalendarData data, final String id) {
public static Mono<Boolean> deleteEvent(CalendarData data, String id) {
return CalendarAuth.getCalendarService(data).flatMap(service ->
Mono.fromCallable(() ->
service.events()
Mono.fromCallable(() -> {
HttpResponse response = service.events()
.delete(data.getCalendarAddress(), id)
.execute()
.setQuotaUser(data.getGuildId().asString())
.executeUnparsed();
//Log error code if one happened
if (response.getStatusCode() != HttpStatusCodes.STATUS_CODE_OK) {
LogFeed.log(LogObject.forDebug(
"Event Delete Error | " + response.getStatusCode() + " | " + response.getStatusMessage()
));
}
return response.getStatusCode() == HttpStatusCodes.STATUS_CODE_OK;
}
).subscribeOn(Schedulers.boundedElastic())
).onErrorResume(GoogleJsonResponseException.class, e -> {
if ("requiredAccessLevel".equalsIgnoreCase(e.getDetails().getErrors().get(0).getReason())) {
@@ -169,34 +184,37 @@ public class EventWrapper {
return DatabaseManager.getCalendar(data.getGuildId(), data.getCalendarNumber())
.flatMap(cd -> deleteEvent(cd, id));
} else {
return Mono.empty();
return Mono.just(false);
}
});
} else {
//This is some other issue I am not currently aware of, logging for handling
LogFeed.log(LogObject.forException("GJRE: Event delete Failure", e, EventWrapper.class));
return Mono.just(false);
}
return Mono.empty();
}).doOnError(e -> LogFeed.log(LogObject.forException("Event Delete Failure", e, EventWrapper.class))
).onErrorResume(e -> Mono.empty());
).onErrorReturn(false);
}
private static Mono<Boolean> correctAssignedCredentialId(CalendarData data) {
return Flux.range(0, CalendarAuth.credentialsCount()).flatMap(i ->
CalendarAuth.getCalendarService(i).flatMap(service -> Mono.fromCallable(() ->
service.calendarList().get(data.getCalendarId()).execute()
service.calendarList()
.get(data.getCalendarId())
.setQuotaUser(data.getGuildId().asString())
.execute()
).subscribeOn(Schedulers.boundedElastic())
.onErrorResume(GoogleJsonResponseException.class, e -> {
if (e.getStatusCode() == GlobalConst.STATUS_NOT_FOUND ||
"requiredAccessLevel".equalsIgnoreCase(e.getDetails().getErrors().get(0).getReason())) {
return Mono.empty();
}
.onErrorResume(GoogleJsonResponseException.class, e -> {
if (e.getStatusCode() == GlobalConst.STATUS_NOT_FOUND ||
"requiredAccessLevel".equalsIgnoreCase(e.getDetails().getErrors().get(0).getReason())) {
return Mono.empty();
}
return Mono.empty();
})
return Mono.empty();
})
).map(cal -> "owner".equalsIgnoreCase(cal.getAccessRole()) ? i : -1)
).filter(i -> i > -1)
).filter(i -> i > -1)
.flatMap(correctCredential -> {
//Ayyyyy we found the correct one!! Lets go ahead and save that and bump this back to the calling method
CalendarData corrected = new CalendarData(
@@ -13,7 +13,7 @@ data class CalendarData(
@SerialName("guild_id")
val guildId: Snowflake = Snowflake.of(0),
@SerialName("calendar_number")
val calendarNumber: Int = 0,
val calendarNumber: Int = 1,
@SerialName("calendar_id")
val calendarId: String = "primary",
@SerialName("calendar_address")
@@ -1,20 +1,22 @@
package org.dreamexposure.discal.core.`object`.event
import com.google.api.services.calendar.model.Calendar
import com.google.api.services.calendar.model.Event
import com.google.api.services.calendar.model.EventDateTime
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.Message
import org.dreamexposure.discal.core.`object`.calendar.CalendarData
import org.dreamexposure.discal.core.database.DatabaseManager
import org.dreamexposure.discal.core.enums.event.EventColor
import org.dreamexposure.discal.core.logger.LogFeed
import org.dreamexposure.discal.core.logger.`object`.LogObject
import org.dreamexposure.discal.core.utils.TimeUtils
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper
import reactor.core.publisher.Mono
import java.time.ZoneId
@Suppress("DataClassPrivateConstructor")
data class PreEvent private constructor(
val guildId: Snowflake,
val eventId: String,
val calNumber: Int,
) {
//fields
var summary: String? = null
@@ -39,10 +41,15 @@ data class PreEvent private constructor(
var lastEdit = System.currentTimeMillis()
//Constructors
constructor(guildId: Snowflake) : this(guildId, "N/a")
constructor(guildId: Snowflake, calNumber: Int) : this(guildId, "N/a", calNumber)
constructor(guildId: Snowflake, e: Event) : this(guildId, e.id) {
this.color = EventColor.fromNameOrHexOrId(e.colorId)
private constructor(guildId: Snowflake, e: Event, calData: CalendarData) : this(guildId, e.id, calData
.calendarNumber) {
try {
this.color = EventColor.fromNameOrHexOrId(e.colorId)
} catch (ignore: NullPointerException) {
this.color = EventColor.NONE
}
if (e.recurrence != null && e.recurrence.isNotEmpty()) {
this.recur = true
@@ -53,25 +60,44 @@ data class PreEvent private constructor(
if (e.description != null) this.description = e.description
if (e.location != null) this.location = e.location
this.startDateTime = e.start
this.endDateTime = e.end
if (e.start.date == null)
this.startDateTime = e.start
//Here is where I need to fix the display times
//TODO: Get rid of the blocking
//TODO: Support multi-cal
val data = DatabaseManager.getMainCalendar(this.guildId).block()!!
if (e.end.date == null)
this.endDateTime = e.end
var cal: Calendar? = null
try {
cal = CalendarWrapper.getCalendar(data).block()
} catch (ex: Exception) {
LogFeed.log(LogObject.forException("Failed to get proper date/time for event!", ex, this.javaClass))
if (e.start.timeZone != null) this.timezone = e.start.timeZone
}
companion object {
@JvmStatic
fun copy(guildId: Snowflake, e: Event, calData: CalendarData): Mono<PreEvent> {
return CalendarWrapper.getCalendar(calData)
.map { ZoneId.of(it.timeZone) }
.map { tz ->
val event = PreEvent(guildId, e, calData)
event.timezone = tz.id
if (e.start.date != null) {
event.startDateTime = EventDateTime()
event.startDateTime!!.dateTime = TimeUtils.doTimeShiftBullshit(e.start.date, tz)
}
if (e.end.date != null) {
event.endDateTime = EventDateTime()
event.endDateTime!!.dateTime = TimeUtils.doTimeShiftBullshit(e.end.date, tz)
}
return@map event
}
.flatMap { event ->
DatabaseManager.getEventData(guildId, event.eventId)
.switchIfEmpty(Mono.just(EventData(guildId, event.eventId)))
.doOnNext {
event.eventData = it
}
.thenReturn(event)
}
}
if (cal != null) this.timezone = cal.timeZone
else this.timezone = "ERROR/Unknown"
this.eventData = DatabaseManager.getEventData(this.guildId, e.id).block()!!
}
//Functions
+31 -22
View File
@@ -10,40 +10,49 @@ let browserSync = require('browser-sync').create();
// Set the banner content
let banner = ['/*!\n',
' */\n',
'\n'
' */\n',
'\n'
].join('');
// Copy third party libraries from /node_modules into /vendor
gulp.task('vendor', gulp.series(function(done) {
// Bootstrap
gulp.src([
gulp.task('vendor', gulp.series(function (done) {
// Bootstrap
gulp.src([
'./node_modules/bootstrap/dist/**/*',
'!./node_modules/bootstrap/dist/css/bootstrap-grid*',
'!./node_modules/bootstrap/dist/css/bootstrap-reboot*'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/bootstrap'));
// jQuery
// jQuery
gulp.src([
'./node_modules/jquery/dist/*',
'!./node_modules/jquery/dist/core.js'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/jquery'));
// jQuery Easing
// jQuery Easing
gulp.src([
'./node_modules/jquery.easing/*.js'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/jquery-easing'));
//ChartJS
// FullCalendar
/*
gulp.src([
'./node_modules/fullcalendar/main.min.js',
'./node_modules/fullcalendar/main.min.css'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/fullcalendar'))
*/
// ChartJS
gulp.src([
'./node_modules/chart.js/dist/*.js'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/chart.js'));
//DataTables
// DataTables
gulp.src([
'./node_modules/datatables.net/js/*.js',
'./node_modules/datatables.net-bs4/js/*.js',
@@ -51,13 +60,13 @@ gulp.task('vendor', gulp.series(function(done) {
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/datatables'));
// Font Awesome 5
// Font Awesome 5
gulp.src([
'./node_modules/@fortawesome/**/*'
])
.pipe(gulp.dest('./web/src/main/html/static/vendor'));
// Simple Line Icons
// Simple Line Icons
gulp.src([
'./node_modules/simple-line-icons/fonts/**'
])
@@ -68,11 +77,11 @@ gulp.task('vendor', gulp.series(function(done) {
])
.pipe(gulp.dest('./web/src/main/html/static/vendor/simple-line-icons/css'));
done();
done();
}));
gulp.task('clean:all', gulp.series(function () {
return del([
return del([
"./web/build",
"./web/src/main/html/static/assets/js/**",
"./web/src/main/html/static/assets/css/**",
@@ -81,14 +90,14 @@ gulp.task('clean:all', gulp.series(function () {
}));
gulp.task('clean:build', gulp.series(function () {
return del([
"./web/build"
])
return del([
"./web/build"
])
}));
// Compile SCSS
gulp.task('css:compile', gulp.series(function () {
return gulp.src('./web/src/main/less/**/*.scss')
return gulp.src('./web/src/main/less/**/*.scss')
.pipe(sass.sync({
outputStyle: 'expanded'
}).on('error', sass.logError))
@@ -124,12 +133,12 @@ gulp.task('default', gulp.series(['clean:all', 'css', 'vendor', 'clean:build']))
gulp.task('build', gulp.series(['clean:all', 'css', 'vendor', 'clean:build']));
// Configure the browserSync task
gulp.task('browserSync', gulp.series(function() {
browserSync.init({
server: {
gulp.task('browserSync', gulp.series(function () {
browserSync.init({
server: {
baseDir: "./web/src/main/html/"
}
});
});
}));
// Dev task
@@ -141,4 +150,4 @@ gulp.task('dev', gulp.series(['css', 'browserSync'], function () {
gulp.watch('/web/src/main/html/static/assets/js/*.js').on('change', function () {
browserSync.reload();
});
}));
}));
+950 -18
View File
File diff suppressed because it is too large Load Diff
+14
View File
@@ -17,6 +17,7 @@
"devDependencies": {
"@types/jquery": "3.5.5",
"browser-sync": "2.26.13",
"css-loader": "5.0.2",
"del": "6.0.0",
"gulp": "4.0.2",
"gulp-autoprefixer": "7.0.1",
@@ -25,6 +26,7 @@
"gulp-header": "2.0.9",
"gulp-rename": "2.0.0",
"gulp-sass": "4.1.0",
"mini-css-extract-plugin": "1.3.6",
"node-sass": "5.0.0",
"ts-loader": "8.0.11",
"webpack": "5.10.0",
@@ -32,12 +34,24 @@
},
"dependencies": {
"@fortawesome/fontawesome-free": "5.15.1",
"@fullcalendar/bootstrap": "5.5.0",
"@fullcalendar/core": "5.5.0",
"@fullcalendar/daygrid": "5.5.0",
"@fullcalendar/interaction": "5.5.0",
"@fullcalendar/list": "5.5.0",
"@fullcalendar/moment-timezone": "5.5.0",
"@fullcalendar/rrule": "5.5.1",
"@fullcalendar/timegrid": "5.5.0",
"@popperjs/core": "2.7.0",
"bootstrap": "4.5.3",
"chart.js": "2.9.4",
"datatables.net-bs4": "1.10.22",
"jquery": "3.5.1",
"jquery.easing": "1.4.1",
"moment-timezone": "0.5.33",
"rrule": "2.6.8",
"sass": "^1.32.8",
"tippy.js": "6.2.7",
"typescript": "4.1.2",
"what-input": "5.2.10"
}
@@ -1,9 +1,8 @@
package org.dreamexposure.discal.server.api.endpoints.v2.event;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.Calendar;
import com.google.api.services.calendar.model.Event;
import org.dreamexposure.discal.core.calendar.CalendarAuth;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
@@ -13,6 +12,8 @@ import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.JsonUtil;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
import org.json.JSONObject;
@@ -21,10 +22,13 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZoneId;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/v2/events")
@@ -46,18 +50,22 @@ public class GetEventEndpoint {
final String guildId = requestBody.getString("guild_id");
final int calNumber = requestBody.getInt("calendar_number");
final String eventId = requestBody.getString("event_id");
final GuildSettings settings = DatabaseManager.getSettings(Snowflake.of(guildId)).block();
final CalendarData calendarData = DatabaseManager.getCalendar(settings.getGuildID(), calNumber).block();
Mono<CalendarData> calDataMono = DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
.cache();
final Event event = calDataMono.flatMap(calData -> EventWrapper.getEvent(calData, eventId))
.block();
final ZoneId tz = calDataMono.flatMap(CalendarWrapper::getCalendar)
.map(Calendar::getTimeZone)
.map(ZoneId::of)
.block();
//okay, get the calendar service and then the event
final Calendar service = CalendarAuth.getCalendarService(calendarData).block();
final Event event = service.events().get(calendarData.getCalendarAddress(), eventId).execute();
response.setContentType("application/json");
if (event != null) {
response.setStatus(GlobalConst.STATUS_SUCCESS);
return JsonUtils.convertEventToJson(event, settings).toString();
return JsonUtils.convertEventToJson(event, tz, settings).block().toString();
} else {
response.setStatus(GlobalConst.STATUS_NOT_FOUND);
return JsonUtils.getJsonResponseMessage("Event not Found");
@@ -1,13 +1,17 @@
package org.dreamexposure.discal.server.api.endpoints.v2.event.list;
import com.google.api.services.calendar.model.Calendar;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.JsonUtil;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
@@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZoneId;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -24,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/v2/events/list")
@@ -46,13 +52,20 @@ public class ListEventDateEndpoint {
final int calNumber = requestBody.getInt("calendar_number");
final long startEpoch = requestBody.getLong("epoch_start");
final long endEpoch = startEpoch + GlobalConst.oneDayMs;
final GuildSettings settings = DatabaseManager.getSettings(guildId).block();
Mono<CalendarData> calDataMono = DatabaseManager.getCalendar(guildId, calNumber)
.cache();
final ZoneId tz = calDataMono.flatMap(CalendarWrapper::getCalendar)
.map(Calendar::getTimeZone)
.map(ZoneId::of)
.block();
//okay, lets actually get the date's events.
final List<JSONObject> events = DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
final List<JSONObject> events = calDataMono
.flatMap(calData -> EventWrapper.getEvents(calData, startEpoch, endEpoch))
.flatMapMany(Flux::fromIterable)
.map(e -> JsonUtils.convertEventToJson(e, settings))
.flatMap(e -> JsonUtils.convertEventToJson(e, tz, settings))
.collectList()
.block();
@@ -1,13 +1,17 @@
package org.dreamexposure.discal.server.api.endpoints.v2.event.list;
import com.google.api.services.calendar.model.Calendar;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.JsonUtil;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
@@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZoneId;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -24,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/v2/events/list")
@@ -47,13 +53,20 @@ public class ListEventMonthEndpoint {
final int daysInMonth = requestBody.getInt("days_in_month");
final long startEpoch = requestBody.getLong("epoch_start");
final long endEpoch = startEpoch + (GlobalConst.oneDayMs * daysInMonth);
final GuildSettings settings = DatabaseManager.getSettings(guildId).block();
Mono<CalendarData> calDataMono = DatabaseManager.getCalendar(guildId, calNumber)
.cache();
final ZoneId tz = calDataMono.flatMap(CalendarWrapper::getCalendar)
.map(Calendar::getTimeZone)
.map(ZoneId::of)
.block();
//okay, lets actually get the month's events.
final List<JSONObject> events = DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
final List<JSONObject> events = calDataMono
.flatMap(calData -> EventWrapper.getEvents(calData, startEpoch, endEpoch))
.flatMapMany(Flux::fromIterable)
.map(e -> JsonUtils.convertEventToJson(e, settings))
.flatMap(e -> JsonUtils.convertEventToJson(e, tz, settings))
.collectList()
.block();
@@ -1,13 +1,17 @@
package org.dreamexposure.discal.server.api.endpoints.v2.event.list;
import com.google.api.services.calendar.model.Calendar;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.JsonUtil;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
@@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZoneId;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -24,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/v2/events/list")
@@ -48,13 +54,21 @@ public class ListEventOngoingEndpoint {
final long end = System.currentTimeMillis() + GlobalConst.oneDayMs; // one day from now
final GuildSettings settings = DatabaseManager.getSettings(guildId).block();
Mono<CalendarData> calDataMono = DatabaseManager.getCalendar(guildId, calNumber)
.cache();
final ZoneId tz = calDataMono.flatMap(CalendarWrapper::getCalendar)
.map(Calendar::getTimeZone)
.map(ZoneId::of)
.block();
//okay, lets actually get the date's events.
final List<JSONObject> events = DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
final List<JSONObject> events = calDataMono
.flatMap(calData -> EventWrapper.getEvents(calData, start, end))
.flatMapMany(Flux::fromIterable)
.filter(e -> e.getStart().getDateTime().getValue() < System.currentTimeMillis())
.filter(e -> e.getEnd().getDateTime().getValue() > System.currentTimeMillis())
.map(e -> JsonUtils.convertEventToJson(e, settings))
.flatMap(e -> JsonUtils.convertEventToJson(e, tz, settings))
.collectList()
.block();
@@ -1,13 +1,17 @@
package org.dreamexposure.discal.server.api.endpoints.v2.event.list;
import com.google.api.services.calendar.model.Calendar;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.logger.LogFeed;
import org.dreamexposure.discal.core.logger.object.LogObject;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.calendar.CalendarData;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.JsonUtil;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
@@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZoneId;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -24,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import discord4j.common.util.Snowflake;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/v2/events/list")
@@ -46,13 +52,22 @@ public class ListEventRangeEndpoint {
final int calNumber = requestBody.getInt("calendar_number");
final long startEpoch = requestBody.getLong("epoch_start");
final long endEpoch = requestBody.getLong("epoch_end");
final GuildSettings settings = DatabaseManager.getSettings(guildId).block();
Mono<CalendarData> calDataMono = DatabaseManager.getCalendar(guildId, calNumber)
.cache();
final ZoneId tz = calDataMono.flatMap(CalendarWrapper::getCalendar)
.map(Calendar::getTimeZone)
.map(ZoneId::of)
.block();
//okay, lets actually get the range's events.
final List<JSONObject> events = DatabaseManager.getCalendar(settings.getGuildID(), calNumber)
final List<JSONObject> events = calDataMono
.flatMap(calData -> EventWrapper.getEvents(calData, startEpoch, endEpoch))
.flatMapMany(Flux::fromIterable)
.map(e -> JsonUtils.convertEventToJson(e, settings))
.flatMap(e -> JsonUtils.convertEventToJson(e, tz, settings))
.collectList()
.block();
+24 -24
View File
@@ -1,31 +1,31 @@
{
"compilerOptions": {
"target": "ES5",
"module": "ES6",
"strict": true,
"noImplicitThis": false,
"removeComments": true,
"importHelpers": true,
"sourceMap": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"moduleResolution": "node",
"baseUrl": ".",
"types": [
"jquery"
],
"paths": {
"@/*": [
"web/src/main/javascript/*"
]
}
"target": "ES5",
"module": "ES6",
"strict": true,
"noImplicitThis": false,
"removeComments": true,
"importHelpers": true,
"sourceMap": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"moduleResolution": "node",
"baseUrl": ".",
"types": [
"jquery"
],
"paths": {
"@/*": [
"web/src/main/javascript/*"
]
}
},
"include": [
"web/src/main/javascript/**/*.ts",
"web/src/main/javascript/**/*.js"
"web/src/main/javascript/**/*.ts",
"web/src/main/javascript/**/*.js"
],
"exclude": [
"node_modules"
"node_modules"
]
}
}
+62 -145
View File
@@ -45,6 +45,7 @@
<!-- Custom styles for this template-->
<link href="/assets/css/sb-admin-2.min.css" rel="stylesheet">
<link href="/assets/js/main.css" rel="stylesheet">
</head>
@@ -53,22 +54,22 @@
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-discal-dark-gray sidebar sidebar-dark accordion"
id="accordionSidebar">
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-discal-dark-gray sidebar sidebar-dark accordion"
id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="/">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-calendar"></i>
</div>
<div class="sidebar-brand-text mx-3">DISCAL</div>
</a>
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="/">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-calendar"></i>
</div>
<div class="sidebar-brand-text mx-3">DISCAL</div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - About -->
<!-- Nav Item - About -->
<li class="nav-item">
<a class="nav-link" href="/about">
<i class="fas fa-fw fa-info-circle"></i>
@@ -192,23 +193,23 @@
<!-- Nav Item - User Information -->
<li th:if="${logged_in}" class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-lg-inline small" th:text="${username}"></span>
<img class="img-profile rounded-circle" th:src="${pfp}"
alt="pfp">
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-lg-inline small" th:text="${username}"></span>
<img class="img-profile rounded-circle" th:src="${pfp}"
alt="pfp">
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow
animated--grow-in bg-discal-not-black"
aria-labelledby="userDropdown">
<a class="dropdown-item text-discord-full-white" href="#"
data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2"></i>
Logout
</a>
</div>
</li>
aria-labelledby="userDropdown">
<a class="dropdown-item text-discord-full-white" href="#"
data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2"></i>
Logout
</a>
</div>
</li>
<li th:unless="${logged_in}" class="nav-item">
<a class="nav-link text-discord-full-white" href="/login">
<i class="fas fa-sign-in-alt fa-sm fa-fw mr-2"></i>
@@ -225,111 +226,27 @@
<div class="container-fluid">
<div class="loader"></div>
<div>
<label class="text-discord-full-white form-select" for="time-zone-selector">Timezone:</label>
<select id="time-zone-selector">
<option value="local">local</option>
<option value="UTC">UTC</option>
</select>
</div>
<!--Start calendar -->
<div id="calendar-container" hidden="hidden">
<table id="calendar" style="border-color: #bcbcbc"
border="#bcbcbc" cellpadding="4" cellspacing="0">
<tbody>
<tr style="height: 50px;">
<th id="previous-month" class="cal-nav">
<i class="fa fa-arrow-left"></i>
</th>
<th></th>
<th></th>
<th id="month-display" class="text-center"></th>
<th></th>
<th></th>
<th id="next-month" class="cal-nav">
<i class="fa fa-arrow-right"></i>
</th>
</tr>
<tr style="height: 40px;">
<th>Sunday</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
<tr>
<td class="cal-date" id="r1c1"></td>
<td class="cal-date" id="r1c2"></td>
<td class="cal-date" id="r1c3"></td>
<td class="cal-date" id="r1c4"></td>
<td class="cal-date" id="r1c5"></td>
<td class="cal-date" id="r1c6"></td>
<td class="cal-date" id="r1c7"></td>
</tr>
<tr>
<td class="cal-date" id="r2c1"></td>
<td class="cal-date" id="r2c2"></td>
<td class="cal-date" id="r2c3"></td>
<td class="cal-date" id="r2c4"></td>
<td class="cal-date" id="r2c5"></td>
<td class="cal-date" id="r2c6"></td>
<td class="cal-date" id="r2c7"></td>
</tr>
<tr>
<td class="cal-date" id="r3c1"></td>
<td class="cal-date" id="r3c2"></td>
<td class="cal-date" id="r3c3"></td>
<td class="cal-date" id="r3c4"></td>
<td class="cal-date" id="r3c5"></td>
<td class="cal-date" id="r3c6"></td>
<td class="cal-date" id="r3c7"></td>
</tr>
<tr>
<td class="cal-date" id="r4c1"></td>
<td class="cal-date" id="r4c2"></td>
<td class="cal-date" id="r4c3"></td>
<td class="cal-date" id="r4c4"></td>
<td class="cal-date" id="r4c5"></td>
<td class="cal-date" id="r4c6"></td>
<td class="cal-date" id="r4c7"></td>
</tr>
<tr>
<td class="cal-date" id="r5c1"></td>
<td class="cal-date" id="r5c2"></td>
<td class="cal-date" id="r5c3"></td>
<td class="cal-date" id="r5c4"></td>
<td class="cal-date" id="r5c5"></td>
<td class="cal-date" id="r5c6"></td>
<td class="cal-date" id="r5c7"></td>
</tr>
<tr>
<td class="cal-date" id="r6c1"></td>
<td class="cal-date" id="r6c2"></td>
<td class="cal-date" id="r6c3"></td>
<td class="cal-date" id="r6c4"></td>
<td class="cal-date" id="r6c5"></td>
<td class="cal-date" id="r6c6"></td>
<td class="cal-date" id="r6c7"></td>
</tr>
</tbody>
</table>
<p class="text-discord-full-white text-center" id="local-time-display">All Dates
and Times are displayed in the calendar's timezone!</p>
<br>
<br>
<a id="view-on-google-button"
class="bg-discord-blurple btn btn-discord btn-user btn-block text-discord-full-white"
style="margin: 0 auto; max-width: 200px"
target="_blank">
View on Google Calendar
</a>
<div id="calendar-container">
<div id="calendar"></div>
</div>
<!--End calendar -->
<hr>
<!--Start Event Container-->
<div id="events-container" hidden="hidden">
<h6>Events for Selected Date</h6>
<!--Add events for selected date via JS and JQuery-->
</div>
<div id="events-container" hidden="hidden">
<h6>Events for Selected Date</h6>
<!--Add events for selected date via JS and JQuery-->
</div>
<!--End Event Container-->
</div>
<!--End container fluid-->
@@ -376,25 +293,25 @@
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content bg-discal-not-black">
<div class="modal-header">
<h5 class="modal-title text-discal-blue" id="exampleModalLabel">Ready to Leave?</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span class="text-discal-red" aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p class="text-left text-discord-full-white">
Select "Logout" below if you are ready to end your current session.
</p>
</div>
<div class="modal-footer">
<button class="btn btn-discal-dark-gray text-discord-full-white"
type="button" data-dismiss="modal">Cancel
</button>
<div class="modal-header">
<h5 class="modal-title text-discal-blue" id="exampleModalLabel">Ready to Leave?</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span class="text-discal-red" aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p class="text-left text-discord-full-white">
Select "Logout" below if you are ready to end your current session.
</p>
</div>
<div class="modal-footer">
<button class="btn btn-discal-dark-gray text-discord-full-white"
type="button" data-dismiss="modal">Cancel
</button>
<a class="btn btn-discal-red text-discord-full-white" href="/logout">Logout</a>
</div>
</div>
<a class="btn btn-discal-red text-discord-full-white" href="/logout">Logout</a>
</div>
</div>
</div>
</div>
@@ -443,6 +443,12 @@
<td>!event color GREEN</td>
<td>Set's the event's <a href="/docs/events/event-colors">Color</a></td>
</tr>
<tr>
<td>!event colour</td>
<td>Alias of 'color' See above</td>
<td></td>
<td></td>
</tr>
<!-- Start event location command-->
<tr>
<td>!event location</td>
@@ -730,6 +736,12 @@
<strong>ONLY needed when using COLOR</strong>
</td>
</tr>
<tr>
<td>!a colour</td>
<td>Alias of 'color' see above</td>
<td></td>
<td></td>
</tr>
<!-- Start announcement channel command-->
<tr>
<td>!a channel</td>
@@ -308,7 +308,7 @@
</p>
<p class="text-left text-discord-full-white"
th:text="'Discord4J Version: ' + ${client.d4JVersion}">
th:text="'Discord4J Version: ' + ${client.d4jVersion}">
</p>
<p class="text-left text-discord-full-white"
+432 -62
View File
@@ -1,67 +1,437 @@
import {EmbedCalendar} from "@/objects/calendar/EmbedCalendar";
import {Calendar} from "@fullcalendar/core";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import boostrapPlugin from "@fullcalendar/bootstrap";
import interactionPlugin from "@fullcalendar/interaction";
import rrulePlugin from "@fullcalendar/rrule";
import momentTimezonePlugin from "@fullcalendar/moment-timezone";
import {ElementUtil} from "@/utils/ElementUtil";
import {CalendarGetRequest} from "@/network/calendar/CalendarGetRequest";
import {TaskCallback} from "@/objects/task/TaskCallback";
import {NetworkCallStatus} from "@/objects/network/NetworkCallStatus";
import {Snackbar} from "@/utils/snackbar";
import {TaskType} from "@/enums/TaskType";
import {WebCalendar} from "@/objects/calendar/WebCalendar";
import {Event} from "@/objects/event/Event";
import moment from "moment-timezone";
import {EventColor, eventColorClass} from "@/enums/EventColor";
import {EventFrequency} from "@/enums/EventFrequency";
export class EmbedCalendarRunner {
private embedCalendar: EmbedCalendar;
export class EmbedCalendarRunner implements TaskCallback {
private initialTimezone: string = 'local';
private timezoneSelectorEl = document
.getElementById('time-zone-selector')! as HTMLSelectElement;
private calendar?: Calendar;
private readonly guildId;
private readonly calNumber;
private readonly apiKey;
private readonly apiUrl;
private calendarData: WebCalendar = new WebCalendar();
constructor(key: string, url: string) {
this.guildId = window.location.pathname.split("/")[2];
this.calNumber = parseInt(window.location.pathname.split("/")[4]);
this.apiKey = key;
this.apiUrl = url;
//Create calendar and its needed components
let calendarEl = document.getElementById('calendar')!;
this.calendar = new Calendar(calendarEl, {
plugins: [
dayGridPlugin, timeGridPlugin,
boostrapPlugin, interactionPlugin,
rrulePlugin, momentTimezonePlugin
],
themeSystem: 'bootstrap',
initialView: 'dayGridMonth',
customButtons: {
viewGoogle: {
text: 'View on Google',
click: () => {
window.open("https://calendar.google.com/calendar/embed?src=" + this.calendarData.id, "_blank");
},
}
},
headerToolbar: {
start: 'prev,next,today',
center: 'title',
end: 'dayGridMonth,timeGridWeek,timeGridDay viewGoogle'
},
navLinks: true,
nowIndicator: true,
slotEventOverlap: true,
dayMaxEvents: true,
timeZone: this.initialTimezone,
displayEventEnd: true,
eventColor: '#5566c2',
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
omitZeroMinute: true,
hour12: true, //TODO: Support guild setting for this...
timeZoneName: 'short'
},
eventDidMount: (info) => {
// So here we will call the method to build the event modal and have that method add to dom
document.body.appendChild(this.buildModal(info.event.extendedProps.rawEvent));
},
eventWillUnmount: (info) => {
//Remove the event modal from the dom
document.body.removeChild(document.getElementById("modal-" + info.event.id)!);
},
eventClick: (info) => {
//Open modal to show all the event details instead of just the short info...
info.jsEvent.preventDefault();
// @ts-ignore
$("#modal-" + info.event.id).modal("show");
},
events: (fetchInfo, successCallback, failureCallback) => {
let bodyRaw = {
'guild_id': this.guildId,
'calendar_number': this.calNumber,
'epoch_start': fetchInfo.start.valueOf(),
'epoch_end': fetchInfo.end.valueOf(),
}
$.ajax({
url: this.apiUrl + "/v2/events/list/range",
headers: {
"Content-Type": "application/json",
"Authorization": this.apiKey,
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: (json: any) => {
let events = [];
for (let i = 0; i < json.events.length; i++) {
events.push(new Event().fromJson(json.events[i]).toFullCalEvent(false));
}
successCallback(events);
},
error: (jqXHR) => {
Snackbar.showSnackbar("[ERROR] " + jqXHR.responseJSON.message);
failureCallback(jqXHR.responseJSON.message);
},
})
}
});
//Add listener for user changing timezone selector
this.timezoneSelectorEl.addEventListener('change', function () {
this.calendar.setOption('timeZone', this.timezoneSelectorEl.value)
}.bind(this))
//Get timezones for selector
$.ajax({
url: "https://fullcalendar.io/demo-timezones.json",
method: "GET",
success: function (json: any) {
for (let timezone in json) {
if (json.hasOwnProperty(timezone) && json[timezone] !== 'UTC') {
let optionEl = document.createElement('option');
optionEl.value = json[timezone];
optionEl.innerText = json[timezone];
this.timezoneSelectorEl.appendChild(optionEl);
}
}
}.bind(this),
error: function (ignore: JQueryXHR) {
//failure
}
});
//Run init to start other API requests...
this.init();
}
private init() {
if (this.apiKey === "internal_error") {
alert("Failed to get a read-only API key to display your calendar.\nIf you keep receiving this error," +
" please contact the developers.");
} else {
//Request calendar information
let calReq = new CalendarGetRequest(this.guildId, this.calNumber, this);
calReq.provideApiDetails(this.apiKey, this.apiUrl);
//Execute the calls
calReq.execute();
}
}
onCallback(status: NetworkCallStatus) {
if (status.isSuccess) {
switch (status.type) {
case TaskType.CALENDAR_GET: {
this.calendarData = new WebCalendar().fromJson(status.body);
//Hide loading UI and show calendar...
ElementUtil.hideLoader();
this.calendar?.render();
break;
}
}
} else {
Snackbar.showSnackbar("[ERROR] " + status.message);
}
}
//Ugh, this actually sucks having to make this stuff...
buildModal(event: Event): HTMLElement {
//Create modal container
let modalContainer = document.createElement("div");
modalContainer.className = "modal fade";
modalContainer.id = "modal-" + event.eventId;
// @ts-ignore
modalContainer.role = "dialog";
//Create modal-dialog
let modalDia = document.createElement("div");
modalDia.className = "modal-dialog modal-dialog-scrollable";
modalContainer.appendChild(modalDia);
//Create modal content
let modalCon = document.createElement("div");
modalCon.className = "modal-content bg-discal-not-black";
modalDia.appendChild(modalCon);
//Create modal header and title
let modalHeader = document.createElement("div");
modalHeader.className = "modal-header bg-discal-not-black";
modalCon.appendChild(modalHeader);
let modalTitle = document.createElement("h4");
modalTitle.className = "modal-title text-discord-blurple text-center";
modalTitle.innerText = "Viewing Event";
modalHeader.appendChild(modalTitle);
//Create modal body
let modalBody = document.createElement("div");
modalBody.className = "modal-body";
modalCon.appendChild(modalBody);
//summary/name
let summaryLabel = document.createElement("label");
summaryLabel.className = "text-discord-full-white form-label";
summaryLabel.htmlFor = "event-summary-" + event.eventId;
summaryLabel.innerText = "Summary/Name";
summaryLabel.appendChild(document.createElement("br"));
modalBody.appendChild(summaryLabel);
let summary = document.createElement("textarea");
summary.className = "form-control";
summary.id = "event-summary-" + event.eventId;
summary.name = "summary";
summary.readOnly = true;
summary.value = event.summary;
modalBody.appendChild(summary);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
//Description
if (event.description.trim().length > 0) {
let descLabel = document.createElement("label");
descLabel.className = "text-discord-full-white form-label";
descLabel.htmlFor = "event-description-" + event.eventId;
descLabel.innerText = "Description";
descLabel.appendChild(document.createElement("br"));
modalBody.appendChild(descLabel);
let desc = document.createElement("textarea");
desc.className = "form-control";
desc.id = "event-description-" + event.eventId;
desc.name = "description";
desc.readOnly = true;
desc.value = event.description;
modalBody.appendChild(desc);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
}
//Create correctly formatted start/end date/times
//TODO: Support 24-hour format guild setting
const format = "dddd, MMMM, Do YYYY, h:mm a z" //Friday, February 26th 2021, 1:20 AM CST
let startString;
let endString;
if (this.timezoneSelectorEl.value == "local") {
startString = moment(new Date(event.epochStart)).format(format);
endString = moment(new Date(event.epochEnd)).format(format);
} else {
startString = moment.tz(new Date(event.epochStart), this.timezoneSelectorEl.value).format(format);
endString = moment.tz(new Date(event.epochEnd), this.timezoneSelectorEl.value).format(format);
}
//Start date and time
let startLabel = document.createElement("label");
startLabel.className = "text-discord-full-white form-label";
startLabel.htmlFor = "event-start-" + event.eventId;
startLabel.innerText = "Event Start";
startLabel.appendChild(document.createElement("br"));
modalBody.appendChild(startLabel);
let start = document.createElement("input");
start.type = "text";
start.className = "form-control";
start.id = "event-start-" + event.eventId;
start.name = "label";
start.readOnly = true;
start.value = startString;
modalBody.appendChild(start);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
//End date and time
let endLabel = document.createElement("label");
endLabel.className = "text-discord-full-white form-label";
endLabel.htmlFor = "event-end-" + event.eventId;
endLabel.innerText = "Event End";
endLabel.appendChild(document.createElement("br"));
modalBody.appendChild(endLabel);
let end = document.createElement("input");
end.type = "text";
end.className = "form-control";
end.id = "event-start-" + event.eventId;
end.name = "label";
end.readOnly = true;
end.value = endString;
modalBody.appendChild(end);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
//Location
if (event.location.trim().length > 0) {
let locationLabel = document.createElement("label");
locationLabel.className = "text-discord-full-white form-label";
locationLabel.htmlFor = "event-location-" + event.eventId;
locationLabel.innerText = "Location";
locationLabel.appendChild(document.createElement("br"));
modalBody.appendChild(locationLabel);
let location = document.createElement("textarea");
location.className = "form-control";
location.id = "event-location-" + event.eventId;
location.name = "location";
location.readOnly = true;
location.value = event.location;
modalBody.appendChild(location);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
}
//Color
let eventColor = document.createElement("h1");
eventColor.className = "text-discal-not-black bg-" + eventColorClass(event.color);
eventColor.id = "event-color-" + event.eventId;
eventColor.innerText = "Event Color: " + EventColor[event.color];
modalBody.appendChild(eventColor);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
//Recurrence
if (event.doesRecur) {
//Label
let recurLabel = document.createElement("label");
recurLabel.className = "text-discord-full-white form-label"
recurLabel.innerText = "Recurrence Settings";
recurLabel.appendChild(document.createElement("br"));
modalBody.appendChild(recurLabel);
//Group
let recurGroup = document.createElement("div");
recurGroup.className = "input-group";
modalBody.appendChild(recurGroup);
//Frequency
let freqLabel = document.createElement("span");
freqLabel.className = "input-group-text";
freqLabel.id = "event-freq-label-" + event.eventId;
freqLabel.innerText = "Frequency";
recurGroup.appendChild(freqLabel);
let freq = document.createElement("input");
freq.className = "form-control";
freq.type = "text";
freq.setAttribute("aria-describedby", "event-freq-label-" + event.eventId);
freq.readOnly = true;
freq.innerText = EventFrequency[event.recurrence.frequency];
recurGroup.appendChild(freq);
//Count
let countLabel = document.createElement("span");
countLabel.className = "input-group-text";
countLabel.id = "event-count-label-" + event.eventId;
countLabel.innerText = "Count";
recurGroup.appendChild(countLabel);
let count = document.createElement("input");
count.className = "form-control";
count.type = "number";
count.setAttribute("aria-describedby", "event-count-label-" + event.eventId);
count.readOnly = true;
count.innerText = event.recurrence.count.toString();
recurGroup.appendChild(count);
//Interval
let intervalLabel = document.createElement("span");
intervalLabel.className = "input-group-text";
intervalLabel.id = "event-interval-label-" + event.eventId;
intervalLabel.innerText = "Interval";
recurGroup.appendChild(intervalLabel);
let interval = document.createElement("input");
interval.className = "form-control";
interval.type = "number";
interval.setAttribute("aria-describedby", "event-interval-label-" + event.eventId);
interval.readOnly = true;
interval.innerText = event.recurrence.interval.toString();
recurGroup.appendChild(interval);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
}
//Image
if (event.image.trim().length > 0) {
let img = document.createElement("img");
img.className = "img-fluid round";
img.id = "event-img-" + event.eventId;
img.alt = "Event Image";
img.src = event.image;
modalBody.appendChild(img);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
}
//ID
let idLabel = document.createElement("label");
idLabel.className = "text-discord-full-white form-label";
idLabel.htmlFor = "event-id-" + event.eventId;
idLabel.innerText = "Event ID";
idLabel.appendChild(document.createElement("br"));
modalBody.appendChild(idLabel);
let id = document.createElement("input");
id.className = "form-control";
id.id = "event-id-" + event.eventId;
id.type = "text";
id.name = "id";
id.readOnly = true;
id.value = event.eventId;
modalBody.appendChild(id);
modalBody.appendChild(document.createElement("br"));
modalBody.appendChild(document.createElement("br"));
constructor() {
this.embedCalendar = new EmbedCalendar();
}
//Create modal footer
let modalFooter = document.createElement("div");
modalFooter.className = "modal-footer";
modalCon.appendChild(modalFooter);
init(key: string, url: string) {
this.embedCalendar.init(key, url);
let closeButton = document.createElement("button");
closeButton.type = "button";
closeButton.className = "btn bg-discord-blurple btn-discord btn-block text-discord-full-white";
closeButton.setAttribute("data-dismiss", "modal");
closeButton.innerText = "Close";
modalFooter.appendChild(closeButton);
/**loop through stuff and assign onclick to the functions here since we can't do it in html
*due to how the code is compiled and minified, making it impossible to call these functions
**/
document.getElementById("previous-month")!.onclick = function () {
this.previousMonth();
}.bind(this);
document.getElementById("next-month")!.onclick = function () {
this.nextMonth();
}.bind(this);
let dateDisplays = document.getElementsByClassName("cal-date");
for (let i = 0; i < dateDisplays.length; i++) {
let e = (<HTMLElement>dateDisplays[i]);
e.onclick = function () {
this.selectDate(e.id);
}.bind(this);
}
}
//Handle user input for the calendar....
previousMonth() {
this.embedCalendar.selectedDate.setMonth(this.embedCalendar.selectedDate.getMonth() - 1);
this.embedCalendar.selectedDate.setDate(1);
this.embedCalendar.setMonth(this.embedCalendar.selectedDate);
this.embedCalendar.getEventsForMonth();
this.embedCalendar.getEventsForSelectedDate();
}
nextMonth() {
this.embedCalendar.selectedDate.setMonth(this.embedCalendar.selectedDate.getMonth() + 1);
this.embedCalendar.selectedDate.setDate(1);
this.embedCalendar.setMonth(this.embedCalendar.selectedDate);
this.embedCalendar.getEventsForMonth();
this.embedCalendar.getEventsForSelectedDate();
}
selectDate(clickedId: string) {
let e = document.getElementById(clickedId)!;
let dateString = e.innerHTML.split("[")[0];
if (dateString !== "") {
let dateNum = parseInt(dateString);
this.embedCalendar.selectedDate.setDate(dateNum);
this.embedCalendar.getEventsForSelectedDate();
document.getElementsByClassName("selected")[0].classList.remove("selected");
e.classList.add("selected");
}
}
}
return modalContainer;
}
}
+81 -1
View File
@@ -11,4 +11,84 @@ export enum EventColor {
GREEN,
RED,
NONE
}
}
export function eventColorRGB(color: EventColor) {
switch (color) {
case EventColor.MELROSE: {
return '#A4BDFC';
}
case EventColor.RIPTIDE: {
return '#7AE7BF';
}
case EventColor.MAUVE: {
return '#DBADFF';
}
case EventColor.TANGERINE: {
return '#FF887C';
}
case EventColor.DANDELION: {
return '#FBD75B';
}
case EventColor.MAC_AND_CHEESE: {
return '#FFB878';
}
case EventColor.TURQUOISE: {
return '#46D6DB';
}
case EventColor.MERCURY: {
return '#E1E1E1';
}
case EventColor.BLUE: {
return '#5484ED';
}
case EventColor.GREEN: {
return '#51B749';
}
case EventColor.RED: {
return '#DC2127';
}
}
}
export function eventColorClass(color: EventColor) {
switch (color) {
case EventColor.MELROSE: {
return 'google-melrose';
}
case EventColor.RIPTIDE: {
return 'google-riptide';
}
case EventColor.MAUVE: {
return 'google-mauve';
}
case EventColor.TANGERINE: {
return 'google-tangerine';
}
case EventColor.DANDELION: {
return 'google-dandelion';
}
case EventColor.MAC_AND_CHEESE: {
return 'google-mac_and_cheese';
}
case EventColor.TURQUOISE: {
return 'google-turquoise';
}
case EventColor.MERCURY: {
return 'google-mercury';
}
case EventColor.BLUE: {
return 'google-blue';
}
case EventColor.GREEN: {
return 'google-green';
}
case EventColor.RED: {
return 'google-red';
}
default: {
return "discord-blurple";
}
}
}
+2 -3
View File
@@ -13,8 +13,7 @@ function loadDashboardCalendarPage(apiKey: string, apiUrl: string, userId: strin
}
function loadEmbedCalendar(embedKey: string, apiUrl: string) {
let embedRunner = new EmbedCalendarRunner();
embedRunner.init(embedKey, apiUrl);
new EmbedCalendarRunner(embedKey, apiUrl);
}
const body = document.getElementById("page-top")!;
@@ -94,4 +93,4 @@ if (body.dataset.embedKey != null) {
e.preventDefault();
});
})(jQuery);
})(jQuery);
@@ -1,559 +0,0 @@
import {Snackbar} from "@/utils/snackbar";
import {EventColor} from "@/enums/EventColor";
import {EventFrequency} from "@/enums/EventFrequency";
import {TaskCallback} from "@/objects/task/TaskCallback";
import {NetworkCallStatus} from "@/objects/network/NetworkCallStatus";
import {TaskType} from "@/enums/TaskType";
import {WebCalendar} from "@/objects/calendar/WebCalendar";
import {CalendarGetRequest} from "@/network/calendar/CalendarGetRequest";
import {EventListMonthRequest} from "@/network/event/list/EventListMonthRequest";
import {EventListDateRequest} from "@/network/event/list/EventListDateRequest";
import {Event} from "@/objects/event/Event";
import {ElementUtil} from "@/utils/ElementUtil";
//The calendar class. This just handles all the stuff inside of the calendar, and keeps it isolated.
export class EmbedCalendar implements TaskCallback {
private readonly guildId: string;
private readonly calNumber: number;
private todaysDate: Date;
private displays: string[];
private apiKey: string;
private apiUrl: string;
public selectedDate: Date;
private calendarData: WebCalendar = new WebCalendar();
constructor() {
this.guildId = window.location.pathname.split("/")[2];
this.calNumber = parseInt(window.location.pathname.split("/")[4]);
this.todaysDate = new Date();
this.selectedDate = new Date();
this.displays = [];
this.apiKey = "";
this.apiUrl = "";
}
init(key: string, url: string) {
this.apiKey = key;
this.apiUrl = url;
if (this.apiKey === "internal_error") {
ElementUtil.hideLoader();
alert("Failed to get a read-only API key to display your calendar. \n" +
"If you keep receiving this error, please contact the developers");
} else {
//Request calendar information
let calReq = new CalendarGetRequest(this.guildId, this.calNumber, this);
calReq.provideApiDetails(this.apiKey, this.apiUrl);
//Execute the calls
this.setMonth(this.selectedDate);
calReq.execute();
this.getEventsForMonth();
}
return this;
}
//Utility methods for data to human readable conversions
getMonthName(index: number) {
return ["January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"][index];
}
getDayName(index: number) {
return ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday"][index];
}
dateDisplays() {
//This is all of the IDs for the date displays, in row N, column X shorthand.
return ["r1c1", "r1c2", "r1c3", "r1c4", "r1c5", "r1c6", "r1c7",
"r2c1", "r2c2", "r2c3", "r2c4", "r2c5", "r2c6", "r2c7",
"r3c1", "r3c2", "r3c3", "r3c4", "r3c5", "r3c6", "r3c7",
"r4c1", "r4c2", "r4c3", "r4c4", "r4c5", "r4c6", "r4c7",
"r5c1", "r5c2", "r5c3", "r5c4", "r5c5", "r5c6", "r5c7",
"r6c1", "r6c2", "r6c3", "r6c4", "r6c5", "r6c6", "r6c7"];
}
daysInMonth() {
return new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth() + 1, 0).getDate();
}
//Handling some display nonsense
dateDisplaysToChange(str: string) {
return this.dateDisplays().slice(this.dateDisplays().indexOf(str), this.dateDisplays().length - 1);
}
findFirstDayOfMonthPosition() {
let firstDay = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), 1);
let firstDayName = this.getDayName(firstDay.getDay());
switch (firstDayName) {
case "Sunday":
return "r1c1";
case "Monday":
return "r1c2";
case "Tuesday":
return "r1c3";
case "Wednesday":
return "r1c4";
case "Thursday":
return "r1c5";
case "Friday":
return "r1c6";
case "Saturday":
return "r1c7";
}
return "r1c1";
}
changeRecurrenceEditDisplays(checkbox: HTMLInputElement) {
let eventId = checkbox.id.split("-")[1];
if (checkbox.checked) {
//Enable recur input
(<HTMLInputElement>document.getElementById("editFrequency-" + eventId)).disabled = false;
(<HTMLInputElement>document.getElementById("editCount-" + eventId)).disabled = false;
(<HTMLInputElement>document.getElementById("editInterval-" + eventId)).disabled = false;
} else {
//Disable recur input
(<HTMLInputElement>document.getElementById("editFrequency-" + eventId)).disabled = true;
(<HTMLInputElement>document.getElementById("editCount-" + eventId)).disabled = true;
(<HTMLInputElement>document.getElementById("editInterval-" + eventId)).disabled = true;
}
}
//Actually handling calendar activities
setMonth(date: Date) {
document.getElementById("month-display")!.innerHTML = this.getMonthName(date.getMonth()) + " " + date.getFullYear();
this.displays = [];
let tcc = this.dateDisplays();
for (let ii = 0; ii < tcc.length; ii++) {
let e = document.getElementById(tcc[ii])!;
e.innerHTML = "";
e.className = "cal-date";
}
let tc = this.dateDisplaysToChange(this.findFirstDayOfMonthPosition());
let count = this.daysInMonth();
for (let i = 0; i < tc.length; i++) {
let d = i + 1;
if (d <= count) {
let el = document.getElementById(tc[i])!;
el.innerHTML = d + "";
this.displays[d] = tc[i];
let thisDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), d);
if (d === this.selectedDate.getDate()) {
el.className = "selected cal-date";
}
if (thisDate.getMonth() === this.todaysDate.getMonth()
&& thisDate.getFullYear() === this.todaysDate.getFullYear()
&& thisDate.getDate() === this.todaysDate.getDate()) {
if (el.classList.contains("selected")) {
el.className = "today selected cal-date";
//get events for it
this.getEventsForSelectedDate();
} else {
el.className = "today cal-date";
}
}
}
}
}
getEventsForMonth() {
let ds = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), 1);
ds.setHours(0, 0, 0, 0);
let eventReq = new EventListMonthRequest(this.guildId, this.calNumber,
this.daysInMonth(), ds.getTime(), this);
eventReq.provideApiDetails(this.apiKey, this.apiUrl);
eventReq.execute();
}
getEventsForSelectedDate() {
let ds = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate());
ds.setHours(0, 0, 0, 0);
ElementUtil.hideEventsContainer();
let eventReq = new EventListDateRequest(this.guildId, this.calNumber, ds.getTime(), this);
eventReq.provideApiDetails(this.apiKey, this.apiUrl);
eventReq.execute();
}
onCallback(status: NetworkCallStatus): void {
if (status.isSuccess) {
switch (status.type) {
case TaskType.CALENDAR_GET:
this.calendarData = new WebCalendar().fromJson(status.body);
(<HTMLLinkElement>document.getElementById("view-on-google-button"))
.href = "https://calendar.google.com/calendar/embed?src="
+ this.calendarData.address;
break;
case TaskType.EVENT_LIST_MONTH:
//Display the event counts on the calendar...
for (let i = 0; i < status.body.events.length; i++) {
let d = new Date(status.body.events[i].epoch_start);
let e = document.getElementById(this.displays[d.getDate()])!;
if (e.innerHTML.indexOf("[") === -1) {
e.innerHTML = d.getDate() + "[1]";
} else {
e.innerHTML = d.getDate().toString()
+ "[" + (parseInt(e.innerHTML.split("[")[1][0]) + 1).toString() + "]";
}
}
ElementUtil.hideLoader();
ElementUtil.showCalendarContainer();
break;
case TaskType.EVENT_LIST_DATE:
EmbedCalendar.loadEventDisplay(status);
break;
default:
break;
}
} else {
Snackbar.showSnackbar("ERROR] " + status.message);
}
}
private static loadEventDisplay(status: NetworkCallStatus) {
//Display the selected day's event details for editing and such.
let container = document.getElementById("events-container")!;
while (container.firstChild) {
container.removeChild(container.firstChild);
}
for (let i = 0; i < status.body.events.length; i++) {
let event = new Event().fromJson(status.body.events[i]);
//Create View Button
let viewButton = document.createElement("button");
viewButton.type = "button";
viewButton.className =
"btn bg-discord-blurple btn-discord btn-block " +
"text-discord-full-white event-view-btn";
viewButton.setAttribute("data-toggle", "modal");
viewButton.setAttribute("data-target", "#modal-" + event.eventId);
viewButton.innerHTML = "View " + event.summary;
container.appendChild(viewButton);
container.appendChild(document.createElement("br"));
container.appendChild(document.createElement("br"));
//Create modal container
let modalContainer = document.createElement("div");
modalContainer.className = "modal fade";
modalContainer.id = "modal-" + event.eventId;
// @ts-ignore
modalContainer.role = "dialog";
container.appendChild(modalContainer);
//Create modal-dialog
let modalDia = document.createElement("div");
modalDia.className = "modal-dialog";
modalContainer.appendChild(modalDia);
//Create Modal Content
let modalCon = document.createElement("div");
modalCon.className = "modal-content bg-discal-not-black";
modalDia.appendChild(modalCon);
//Create modal header and title
let modalHeader = document.createElement("div");
modalHeader.className = "modal-header bg-discal-not-black";
modalCon.appendChild(modalHeader);
let modalTitle = document.createElement("h4");
modalTitle.className = "modal-title text-discord-blurple text-center";
modalTitle.innerHTML = "Viewing Event";
modalHeader.appendChild(modalTitle);
//Create Modal Body
let modalBody = document.createElement("div");
modalBody.className = "modal-body";
modalCon.appendChild(modalBody);
let form = document.createElement("form");
modalBody.appendChild(form);
//Summary
let summaryLabel = document.createElement("label");
summaryLabel.innerHTML = "Summary";
summaryLabel.className = "text-discord-full-white";
summaryLabel.appendChild(document.createElement("br"));
form.appendChild(summaryLabel);
let summary = document.createElement("input");
summary.name = "summary";
summary.type = "text";
// noinspection JSDeprecatedSymbols
summary.value = event.summary;
summary.id = "editSummary-" + event.eventId;
summary.readOnly = true;
summaryLabel.appendChild(summary);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Description
let descriptionLabel = document.createElement("label");
descriptionLabel.innerHTML = "Description";
descriptionLabel.className = "text-discord-full-white";
descriptionLabel.appendChild(document.createElement("br"));
form.appendChild(descriptionLabel);
let description = document.createElement("input");
description.name = "edit-description";
description.type = "text";
description.value = event.description;
description.id = "editDescription-" + event.eventId;
description.readOnly = true;
descriptionLabel.appendChild(description);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Start date and time
let sd = new Date(event.epochStart);
let startLabel = document.createElement("label");
startLabel.innerHTML = "Start Date and Time";
startLabel.className = "text-discord-full-white";
startLabel.appendChild(document.createElement("br"));
form.appendChild(startLabel);
let startDate = document.createElement("input");
startDate.name = "start-date";
startDate.type = "date";
startDate.valueAsDate = sd;
startDate.id = "editStartDate-" + event.eventId;
startDate.readOnly = true;
startLabel.appendChild(startDate);
let startTime = document.createElement("input");
startTime.name = "start-time";
startTime.type = "time";
startTime.value = (sd.getHours() < 10 ? "0" : "") + sd.getHours() + ":" + (sd.getMinutes() < 10 ? "0" : "") + sd.getMinutes();
startTime.id = "editStartTime-" + event.eventId;
startTime.readOnly = true;
startLabel.appendChild(startTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//End date and time
let ed = new Date(event.epochEnd);
let endLabel = document.createElement("label");
endLabel.innerHTML = "End Date and Time";
endLabel.className = "text-discord-full-white";
endLabel.appendChild(document.createElement("br"));
form.appendChild(endLabel);
let endDate = document.createElement("input");
endDate.name = "end-date";
endDate.type = "date";
endDate.valueAsDate = ed;
endDate.id = "editEndDate-" + event.eventId;
endDate.readOnly = true;
endLabel.appendChild(endDate);
let endTime = document.createElement("input");
endTime.name = "end-time";
endTime.type = "time";
endTime.value = (ed.getHours() < 10 ? "0" : "") + ed.getHours() + ":" + (ed.getMinutes() < 10 ? "0" : "") + ed.getMinutes();
endTime.id = "editEndTime-" + event.eventId;
endTime.readOnly = true;
endLabel.appendChild(endTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Location
let locationLabel = document.createElement("label");
locationLabel.innerHTML = "Location";
locationLabel.className = "text-discord-full-white";
locationLabel.appendChild(document.createElement("br"));
form.appendChild(locationLabel);
let location = document.createElement("input");
location.name = "location";
location.type = "text";
location.value = event.location;
location.id = "editLocation-" + event.eventId;
location.readOnly = true;
locationLabel.appendChild(location);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Color
let colorLabel = document.createElement("label");
colorLabel.innerHTML = "Color";
colorLabel.className = "text-discord-full-white";
colorLabel.appendChild(document.createElement("br"));
form.appendChild(colorLabel);
let colorSelect = document.createElement("select");
colorSelect.name = "color";
colorSelect.id = "editColor-" + event.eventId;
colorSelect.disabled = true;
colorLabel.appendChild(colorSelect);
for (let ec in EventColor) {
let option = document.createElement("option");
option.value = EventColor[ec];
option.text = EventColor[ec];
option.selected = (EventColor[event.color] === EventColor[ec]);
colorSelect.appendChild(option);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
if (event.doesRecur) {
//Recurrence
let recurrenceLabel = document.createElement("label");
recurrenceLabel.innerHTML = "Recurrence";
recurrenceLabel.className = "text-discord-full-white";
recurrenceLabel.appendChild(document.createElement("br"));
form.appendChild(recurrenceLabel);
if (event.isParent) {
let enableRecurrence = document.createElement("input");
enableRecurrence.name = "enable-recurrence";
enableRecurrence.type = "checkbox";
enableRecurrence.checked = false;
enableRecurrence.readOnly = true;
enableRecurrence.id = "editEnableRecur-" + event.eventId;
recurrenceLabel.appendChild(enableRecurrence);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Frequency
let frequencyLabel = document.createElement("label");
frequencyLabel.innerHTML = "Recurrence - Frequency";
frequencyLabel.className = "text-discord-full-white";
frequencyLabel.appendChild(document.createElement("br"));
form.appendChild(frequencyLabel);
let freqSelect = document.createElement("select");
freqSelect.name = "frequency";
freqSelect.id = "editFrequency-" + event.eventId;
frequencyLabel.appendChild(freqSelect);
for (let f in EventFrequency) {
let op = document.createElement("option");
op.value = EventFrequency[f];
op.text = EventFrequency[f];
op.selected = (EventFrequency[event.recurrence.frequency] === EventFrequency[f]);
freqSelect.appendChild(op);
}
freqSelect.disabled = true;
frequencyLabel.appendChild(freqSelect);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Count
let countLabel = document.createElement("label");
countLabel.innerHTML = "Recurrence - Count";
countLabel.className = "text-discord-full-white";
countLabel.appendChild(document.createElement("br"));
form.appendChild(countLabel);
let count = document.createElement("input");
count.name = "count";
count.type = "number";
count.valueAsNumber = event.recurrence.count;
count.min = "-1";
count.id = "editCount-" + event.eventId;
count.readOnly = true;
countLabel.appendChild(count);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Interval
let intervalLabel = document.createElement("label");
intervalLabel.innerHTML = "Recurrence - Interval";
intervalLabel.className = "text-discord-full-white";
intervalLabel.appendChild(document.createElement("br"));
form.appendChild(intervalLabel);
let interval = document.createElement("input");
interval.name = "interval";
interval.type = "number";
interval.valueAsNumber = event.recurrence.interval;
interval.min = "1";
interval.id = "editInterval-" + event.eventId;
interval.readOnly = true;
intervalLabel.appendChild(interval);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
} else {
//Cannot edit recurrence
let cannotEditRecur = document.createElement("input");
cannotEditRecur.name = "ignore-cer";
cannotEditRecur.type = "text";
cannotEditRecur.readOnly = true;
cannotEditRecur.value = "Cannot edit child";
recurrenceLabel.appendChild(cannotEditRecur);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
}
//Image
let imageLabel = document.createElement("label");
imageLabel.innerHTML = "Image";
imageLabel.className = "text-discord-full-white";
imageLabel.appendChild(document.createElement("br"));
form.appendChild(imageLabel);
let image = document.createElement("input");
image.name = "image";
image.type = "text";
image.value = event.image;
image.id = "editImage-" + event.eventId;
image.readOnly = true;
imageLabel.appendChild(image);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//ID (readonly) for API
let idLabel = document.createElement("label");
idLabel.innerHTML = "Event ID";
idLabel.className = "text-discord-full-white";
idLabel.appendChild(document.createElement("br"));
form.appendChild(idLabel);
let hiddenId = document.createElement("input");
hiddenId.type = "text";
hiddenId.name = "id";
hiddenId.value = event.eventId;
hiddenId.id = "editId-" + event.eventId;
hiddenId.readOnly = true;
idLabel.appendChild(hiddenId);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Create modal footer
let modalFooter = document.createElement("div");
modalFooter.className = "modal-footer";
modalCon.appendChild(modalFooter);
let closeButton = document.createElement("button");
closeButton.type = "button";
closeButton.className = "btn bg-discord-blurple btn-discord btn-block " +
"text-discord-full-white";
closeButton.setAttribute("data-dismiss", "modal");
closeButton.innerHTML = "Close";
modalFooter.appendChild(closeButton);
//Oh my god finally done!!!
}
ElementUtil.showEventsContainer();
}
}
+60 -19
View File
@@ -1,30 +1,31 @@
import {EventColor} from "@/enums/EventColor";
import {EventColor, eventColorRGB} from "@/enums/EventColor";
import {Recurrence} from "@/objects/event/Recurrence";
export class Event {
private _eventId: string = "";
private _epochStart: number = 0;
private _epochEnd: number = 0;
private _eventId: string = "";
private _epochStart: number = 0;
private _epochEnd: number = 0;
private _summary: string = "";
private _description: string = "";
private _location: string = "";
private _summary: string = "";
private _description: string = "";
private _location: string = "";
private _isParent: boolean = false;
private _color: EventColor = EventColor.NONE;
private _isParent: boolean = false;
private _color: EventColor = EventColor.NONE;
private _recur: boolean = false;
private _recurrence: Recurrence = new Recurrence();
private _recur: boolean = false;
private _recurrence: Recurrence = new Recurrence();
private _rrule: String = "";
private _image: string = "";
private _image: string = "";
constructor() {
}
constructor() {
}
//Setter/getter pairs
get eventId() {
return this._eventId;
}
//Setter/getter pairs
get eventId() {
return this._eventId;
}
set eventId(id) {
this._eventId = id;
@@ -102,6 +103,14 @@ export class Event {
this._recurrence = rec;
}
get rrule() {
return this._rrule;
}
set rrule(rr) {
this._rrule = rr;
}
get image() {
return this._image;
}
@@ -112,6 +121,36 @@ export class Event {
//Json conversion
toFullCalEvent(editable: boolean) {
let event: any = {
id: this.eventId,
groupId: this.eventId.split("_")[0],
title: this.summary,
description: this.description,
location: this.location,
image: this.image,
eventColor: this.color,
start: this.epochStart,
end: this.epochEnd,
overlap: true,
editable: editable,
rawEvent: this,
};
if (this.color != EventColor.NONE) {
event.borderColor = eventColorRGB(this.color);
}
if (this.doesRecur) {
event.rrule = this.rrule;
}
return event;
}
toJson() {
let json: any = {
"event_id": this.eventId,
@@ -132,6 +171,7 @@ export class Event {
}
if (this.doesRecur) {
json.recurrence = this.recurrence.toJson();
json.rrule = this.rrule
}
if (this.image.length > 0) {
json.image = this.image;
@@ -161,6 +201,7 @@ export class Event {
this.doesRecur = json.recur;
if (this.doesRecur) {
this.recurrence = new Recurrence().fromJson(json.recurrence);
this.rrule = json.rrule;
}
if (json.hasOwnProperty("image")) {
@@ -169,4 +210,4 @@ export class Event {
return this;
}
}
}
+15 -19
View File
@@ -1,26 +1,22 @@
@import "variables";
.cal-date {
width: 80px;
height: 80px;
.fc-toolbar-title {
color: $discal-light-gray;
}
.cal-date:hover {
background-color: $discal-red;
.fc-prev-button, .fc-today-button, .fc-next-button, .fc-viewGoogle-button, .fc-dayGridMonth-button,
.fc-timeGridDay-button, .fc-timeGridWeek-button {
background-color: $discal-blue !important;
border-color: $discal-blue !important;
:active {
background-color: $discal-red !important;
border-color: $discal-red !important;
}
}
.cal-date.today {
background-color: $discord-blurple;
.tippy-box[data-theme~='discal'] {
background-color: $discal-light-gray;
color: $discal-dark-gray;
padding: 5px;
}
.cal-date.selected {
background-color: $discord-greyple;
}
.cal-nav {
text-align: center;
}
.event-view-btn {
margin: 0 auto;
}
+40 -18
View File
@@ -51,25 +51,47 @@ $brand-google: #ea4335 !default;
$brand-facebook: #3b5998 !default;
$brand-discord: #7289da !default;
// Google colors
$google-melrose: #A4BDFC !default;
$google-riptide: #7AE7BF !default;
$google-mauve: #DBADFF !default;
$google-tangerine: #FF887C !default;
$google-dandelion: #FBD75B !default;
$google-mac_and_cheese: #FFB878 !default;
$google-turquoise: #46D6DB !default;
$google-mercury: #E1E1E1 !default;
$google-blue: #5484ED !default;
$google-green: #51B749 !default;
$google-red: #DC2127 !default;
$theme-colors: (
// Discord Colors
discord-blurple: #7289DA,
discord-full-white: #FFFFFF,
discord-greyple: #99AAB5,
discord-dark-but-not-black: #2C2F33,
discord-not-quite-black: #23272A,
// DisCal colors
discal-blue: #5566c2,
discal-red: #ef0813,
discal-light-gray: #bcbcbc,
discal-dark-gray: #3c3d41,
discal-not-black: #242428,
// Brand colors
brand-google: #ea4335,
brand-facebook: #3b5998,
brand-discord: #7289da,
// Discord Colors
discord-blurple: #7289DA,
discord-full-white: #FFFFFF,
discord-greyple: #99AAB5,
discord-dark-but-not-black: #2C2F33,
discord-not-quite-black: #23272A,
// DisCal colors
discal-blue: #5566c2,
discal-red: #ef0813,
discal-light-gray: #bcbcbc,
discal-dark-gray: #3c3d41,
discal-not-black: #242428,
// Brand colors
brand-google: #ea4335,
brand-facebook: #3b5998,
brand-discord: #7289da,
// Google colors
google-mauve: #DBADFF,
google-tangerine: #FF887C,
google-dandelion: #FBD75B,
google-mac_and_cheese: #FFB878,
google-turquoise: #46D6DB,
google-mercury: #E1E1E1,
google-blue: #5484ED,
google-green: #51B749,
google-red: #DC2127,
);
// Set Contrast Threshold
+39 -18
View File
@@ -1,24 +1,45 @@
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode: "production",
entry: './web/src/main/javascript/index.ts',
devtool: "inline-source-map",
module: {
rules: [{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}],
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
alias: {
'@': path.resolve('web/src/main/javascript')
}
},
output: {
mode: "production",
entry: './web/src/main/javascript/index.ts',
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader', options: {
importLoaders: 1
}
}
]
}
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
alias: {
'@': path.resolve('web/src/main/javascript')
}
},
output: {
path: path.resolve(__dirname, "web/src/main/html/static/assets/js"),
filename: 'bundle.js'
},
};
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css'
})
]
};