Make some massive changes to how the website is built and fix several issues

This commit changes a lot of things, the major changes are as follows:
- removed all old web files from server module
- Switched to using Typescript for development of the frontend
- fixed /events/list/list endpoint duplication
- Compile all TS code into a single JS file
- Add automatic gulp building/cleaning on maven steps
- Add object parity in TS for OOP handling
- All relevant API calls have own TS file for request eliminating duplicated code
- Add read-only API key support for embed pages (so that a temp key can be generated for anonymous users without write permissions)
- Fixed several typos and small issues
This commit is contained in:
NovaFox161
2020-03-03 14:16:40 -06:00
parent 4977ade3e1
commit 164a939c8f
165 changed files with 6672 additions and 10621 deletions
@@ -5,14 +5,14 @@ import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.network.google.Authorization;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.network.discal.NetworkInfo;
import org.dreamexposure.discal.server.listeners.PubSubListener;
import org.dreamexposure.discal.server.network.discal.NetworkMediator;
import org.dreamexposure.discal.server.network.discordbots.UpdateDisBotData;
import org.dreamexposure.discal.server.network.discordpw.UpdateDisPwData;
import org.dreamexposure.novautils.event.EventManager;
import org.dreamexposure.novautils.network.pubsub.PubSubManager;
import org.dreamexposure.discal.server.utils.Authentication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration;
import org.springframework.boot.system.ApplicationPid;
import java.io.File;
import java.io.FileReader;
@@ -32,10 +32,6 @@ public class DisCalServer {
//Init logger
Logger.getLogger().init();
//Register DisCal events
EventManager.get().init();
EventManager.get().getEventBus().register(new PubSubListener());
//Connect to MySQL
DatabaseManager.getManager().connectToMySQL();
DatabaseManager.getManager().handleMigrations();
@@ -53,16 +49,26 @@ public class DisCalServer {
Logger.getLogger().exception(null, "'Spring ERROR' by 'PANIC! AT THE API'", e, true, DisCalServer.class);
}
//Start Redis PubSub Listeners
PubSubManager.get().init(BotSettings.REDIS_HOSTNAME.get(), Integer.parseInt(BotSettings.REDIS_PORT.get()), "N/a", BotSettings.REDIS_PASSWORD.get());
//We must register each channel we want to use. This is super important.
PubSubManager.get().register(-1, BotSettings.PUBSUB_PREFIX.get() + "/ToServer/KeepAlive");
//Start network monitoring
NetworkMediator.get().init();
//Handle the rest of the bullshit
UpdateDisBotData.init();
UpdateDisPwData.init();
Authentication.init();
//Save pid...
networkInfo.setPid(new ApplicationPid().toString());
//Add shutdown hooks...
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Logger.getLogger().status("Shutting down API", "API Shutting down...");
Authentication.shutdown();
NetworkMediator.get().shutdown();
UpdateDisBotData.shutdown();
UpdateDisPwData.shutdown();
DatabaseManager.getManager().disconnectFromMySQL();
}));
}
public static NetworkInfo getNetworkInfo() {
@@ -0,0 +1,63 @@
package org.dreamexposure.discal.server.api.endpoints.v2.account;
import org.dreamexposure.discal.core.crypto.KeyGenerator;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/v2/account/key")
public class KeyRequestEndpoint {
@GetMapping(value = "/readonly/get")
public String getReadonlyKey(HttpServletRequest request, HttpServletResponse response) {
//Check auth, must be from within DisCal network, as this is generating an API key...
AuthenticationState authState = Authentication.authenticate(request);
if (!authState.isSuccess()) {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (!authState.isFromDiscalNetwork()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Unauthorized to use this Endpoint.");
}
try {
//Generate readonly API key. This key should only be valid for 1 hour...
String key = KeyGenerator.csRandomAlphaNumericString(64);
//Save key to memory... so it can be used for authentication just like the others
Authentication.saveReadOnlyKey(key);
//Return key to web....
JSONObject responseBody = new JSONObject();
responseBody.put("key", key);
response.setContentType("application/json");
response.setStatus(200);
return responseBody.toString();
} catch (JSONException e) {
e.printStackTrace();
response.setContentType("application/json");
response.setStatus(400);
return JsonUtils.getJsonResponseMessage("Bad Request");
} catch (Exception e) {
Logger.getLogger().exception(null, "[API-v2] Internal read only key request exception", e, true, this.getClass());
response.setContentType("application/json");
response.setStatus(500);
return JsonUtils.getJsonResponseMessage("Internal Server Error");
}
}
}
@@ -23,6 +23,10 @@ public class LogoutEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
try {
@@ -31,6 +31,10 @@ public class CreateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -30,6 +30,10 @@ public class DeleteEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -34,6 +34,10 @@ public class UpdateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -31,6 +31,10 @@ public class DeleteEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -35,6 +35,10 @@ public class UpdateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -43,6 +43,10 @@ public class CreateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -30,6 +30,10 @@ public class DeleteEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -42,6 +42,10 @@ public class UpdateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -32,7 +32,7 @@ import discord4j.core.object.util.Snowflake;
@RestController
@RequestMapping("/v2/events/list")
public class DateEndpoint {
@PostMapping(value = "/list/date", produces = "application/json")
@PostMapping(value = "/date", produces = "application/json")
public String getEventsForDate(HttpServletRequest request, HttpServletResponse response, @RequestBody String rBody) {
//Authenticate...
AuthenticationState authState = Authentication.authenticate(request);
@@ -71,6 +71,7 @@ public class DateEndpoint {
JSONObject body = new JSONObject();
body.put("events", jEvents);
body.put("message", "Events successfully listed.");
response.setContentType("application/json");
response.setStatus(200);
@@ -32,7 +32,7 @@ import discord4j.core.object.util.Snowflake;
@RestController
@RequestMapping("/v2/events/list")
public class MonthEndpoint {
@PostMapping(value = "/list/month", produces = "application/json")
@PostMapping(value = "/month", produces = "application/json")
public String getEventsForMonth(HttpServletRequest request, HttpServletResponse response, @RequestBody String rBody) {
//Authenticate...
AuthenticationState authState = Authentication.authenticate(request);
@@ -31,7 +31,7 @@ import discord4j.core.object.util.Snowflake;
@RestController
@RequestMapping("/v2/events/list")
public class RangeEndpoint {
@PostMapping(value = "/list/range", produces = "application/json")
@PostMapping(value = "/range", produces = "application/json")
public String getEventsForRange(HttpServletRequest request, HttpServletResponse response, @RequestBody String rBody) {
//Authenticate...
AuthenticationState authState = Authentication.authenticate(request);
@@ -1,9 +1,13 @@
package org.dreamexposure.discal.server.api.endpoints.v2.guild.settings;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.enums.network.DisCalRealm;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.core.utils.GuildUtils;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
@@ -17,6 +21,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import discord4j.core.object.util.Snowflake;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@RestController
@RequestMapping("/v2/guild/settings")
@@ -29,6 +35,10 @@ public class UpdateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -65,6 +75,32 @@ public class UpdateEndpoint {
if (DatabaseManager.getManager().updateSettings(settings)) {
response.setContentType("application/json");
response.setStatus(200);
//Invalidate the cache on the shard this guild is on...
Thread thread = new Thread(() -> {
try {
JSONObject requestJson = new JSONObject();
requestJson.put("realm", DisCalRealm.BOT_INVALIDATE_CACHES.name());
int shardIndex = GuildUtils.findShard(Snowflake.of(guildId));
OkHttpClient client = new OkHttpClient();
okhttp3.RequestBody cacheRequestBody = okhttp3.RequestBody.create(GlobalConst.JSON, requestJson.toString());
Request cacheRequest = new Request.Builder()
.url(BotSettings.COM_SUB_DOMAIN.get() + shardIndex + ".discalbot.com/api/v1/com/bot/action/handle")
.header("Authorization", BotSettings.BOT_API_TOKEN.get())
.post(cacheRequestBody)
.build();
//If this fails, its not a huge deal, the cache will just be out of date for up to an hour max...
client.newCall(cacheRequest).execute();
} catch (Exception e) {
Logger.getLogger().exception(null, "[API-v2] Cache invalidate failed after update", e, true, this.getClass());
}
});
thread.setDaemon(true);
thread.start();
return JsonUtils.getJsonResponseMessage("Successfully updated guild settings!");
} else {
response.setContentType("application/json");
@@ -30,6 +30,10 @@ public class UpdateEndpoint {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (authState.isReadOnly()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Read-Only key not Allowed");
}
//Okay, now handle actual request.
@@ -1,4 +1,4 @@
package org.dreamexposure.discal.server.api.endpoints.v2;
package org.dreamexposure.discal.server.api.endpoints.v2.status;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
@@ -15,7 +15,7 @@ import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/v2/status")
public class StatusEndpoint {
public class GetEndpoint {
@PostMapping(value = "/get", produces = "application/json")
public String getStatus(HttpServletRequest request, HttpServletResponse response) {
@@ -0,0 +1,92 @@
package org.dreamexposure.discal.server.api.endpoints.v2.status;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.network.discal.ConnectedClient;
import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.utils.JsonUtils;
import org.dreamexposure.discal.server.DisCalServer;
import org.dreamexposure.discal.server.utils.Authentication;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/v2/status")
public class KeepAliveEndpoint {
@PostMapping(value = "/keep-alive", produces = "application/json")
public String keepAlive(HttpServletRequest request, HttpServletResponse response, @RequestBody String rBody) {
//Authenticate...
AuthenticationState authState = Authentication.authenticate(request);
if (!authState.isSuccess()) {
response.setStatus(authState.getStatus());
response.setContentType("application/json");
return authState.toJson();
} else if (!authState.isFromDiscalNetwork()) {
response.setStatus(401);
response.setContentType("application/json");
return JsonUtils.getJsonResponseMessage("Only official DisCal clients can use this Endpoint");
}
//Okay, now handle actual request.
try {
JSONObject body = new JSONObject(rBody);
int index = body.getInt("index");
if (DisCalServer.getNetworkInfo().clientExists(index)) {
//In network, update info...
ConnectedClient cc = DisCalServer.getNetworkInfo().getClient(index);
cc.setLastKeepAlive(System.currentTimeMillis());
cc.setConnectedServers(body.getInt("guilds"));
cc.setMemUsed(body.getDouble("memory"));
cc.setUptime(body.getString("uptime"));
cc.setIpForRestart(body.getString("ip"));
cc.setPortForRestart(body.getInt("port"));
if (!cc.getPid().equals(body.getString("pid"))) {
//Was restarted at some point, so we are "re-adding" to network
cc.setPid(body.getString("pid"));
Logger.getLogger().status("Client pid changed", "Shard Index of changed Client: " + cc.getClientIndex());
}
} else {
//Not in network, add info...
ConnectedClient cc = new ConnectedClient(index);
cc.setLastKeepAlive(System.currentTimeMillis());
cc.setConnectedServers(body.getInt("guilds"));
cc.setMemUsed(body.getDouble("memory"));
cc.setUptime(body.getString("uptime"));
//Network handling stuffs
cc.setIpForRestart(body.getString("ip"));
cc.setPortForRestart(body.getInt("port"));
cc.setPid(body.getString("pid"));
DisCalServer.getNetworkInfo().addClient(cc);
}
response.setContentType("application/json");
response.setStatus(200);
return JsonUtils.getJsonResponseMessage("Success!");
} catch (JSONException e) {
e.printStackTrace();
response.setContentType("application/json");
response.setStatus(400);
return JsonUtils.getJsonResponseMessage("Bad Request");
} catch (Exception e) {
Logger.getLogger().exception(null, "[API-v2] Internal keep alive error", e, true, this.getClass());
response.setContentType("application/json");
response.setStatus(500);
return JsonUtils.getJsonResponseMessage("Internal Server Error");
}
}
}
@@ -8,7 +8,6 @@ import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerF
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.CorsRegistration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -18,7 +17,7 @@ public class ServletConfig implements
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
public void customize(ConfigurableServletWebServerFactory factory) {
factory.setPort(Integer.valueOf(BotSettings.PORT.get()));
factory.setPort(Integer.parseInt(BotSettings.PORT.get()));
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
}
@@ -27,8 +26,8 @@ public class ServletConfig implements
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
CorsRegistration reg = registry.addMapping("/api/**");
reg.allowedOrigins("*");
registry.addMapping("/api/**").allowedOrigins("*");
registry.addMapping("/v2/**").allowedOrigins("*");
}
};
}
@@ -1,44 +0,0 @@
package org.dreamexposure.discal.server.listeners;
import com.google.common.eventbus.Subscribe;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.network.discal.ConnectedClient;
import org.dreamexposure.discal.server.DisCalServer;
import org.dreamexposure.novautils.events.network.pubsub.PubSubReceiveEvent;
/**
* @author NovaFox161
* Date Created: 9/8/2018
* For Project: DisCal-Discord-Bot
* Author Website: https://www.novamaday.com
* Company Website: https://www.dreamexposure.org
* Contact: nova@dreamexposure.org
*/
@SuppressWarnings({"Duplicates", "UnstableApiUsage"})
public class PubSubListener {
@Subscribe
public static void handle(PubSubReceiveEvent event) {
//Handle keep alive...
if (event.getChannelName().equalsIgnoreCase(BotSettings.PUBSUB_PREFIX.get() + "/ToServer/KeepAlive")) {
if (DisCalServer.getNetworkInfo().clientExists(event.getClient())) {
//In network, update info...
ConnectedClient cc = DisCalServer.getNetworkInfo().getClient(event.getClient());
cc.setLastKeepAlive(System.currentTimeMillis());
cc.setConnectedServers(event.getData().getInt("Server-Count"));
cc.setUptime(event.getData().getString("Uptime"));
cc.setMemUsed(event.getData().getDouble("Mem-Used"));
} else {
//Not in network, add info...
ConnectedClient cc = new ConnectedClient(event.getClient());
cc.setLastKeepAlive(System.currentTimeMillis());
cc.setConnectedServers(event.getData().getInt("Server-Count"));
cc.setUptime(event.getData().getString("Uptime"));
cc.setMemUsed(event.getData().getDouble("Mem-Used"));
DisCalServer.getNetworkInfo().addClient(cc);
}
}
}
}
@@ -0,0 +1,120 @@
package org.dreamexposure.discal.server.network.discal;
import com.google.common.io.CharStreams;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.network.discal.ConnectedClient;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.server.DisCalServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
@SuppressWarnings("UnusedReturnValue")
public class NetworkMediator {
private static NetworkMediator instance;
private Timer timer;
private NetworkMediator() {
}
public static NetworkMediator get() {
if (instance == null)
instance = new NetworkMediator();
return instance;
}
public void init() {
timer = new Timer(true);
timer.schedule(new TimerTask() {
@Override
public void run() {
List<ConnectedClient> downShards = new ArrayList<>();
for (ConnectedClient c : DisCalServer.getNetworkInfo().getClients()) {
if (System.currentTimeMillis() > c.getLastKeepAlive() + (5 * GlobalConst.oneMinuteMs))
downShards.add(c); //Missed last 5+ heartbeats...
}
//Now we issue the restarts for the shards...
for (ConnectedClient c : downShards)
issueRestart(c);
}
}, 60 * 1000, 60 * 1000);
}
public void shutdown() {
if (timer != null)
timer.cancel();
}
public String issueRestart(ConnectedClient c) {
try {
Session session = createSession(c.getIpForRestart(), c.getPortForRestart());
session.connect();
ChannelExec channel = (ChannelExec) session.openChannel("exec");
try {
channel.setCommand(BotSettings.RESTART_CMD.get().replace("%index%", c.getClientIndex() + ""));
channel.setInputStream(null);
InputStream output = channel.getInputStream();
channel.connect();
//noinspection UnstableApiUsage
return CharStreams.toString(new InputStreamReader(output));
} catch (JSchException | IOException e) {
Logger.getLogger().exception(null, "[NETWORK] Failed to restart shard.s2: " + c.getClientIndex(), e, true, this.getClass());
closeConnection(channel, session);
} finally {
closeConnection(channel, session);
}
//Tell network manager to remove this client until it restarts.
DisCalServer.getNetworkInfo().removeClient(c.getClientIndex(), "Restart issued by mediator for missed heartbeats");
} catch (Exception e) {
Logger.getLogger().exception(null, "[NETWORK] Failed to restart shard.s1: " + c.getClientIndex(), e, true, this.getClass());
}
return "ERROR";
}
private Session createSession(String ip, int port) throws JSchException {
//Handle config
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
//Handle identity
JSch jSch = new JSch();
jSch.addIdentity(BotSettings.RESTART_SSH_KEY.get());
//Actual session
Session session = jSch.getSession(BotSettings.RESTART_USER.get(), ip, port);
session.setConfig(config);
return session;
}
private void closeConnection(ChannelExec channel, Session session) {
try {
channel.disconnect();
} catch (Exception ignored) {
}
session.disconnect();
}
}
@@ -1,14 +1,19 @@
package org.dreamexposure.discal.server.network.discordpw;
import okhttp3.*;
import org.dreamexposure.discal.core.logger.Logger;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.utils.GlobalConst;
import org.dreamexposure.discal.server.DisCalServer;
import org.json.JSONObject;
import java.util.Timer;
import java.util.TimerTask;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Nova Fox on 1/13/2017.
* Website: www.cloudcraftgaming.com
@@ -17,8 +22,6 @@ import java.util.TimerTask;
public class UpdateDisPwData {
private static Timer timer;
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public static void init() {
if (BotSettings.UPDATE_SITES.get().equalsIgnoreCase("true")) {
timer = new Timer(true);
@@ -43,7 +46,7 @@ public class UpdateDisPwData {
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, json.toString());
RequestBody body = RequestBody.create(GlobalConst.JSON, json.toString());
Request request = new Request.Builder()
.url("https://bots.discord.pw/api/bots/265523588918935552/stats")
.post(body)
@@ -7,15 +7,21 @@ import org.dreamexposure.discal.core.object.web.AuthenticationState;
import org.dreamexposure.discal.core.object.web.UserAPIAccount;
import org.dreamexposure.discal.core.utils.GlobalConst;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.http.HttpServletRequest;
public class Authentication {
private static Map<String, Long> tempKeys = new HashMap<>();
private static Timer timer;
private static Map<String, Long> tempKeys = new HashMap<>();
private static Map<String, Long> readOnlyKeys = new HashMap<>();
//TODO: Still gotta figure out how to handle embed, but whatever...
public static AuthenticationState authenticate(HttpServletRequest request) {
if (!request.getMethod().equalsIgnoreCase("POST")) {
Logger.getLogger().api("Denied '" + request.getMethod() + "' access", request.getRemoteAddr());
@@ -39,7 +45,14 @@ public class Authentication {
return new AuthenticationState(true)
.setStatus(200)
.setReason("Success")
.setKeyUsed(key);
.setKeyUsed(key)
.setIsReadOnly(false);
} else if (readOnlyKeys.containsKey(key)) {
return new AuthenticationState(true)
.setStatus(200)
.setReason("Success")
.setKeyUsed(key)
.setIsReadOnly(true);
} else if (key.equals("teapot")) {
return new AuthenticationState(false)
.setStatus(418)
@@ -79,4 +92,47 @@ public class Authentication {
public static void removeTempKey(String key) {
tempKeys.remove(key);
}
public static void saveReadOnlyKey(String key) {
if (!readOnlyKeys.containsKey(key)) {
readOnlyKeys.put(key, System.currentTimeMillis() + GlobalConst.oneHourMs);
}
}
//Timer handling
public static void init() {
timer = new Timer(true);
timer.schedule(new TimerTask() {
@Override
public void run() {
handleExpiredKeys();
}
}, 60 * 60 * 1000);
}
public static void shutdown() {
if (timer != null)
timer.cancel();
}
private static void handleExpiredKeys() {
List<String> allToRemove = new ArrayList<>();
for (String key : tempKeys.keySet()) {
long expireTime = tempKeys.get(key);
if (expireTime >= System.currentTimeMillis())
allToRemove.add(key);
}
for (String key : readOnlyKeys.keySet()) {
long expireTime = readOnlyKeys.get(key);
if (expireTime >= System.currentTimeMillis())
allToRemove.add(key);
}
for (String key : allToRemove) {
tempKeys.remove(key);
readOnlyKeys.remove(key);
}
}
}
@@ -1,18 +0,0 @@
function handleVisibility() {
var e = document.getElementById("create-ann-type");
var value = e.options[e.selectedIndex].value;
if (value === "UNIVERSAL") {
//HIde color and event ID
document.getElementById("create-ann-event").style.visibility = "hidden";
document.getElementById("create-ann-color").style.visibility = "hidden";
} else if (value === "SPECIFIC" || value === "RECUR") {
//Hide color, show event ID.
document.getElementById("create-ann-event").style.visibility = "visible";
document.getElementById("create-ann-color").style.visibility = "hidden";
} else if (value === "COLOR") {
//Hide event ID, show color.
document.getElementById("create-ann-event").style.visibility = "hidden";
document.getElementById("create-ann-color").style.visibility = "visible";
}
}
@@ -1,753 +0,0 @@
var calendar = {
todaysDate: new Date(),
selectedDate: new Date(),
displays: []
};
function getMonthName(index) {
return ["January", "February",
"March", "April",
"May", "June",
"July", "August",
"September", "October",
"November", "December"][index];
}
function getDayName(index) {
return ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday"][index];
}
function dateDisplays() {
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"];
}
function colors() {
return ["MELROSE", "RIPTIDE", "MAUVE", "TANGERINE",
"DANDELION", "MAC_AND_CHEESE", "TURQUOISE",
"MERCURY", "BLUE", "GREED", "RED", "NONE"];
}
function frequencies() {
return ["DAILY", "WEEKLY", "MONTHLY", "YEARLY"];
}
function dateDisplaysToChange(str) {
return dateDisplays().slice(dateDisplays().indexOf(str), dateDisplays().length - 1);
}
function findFirstDayOfMonthPosition() {
var firstDay = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), 1);
var firstDayName = 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";
}
}
function daysInMonth() {
return new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth() + 1, 0).getDate();
}
function changeRecurrenceEditDisplays(checkbox) {
var eventId = checkbox.id.split("-")[1];
if (checkbox.checked) {
//Enable recur input
document.getElementById("editFrequency-" + eventId).disabled = false;
document.getElementById("editCount-" + eventId).disabled = false;
document.getElementById("editInterval-" + eventId).disabled = false;
} else {
//Disable recur input
document.getElementById("editFrequency-" + eventId).disabled = true;
document.getElementById("editCount-" + eventId).disabled = true;
document.getElementById("editInterval-" + eventId).disabled = true;
}
}
function changeRecurrenceCreateDisplays(checkbox) {
if (checkbox.checked) {
//Enable recur input
document.getElementById("create-frequency").disabled = false;
document.getElementById("create-count").disabled = false;
document.getElementById("create-interval").disabled = false;
} else {
//Disable recur input
document.getElementById("create-frequency").disabled = true;
document.getElementById("create-count").disabled = true;
document.getElementById("create-interval").disabled = true;
}
}
function setMonth(parameters) {
var date = parameters.date;
document.getElementById("month-display").innerHTML = getMonthName(date.getMonth()) + " " + date.getFullYear();
calendar.displays = [];
var tcc = dateDisplays();
for (var ii = 0; ii < tcc.length; ii++) {
var e = document.getElementById(tcc[ii]);
e.innerHTML = "";
e.className = "";
}
var tc = dateDisplaysToChange(findFirstDayOfMonthPosition());
var count = daysInMonth();
for (var i = 0; i < tc.length; i++) {
var d = i + 1;
if (d <= count) {
var el = document.getElementById(tc[i]);
el.innerHTML = d + "";
calendar.displays[d] = tc[i];
var thisDate = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), d);
if (d === calendar.selectedDate.getDate()) {
el.className = "selected";
}
if (thisDate.getMonth() === calendar.todaysDate.getMonth()
&& thisDate.getFullYear() === calendar.todaysDate.getFullYear()
&& thisDate.getDate() === calendar.todaysDate.getDate()) {
el.className = "today";
}
}
}
}
function previousMonth() {
calendar.selectedDate.setMonth(calendar.selectedDate.getMonth() - 1);
calendar.selectedDate.setDate(1);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
}
function nextMonth() {
calendar.selectedDate.setMonth(calendar.selectedDate.getMonth() + 1);
calendar.selectedDate.setDate(1);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
}
function getEventsForMonth() {
var ds = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), 1);
ds.setHours(0, 0, 0, 0);
var bodyRaw = {
"DaysInMonth": daysInMonth().toString(),
"StartEpoch": ds.getTime().toString()
};
$.ajax({
url: "/api/v1/events/list/month",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (json) {
var obj = json;
//Display the event counts on the calendar...
for (var i = 0; i < obj.events.length; i++) {
var d = new Date(obj.events[i].epochStart);
var e = document.getElementById(calendar.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() + "]";
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
var obj = JSON.parse(jqXHR.responseText);
showSnackbar("[ERROR] " + obj.reason);
}
});
}
function getEventsForSelectedDate() {
var ds = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), calendar.selectedDate.getDate());
ds.setHours(0, 0, 0, 0);
var bodyRaw = {
"DaysInMonth": daysInMonth().toString(),
"StartEpoch": ds.getTime().toString()
};
$.ajax({
url: "/api/v1/events/list/date",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (json) {
var obj = json;
//Display the selected day's event details for editing and such.
var container = document.getElementById("event-container");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
for (var i = 0; i < obj.count; i++) {
var event = obj.events[i];
//Create Edit Button
var editButton = document.createElement("button");
editButton.type = "button";
editButton.setAttribute("data-toggle", "modal");
editButton.setAttribute("data-target", "#modal-" + event.id);
editButton.innerHTML = "Edit";
container.appendChild(editButton);
//Create Delete button
var deleteButton = document.createElement("button");
deleteButton.type = "button";
deleteButton.innerHTML = "Delete";
deleteButton.className = "danger";
deleteButton.id = "delete-" + event.id;
deleteButton.onclick = function (ev) {
deleteEvent(this.id)
};
container.appendChild(deleteButton);
container.appendChild(document.createElement("br"));
container.appendChild(document.createElement("br"));
//Create modal container
var modalContainer = document.createElement("div");
modalContainer.className = "modal fade";
modalContainer.id = "modal-" + event.id;
modalContainer.role = "dialog";
container.appendChild(modalContainer);
//Create modal-dialog
var modalDia = document.createElement("div");
modalDia.className = "modal-dialog";
modalContainer.appendChild(modalDia);
//Create Modal Content
var modalCon = document.createElement("div");
modalCon.className = "modal-content";
modalDia.appendChild(modalCon);
//Create modal header and title
var modalHeader = document.createElement("div");
modalHeader.className = "modal-header";
modalCon.appendChild(modalHeader);
var modalTitle = document.createElement("h4");
modalTitle.className = "modal-title";
modalTitle.innerHTML = "Editing Event";
modalHeader.appendChild(modalTitle);
//Create Modal Body
var modalBody = document.createElement("div");
modalBody.className = "modal-body";
modalCon.appendChild(modalBody);
var form = document.createElement("form");
modalBody.appendChild(form);
//Summary
var summaryLabel = document.createElement("label");
summaryLabel.innerHTML = "Summary";
summaryLabel.appendChild(document.createElement("br"));
form.appendChild(summaryLabel);
var summary = document.createElement("input");
summary.name = "summary";
summary.type = "text";
summary.value = event.summary;
summary.id = "editSummary-" + event.id;
summaryLabel.appendChild(summary);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Description
var descriptionLabel = document.createElement("label");
descriptionLabel.innerHTML = "Description";
descriptionLabel.appendChild(document.createElement("br"));
form.appendChild(descriptionLabel);
var description = document.createElement("input");
description.name = "edit-description";
description.type = "text";
description.value = event.description;
description.id = "editDescription-" + event.id;
descriptionLabel.appendChild(description);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Start date and time
var sd = new Date(event.epochStart);
var startLabel = document.createElement("label");
startLabel.innerHTML = "Start Date and Time";
startLabel.appendChild(document.createElement("br"));
form.appendChild(startLabel);
var startDate = document.createElement("input");
startDate.name = "start-date";
startDate.type = "date";
startDate.valueAsDate = sd;
startDate.required = true;
startDate.id = "editStartDate-" + event.id;
startLabel.appendChild(startDate);
var 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.required = true;
startTime.id = "editStartTime-" + event.id;
startLabel.appendChild(startTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//End date and time
var ed = new Date(event.epochEnd);
var endLabel = document.createElement("label");
endLabel.innerHTML = "End Date and Time";
endLabel.appendChild(document.createElement("br"));
form.appendChild(endLabel);
var endDate = document.createElement("input");
endDate.name = "end-date";
endDate.type = "date";
endDate.valueAsDate = ed;
endDate.required = true;
endDate.id = "editEndDate-" + event.id;
endLabel.appendChild(endDate);
var 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.required = true;
endTime.id = "editEndTime-" + event.id;
endLabel.appendChild(endTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Timezone (read only)
var timezoneLabel = document.createElement("label");
timezoneLabel.innerHTML = "Timezone";
timezoneLabel.appendChild(document.createElement("br"));
form.appendChild(timezoneLabel);
var timezone = document.createElement("input");
timezone.name = "timezone";
timezone.type = "text";
timezone.value = event.timezone;
timezone.disabled = true;
timezoneLabel.appendChild(timezone);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Location
var locationLabel = document.createElement("label");
locationLabel.innerHTML = "Location";
locationLabel.appendChild(document.createElement("br"));
form.appendChild(locationLabel);
var location = document.createElement("input");
location.name = "location";
location.type = "text";
location.value = event.location;
location.id = "editLocation-" + event.id;
locationLabel.appendChild(location);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Color
var colorLabel = document.createElement("label");
colorLabel.innerHTML = "Color";
colorLabel.appendChild(document.createElement("br"));
form.appendChild(colorLabel);
var colorSelect = document.createElement("select");
colorSelect.name = "color";
colorSelect.id = "editColor-" + event.id;
colorLabel.appendChild(colorSelect);
for (var c = 0; c < colors().length; c++) {
var option = document.createElement("option");
option.value = colors()[c];
option.text = colors()[c];
option.selected = (event.color === colors()[c]);
colorSelect.appendChild(option);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Recurrence
var recurrenceLabel = document.createElement("label");
recurrenceLabel.innerHTML = "Recurrence";
recurrenceLabel.appendChild(document.createElement("br"));
form.appendChild(recurrenceLabel);
if (event.isParent) {
var enableRecurrence = document.createElement("input");
enableRecurrence.name = "enable-recurrence";
enableRecurrence.type = "checkbox";
enableRecurrence.checked = false;
enableRecurrence.id = "editEnableRecur-" + event.id;
enableRecurrence.onclick = function (ev) {
changeRecurrenceEditDisplays(this);
};
recurrenceLabel.appendChild(enableRecurrence);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Frequency
var frequencyLabel = document.createElement("label");
frequencyLabel.innerHTML = "Recurrence - Frequency";
frequencyLabel.appendChild(document.createElement("br"));
form.appendChild(frequencyLabel);
var freqSelect = document.createElement("select");
freqSelect.name = "frequency";
freqSelect.id = "editFrequency-" + event.id;
frequencyLabel.appendChild(freqSelect);
for (var f = 0; f < frequencies().length; f++) {
var op = document.createElement("option");
op.value = frequencies()[f];
op.text = frequencies()[f];
op.selected = (event.recurrence.frequency === frequencies()[f]);
freqSelect.appendChild(op);
}
freqSelect.disabled = true;
frequencyLabel.appendChild(freqSelect);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Count
var countLabel = document.createElement("label");
countLabel.innerHTML = "Recurrence - Count";
countLabel.appendChild(document.createElement("br"));
form.appendChild(countLabel);
var count = document.createElement("input");
count.name = "count";
count.type = "number";
count.valueAsNumber = parseInt(event.recurrence.count);
count.min = "-1";
count.id = "editCount-" + event.id;
count.disabled = true;
countLabel.appendChild(count);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Interval
var intervalLabel = document.createElement("label");
intervalLabel.innerHTML = "Recurrence - Interval";
intervalLabel.appendChild(document.createElement("br"));
form.appendChild(intervalLabel);
var interval = document.createElement("input");
interval.name = "interval";
interval.type = "number";
interval.valueAsNumber = parseInt(event.recurrence.interval);
interval.min = "1";
interval.id = "editInterval-" + event.id;
interval.disabled = true;
intervalLabel.appendChild(interval);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
} else {
//Cannot edit recurrence
var cannotEditRecur = document.createElement("input");
cannotEditRecur.name = "ignore-cer";
cannotEditRecur.type = "text";
cannotEditRecur.disabled = true;
cannotEditRecur.value = "Cannot edit child";
recurrenceLabel.appendChild(cannotEditRecur);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Image
var imageLabel = document.createElement("label");
imageLabel.innerHTML = "Image";
imageLabel.appendChild(document.createElement("br"));
form.appendChild(imageLabel);
var image = document.createElement("input");
image.name = "image";
image.type = "text";
image.value = event.image;
image.id = "editImage-" + event.id;
imageLabel.appendChild(image);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//ID (readonly) for API
var idLabel = document.createElement("label");
idLabel.innerHTML = "Event ID";
idLabel.appendChild(document.createElement("br"));
form.appendChild(idLabel);
var hiddenId = document.createElement("input");
hiddenId.type = "text";
hiddenId.name = "id";
hiddenId.value = event.id;
hiddenId.id = "editId-" + event.id;
hiddenId.readOnly = true;
idLabel.appendChild(hiddenId);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Submit button
var submit = document.createElement("button");
submit.className = "submit";
submit.type = "button";
submit.id = "editsubmit-" + event.id;
submit.innerHTML = "Update Event!";
submit.onclick = function (ignore) {
updateEvent(this.id);
};
form.appendChild(submit);
//TODO: permission handling for submit button!!!!
//TODO: Reset button
//Create modal footer
var modalFooter = document.createElement("div");
modalFooter.className = "modal-footer";
modalCon.appendChild(modalFooter);
var closeButton = document.createElement("button");
closeButton.type = "button";
closeButton.setAttribute("data-dismiss", "modal");
closeButton.innerHTML = "Close";
modalFooter.appendChild(closeButton);
//Oh my god finally done!!!
}
},
error: function (jqXHR, textStatus, errorThrown) {
var obj = JSON.parse(jqXHR.responseText);
showSnackbar("[ERROR] " + obj.reason);
}
});
}
function selectDate(clickedId) {
var e = document.getElementById(clickedId);
var dateString = e.innerHTML.split("[")[0];
if (dateString !== "") {
var dateNum = parseInt(dateString);
calendar.selectedDate.setDate(dateNum);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
getEventsForSelectedDate();
}
}
function updateEvent(editSubmitId) {
var eventId = editSubmitId.split("-")[1];
var startTimeString = document.getElementById("editStartTime-" + eventId).value.split(":");
var startDate = document.getElementById("editStartDate-" + eventId).valueAsDate;
var endTimeString = document.getElementById("editEndTime-" + eventId).value.split(":");
var endDate = document.getElementById("editEndDate-" + eventId).valueAsDate;
startDate.setHours(parseInt(startTimeString[0]), parseInt(startTimeString[1]), 0, 0);
endDate.setHours(parseInt(endTimeString[0]), parseInt(endTimeString[1]), 0, 0);
var colorElement = document.getElementById("editColor-" + eventId);
var timeOffset = 0;
if (is.firefox() || is.edge() || is.chrome) {
timeOffset = 86400000;
}
if (document.getElementById("editEnableRecur-" + eventId) !== null) {
var freqElement = document.getElementById("editFrequency-" + eventId);
var bodyRaw = {
"id": eventId,
"summary": document.getElementById("editSummary-" + eventId).value,
"description": document.getElementById("editDescription-" + eventId).value,
"location": document.getElementById("editLocation-" + eventId).value,
"image": document.getElementById("editImage-" + eventId).value,
"color": colorElement.options[colorElement.selectedIndex].value,
recurrence: {
"recur": document.getElementById("editEnableRecur-" + eventId).checked,
"frequency": freqElement.options[freqElement.selectedIndex].value,
"count": parseInt(document.getElementById("editCount-" + eventId).value),
"interval": parseInt(document.getElementById("editInterval-" + eventId).value)
},
"epochStart": startDate.getTime() + timeOffset,
"epochEnd": endDate.getTime() + timeOffset
};
} else {
bodyRaw = {
"id": eventId,
"summary": document.getElementById("editSummary-" + eventId).value,
"description": document.getElementById("editDescription-" + eventId).value,
"location": document.getElementById("editLocation-" + eventId).value,
"image": document.getElementById("editImage-" + eventId).value,
"color": colorElement.options[colorElement.selectedIndex].value,
"recurrence": {
"recur": false,
"frequency": "DAILY",
"count": -1,
"interval": 1
},
"epochStart": startDate.getTime() + timeOffset,
"epochEnd": endDate.getTime() + timeOffset
};
}
$.ajax({
url: "/api/v1/events/update",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (data) {
$('#modal-' + bodyRaw.id).modal('hide');
showSnackbar("Event successfully updated!");
setMonth({date: calendar.selectedDate});
getEventsForMonth();
getEventsForSelectedDate();
},
error: function (jqXHR, textStatus, errorThrown) {
var obj = JSON.parse(jqXHR.responseText);
showSnackbar("[ERROR] " + obj.reason);
}
});
}
function createNewEvent() {
var startTimeString = document.getElementById("create-start-time").value.split(":");
var startDate = document.getElementById("create-start-date").valueAsDate;
var endTimeString = document.getElementById("create-end-time").value.split(":");
var endDate = document.getElementById("create-end-date").valueAsDate;
startDate.setHours(parseInt(startTimeString[0]), parseInt(startTimeString[1]), 0, 0);
endDate.setHours(parseInt(endTimeString[0]), parseInt(endTimeString[1]), 0, 0);
var colorElement = document.getElementById("create-color");
var freqElement = document.getElementById("create-frequency");
var timeOffset = 0;
if (is.firefox() || is.edge() || is.chrome()) {
timeOffset = 86400000;
}
var bodyRaw = {
"summary": document.getElementById("create-summary").value,
"description": document.getElementById("create-description").value,
"location": document.getElementById("create-location").value,
"image": document.getElementById("create-image").value,
"color": colorElement.options[colorElement.selectedIndex].value,
"recurrence": {
"recur": document.getElementById("create-enableRecur").checked,
"frequency": freqElement.options[freqElement.selectedIndex].value,
"count": parseInt(document.getElementById("create-count").value),
"interval": parseInt(document.getElementById("create-interval").value)
},
"epochStart": startDate.getTime() + timeOffset,
"epochEnd": endDate.getTime() + timeOffset
};
$.ajax({
url: "/api/v1/events/create",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (data) {
showSnackbar("Event successfully created!");
$('html:not(:animated), body:not(:animated)').animate({
scrollTop: $("#calendar").offset().top
}, 2000);
document.getElementById("create-form").reset();
setMonth({date: calendar.selectedDate});
getEventsForMonth();
getEventsForSelectedDate();
},
error: function (jqXHR, textStatus, errorThrown) {
var obj = JSON.parse(jqXHR.responseText);
showSnackbar("[ERROR] " + obj.reason);
}
});
}
function deleteEvent(clickedId) {
var eventId = clickedId.replace("delete-", "");
var bodyRaw = {"id": eventId};
$.ajax({
url: "/api/v1/events/delete",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (data) {
showSnackbar("Successfully deleted event!");
setMonth({date: calendar.selectedDate});
getEventsForMonth();
getEventsForSelectedDate();
},
error: function (jqXHR, textStatus, errorThrown) {
var obj = JSON.parse(jqXHR.responseText);
showSnackbar("[ERROR] " + obj.reason);
}
});
}
function init() {
setMonth({date: calendar.todaysDate});
getEventsForMonth();
}
@@ -1,535 +0,0 @@
var calendar = {
todaysDate: new Date(),
selectedDate: new Date(),
displays: []
};
function getMonthName(index) {
return ["January", "February",
"March", "April",
"May", "June",
"July", "August",
"September", "October",
"November", "December"][index];
}
function getDayName(index) {
return ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday"][index];
}
function dateDisplays() {
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"];
}
function colors() {
return ["MELROSE", "RIPTIDE", "MAUVE", "TANGERINE",
"DANDELION", "MAC_AND_CHEESE", "TURQUOISE",
"MERCURY", "BLUE", "GREED", "RED", "NONE"];
}
function frequencies() {
return ["DAILY", "WEEKLY", "MONTHLY", "YEARLY"];
}
function dateDisplaysToChange(str) {
return dateDisplays().slice(dateDisplays().indexOf(str), dateDisplays().length - 1);
}
function findFirstDayOfMonthPosition() {
var firstDay = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), 1);
var firstDayName = 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";
}
}
function daysInMonth() {
return new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth() + 1, 0).getDate();
}
function changeRecurrenceEditDisplays(checkbox) {
var eventId = checkbox.id.split("-")[1];
if (checkbox.checked) {
//Enable recur input
document.getElementById("editFrequency-" + eventId).disabled = false;
document.getElementById("editCount-" + eventId).disabled = false;
document.getElementById("editInterval-" + eventId).disabled = false;
} else {
//Disable recur input
document.getElementById("editFrequency-" + eventId).disabled = true;
document.getElementById("editCount-" + eventId).disabled = true;
document.getElementById("editInterval-" + eventId).disabled = true;
}
}
function setMonth(parameters) {
var date = parameters.date;
document.getElementById("month-display").innerHTML = getMonthName(date.getMonth()) + " " + date.getFullYear();
calendar.displays = [];
var tcc = dateDisplays();
for (var ii = 0; ii < tcc.length; ii++) {
var e = document.getElementById(tcc[ii]);
e.innerHTML = "";
e.className = "";
}
var tc = dateDisplaysToChange(findFirstDayOfMonthPosition());
var count = daysInMonth();
for (var i = 0; i < tc.length; i++) {
var d = i + 1;
if (d <= count) {
var el = document.getElementById(tc[i]);
el.innerHTML = d + "";
calendar.displays[d] = tc[i];
var thisDate = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), d);
if (d === calendar.selectedDate.getDate()) {
el.className = "selected";
}
if (thisDate.getMonth() === calendar.todaysDate.getMonth()
&& thisDate.getFullYear() === calendar.todaysDate.getFullYear()
&& thisDate.getDate() === calendar.todaysDate.getDate()) {
el.className = "today";
}
}
}
}
function previousMonth() {
calendar.selectedDate.setMonth(calendar.selectedDate.getMonth() - 1);
calendar.selectedDate.setDate(1);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
}
function nextMonth() {
calendar.selectedDate.setMonth(calendar.selectedDate.getMonth() + 1);
calendar.selectedDate.setDate(1);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
}
function getEventsForMonth() {
var ds = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), 1);
ds.setHours(0, 0, 0, 0);
var bodyRaw = {
"DaysInMonth": daysInMonth().toString(),
"StartEpoch": ds.getTime().toString()
};
$.ajax({
url: "/api/v1/events/list/month",
headers: {
"Content-Type": "application/json",
"Authorization": "EMBEDDED"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (json) {
var obj = json;
//Display the event counts on the calendar...
for (var i = 0; i < obj.events.length; i++) {
var d = new Date(obj.events[i].epochStart);
var e = document.getElementById(calendar.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() + "]";
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
showSnackbar("[ERROR] " + jqXHR.responseText);
}
});
}
function getEventsForSelectedDate() {
var ds = new Date(calendar.selectedDate.getFullYear(), calendar.selectedDate.getMonth(), calendar.selectedDate.getDate());
ds.setHours(0, 0, 0, 0);
var bodyRaw = {
"DaysInMonth": daysInMonth().toString(),
"StartEpoch": ds.getTime().toString()
};
$.ajax({
url: "/api/v1/events/list/date",
headers: {
"Content-Type": "application/json",
"Authorization": "EMBEDDED"
},
method: "POST",
dataType: "json",
data: JSON.stringify(bodyRaw),
success: function (json) {
var obj = json;
//Display the selected day's event details for editing and such.
var container = document.getElementById("event-container");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
for (var i = 0; i < obj.count; i++) {
var event = obj.events[i];
//Create View Button
var viewButton = document.createElement("button");
viewButton.type = "button";
viewButton.setAttribute("data-toggle", "modal");
viewButton.setAttribute("data-target", "#modal-" + event.id);
viewButton.innerHTML = "View Event With ID: " + event.id;
container.appendChild(viewButton);
container.appendChild(document.createElement("br"));
container.appendChild(document.createElement("br"));
//Create modal container
var modalContainer = document.createElement("div");
modalContainer.className = "modal fade";
modalContainer.id = "modal-" + event.id;
modalContainer.role = "dialog";
container.appendChild(modalContainer);
//Create modal-dialog
var modalDia = document.createElement("div");
modalDia.className = "modal-dialog";
modalContainer.appendChild(modalDia);
//Create Modal Content
var modalCon = document.createElement("div");
modalCon.className = "modal-content";
modalDia.appendChild(modalCon);
//Create modal header and title
var modalHeader = document.createElement("div");
modalHeader.className = "modal-header";
modalCon.appendChild(modalHeader);
var modalTitle = document.createElement("h4");
modalTitle.className = "modal-title";
modalTitle.innerHTML = "Viewing Event";
modalHeader.appendChild(modalTitle);
//Create Modal Body
var modalBody = document.createElement("div");
modalBody.className = "modal-body";
modalCon.appendChild(modalBody);
var form = document.createElement("form");
modalBody.appendChild(form);
//Summary
var summaryLabel = document.createElement("label");
summaryLabel.innerHTML = "Summary";
summaryLabel.appendChild(document.createElement("br"));
form.appendChild(summaryLabel);
var summary = document.createElement("input");
summary.name = "summary";
summary.type = "text";
summary.value = event.summary;
summary.id = "editSummary-" + event.id;
summaryLabel.appendChild(summary);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Description
var descriptionLabel = document.createElement("label");
descriptionLabel.innerHTML = "Description";
descriptionLabel.appendChild(document.createElement("br"));
form.appendChild(descriptionLabel);
var description = document.createElement("input");
description.name = "edit-description";
description.type = "text";
description.value = event.description;
description.id = "editDescription-" + event.id;
descriptionLabel.appendChild(description);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Start date and time
var sd = new Date(event.epochStart);
var startLabel = document.createElement("label");
startLabel.innerHTML = "Start Date and Time";
startLabel.appendChild(document.createElement("br"));
form.appendChild(startLabel);
var startDate = document.createElement("input");
startDate.name = "start-date";
startDate.type = "date";
startDate.valueAsDate = sd;
startDate.id = "editStartDate-" + event.id;
startLabel.appendChild(startDate);
var 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.id;
startLabel.appendChild(startTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//End date and time
var ed = new Date(event.epochEnd);
var endLabel = document.createElement("label");
endLabel.innerHTML = "End Date and Time";
endLabel.appendChild(document.createElement("br"));
form.appendChild(endLabel);
var endDate = document.createElement("input");
endDate.name = "end-date";
endDate.type = "date";
endDate.valueAsDate = ed;
endDate.id = "editEndDate-" + event.id;
endLabel.appendChild(endDate);
var 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.id;
endLabel.appendChild(endTime);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Timezone (read only)
var timezoneLabel = document.createElement("label");
timezoneLabel.innerHTML = "Timezone";
timezoneLabel.appendChild(document.createElement("br"));
form.appendChild(timezoneLabel);
var timezone = document.createElement("input");
timezone.name = "timezone";
timezone.type = "text";
timezone.value = event.timezone;
timezone.disabled = true;
timezoneLabel.appendChild(timezone);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Location
var locationLabel = document.createElement("label");
locationLabel.innerHTML = "Location";
locationLabel.appendChild(document.createElement("br"));
form.appendChild(locationLabel);
var location = document.createElement("input");
location.name = "location";
location.type = "text";
location.value = event.location;
location.id = "editLocation-" + event.id;
locationLabel.appendChild(location);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Color
var colorLabel = document.createElement("label");
colorLabel.innerHTML = "Color";
colorLabel.appendChild(document.createElement("br"));
form.appendChild(colorLabel);
var colorSelect = document.createElement("select");
colorSelect.name = "color";
colorSelect.id = "editColor-" + event.id;
colorLabel.appendChild(colorSelect);
for (var c = 0; c < colors().length; c++) {
var option = document.createElement("option");
option.value = colors()[c];
option.text = colors()[c];
option.selected = (event.color === colors()[c]);
colorSelect.appendChild(option);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Recurrence
var recurrenceLabel = document.createElement("label");
recurrenceLabel.innerHTML = "Recurrence";
recurrenceLabel.appendChild(document.createElement("br"));
form.appendChild(recurrenceLabel);
if (event.isParent) {
var enableRecurrence = document.createElement("input");
enableRecurrence.name = "enable-recurrence";
enableRecurrence.type = "checkbox";
enableRecurrence.checked = false;
enableRecurrence.id = "editEnableRecur-" + event.id;
enableRecurrence.onclick = function (ev) {
changeRecurrenceEditDisplays(this);
};
recurrenceLabel.appendChild(enableRecurrence);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Frequency
var frequencyLabel = document.createElement("label");
frequencyLabel.innerHTML = "Recurrence - Frequency";
frequencyLabel.appendChild(document.createElement("br"));
form.appendChild(frequencyLabel);
var freqSelect = document.createElement("select");
freqSelect.name = "frequency";
freqSelect.id = "editFrequency-" + event.id;
frequencyLabel.appendChild(freqSelect);
for (var f = 0; f < frequencies().length; f++) {
var op = document.createElement("option");
op.value = frequencies()[f];
op.text = frequencies()[f];
op.selected = (event.recurrence.frequency === frequencies()[f]);
freqSelect.appendChild(op);
}
freqSelect.disabled = true;
frequencyLabel.appendChild(freqSelect);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Count
var countLabel = document.createElement("label");
countLabel.innerHTML = "Recurrence - Count";
countLabel.appendChild(document.createElement("br"));
form.appendChild(countLabel);
var count = document.createElement("input");
count.name = "count";
count.type = "number";
count.valueAsNumber = parseInt(event.recurrence.count);
count.min = "-1";
count.id = "editCount-" + event.id;
count.disabled = true;
countLabel.appendChild(count);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Interval
var intervalLabel = document.createElement("label");
intervalLabel.innerHTML = "Recurrence - Interval";
intervalLabel.appendChild(document.createElement("br"));
form.appendChild(intervalLabel);
var interval = document.createElement("input");
interval.name = "interval";
interval.type = "number";
interval.valueAsNumber = parseInt(event.recurrence.interval);
interval.min = "1";
interval.id = "editInterval-" + event.id;
interval.disabled = true;
intervalLabel.appendChild(interval);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
} else {
//Cannot edit recurrence
var cannotEditRecur = document.createElement("input");
cannotEditRecur.name = "ignore-cer";
cannotEditRecur.type = "text";
cannotEditRecur.disabled = true;
cannotEditRecur.value = "Cannot edit child";
recurrenceLabel.appendChild(cannotEditRecur);
}
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Image
var imageLabel = document.createElement("label");
imageLabel.innerHTML = "Image";
imageLabel.appendChild(document.createElement("br"));
form.appendChild(imageLabel);
var image = document.createElement("input");
image.name = "image";
image.type = "text";
image.value = event.image;
image.id = "editImage-" + event.id;
imageLabel.appendChild(image);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//ID (readonly) for API
var idLabel = document.createElement("label");
idLabel.innerHTML = "Event ID";
idLabel.appendChild(document.createElement("br"));
form.appendChild(idLabel);
var hiddenId = document.createElement("input");
hiddenId.type = "text";
hiddenId.name = "id";
hiddenId.value = event.id;
hiddenId.id = "editId-" + event.id;
hiddenId.readOnly = true;
idLabel.appendChild(hiddenId);
form.appendChild(document.createElement("br"));
form.appendChild(document.createElement("br"));
//Create modal footer
var modalFooter = document.createElement("div");
modalFooter.className = "modal-footer";
modalCon.appendChild(modalFooter);
var closeButton = document.createElement("button");
closeButton.type = "button";
closeButton.setAttribute("data-dismiss", "modal");
closeButton.innerHTML = "Close";
modalFooter.appendChild(closeButton);
//Oh my god finally done!!!
}
},
error: function (jqXHR, textStatus, errorThrown) {
showSnackbar("[ERROR] " + jqXHR.responseText);
}
});
}
function selectDate(clickedId) {
var e = document.getElementById(clickedId);
var dateString = e.innerHTML.split("[")[0];
if (dateString !== "") {
var dateNum = parseInt(dateString);
calendar.selectedDate.setDate(dateNum);
setMonth({date: calendar.selectedDate});
getEventsForMonth();
getEventsForSelectedDate();
}
}
function init() {
setMonth({date: calendar.todaysDate});
getEventsForMonth();
}
@@ -1,13 +0,0 @@
function showSnackbar(textToDisplay) {
// Get the snackbar DIV
let x = document.getElementById("snackbar");
x.innerHTML = textToDisplay;
// Add the "show" class to DIV
x.className = "show";
// After 3 seconds, remove the show class from DIV
setTimeout(function () {
x.className = x.className.replace("show", "");
}, 3000);
}
@@ -1,874 +0,0 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*!
* Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.3/customize/?id=b6e8defd34fe1e9824c7f81aba29e1a5)
* Config saved to config.json and https://gist.github.com/b6e8defd34fe1e9824c7f81aba29e1a5
*/
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
.img-responsive {
display: block;
max-width: 100%;
height: auto;
}
.img-rounded {
border-radius: 6px;
}
.img-thumbnail {
padding: 4px;
line-height: 1.42857143;
background-color: #ffffff;
border: 1px solid #dddddd;
border-radius: 4px;
-webkit-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
display: inline-block;
max-width: 100%;
height: auto;
}
.img-circle {
border-radius: 50%;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #5566c2;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
[role="button"] {
cursor: pointer;
}
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn:focus,
.btn:active:focus,
.btn.active:focus,
.btn.focus,
.btn:active.focus,
.btn.active.focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.btn:hover,
.btn:focus,
.btn.focus {
color: #333333;
text-decoration: none;
}
.btn:active,
.btn.active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.btn.disabled,
.btn[disabled],
fieldset[disabled] .btn {
cursor: not-allowed;
opacity: 0.65;
filter: alpha(opacity=65);
-webkit-box-shadow: none;
box-shadow: none;
}
a.btn.disabled,
fieldset[disabled] a.btn {
pointer-events: none;
}
.btn-default {
color: #333333;
background-color: #ffffff;
border-color: #cccccc;
}
.btn-default:focus,
.btn-default.focus {
color: #333333;
background-color: #e6e6e6;
border-color: #8c8c8c;
}
.btn-default:hover {
color: #333333;
background-color: #e6e6e6;
border-color: #adadad;
}
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
color: #333333;
background-color: #e6e6e6;
border-color: #adadad;
}
.btn-default:active:hover,
.btn-default.active:hover,
.open > .dropdown-toggle.btn-default:hover,
.btn-default:active:focus,
.btn-default.active:focus,
.open > .dropdown-toggle.btn-default:focus,
.btn-default:active.focus,
.btn-default.active.focus,
.open > .dropdown-toggle.btn-default.focus {
color: #333333;
background-color: #d4d4d4;
border-color: #8c8c8c;
}
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
background-image: none;
}
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus {
background-color: #ffffff;
border-color: #cccccc;
}
.btn-default .badge {
color: #ffffff;
background-color: #333333;
}
.btn-primary {
color: #ffffff;
background-color: #337ab7;
border-color: #2e6da4;
}
.btn-primary:focus,
.btn-primary.focus {
color: #ffffff;
background-color: #286090;
border-color: #122b40;
}
.btn-primary:hover {
color: #ffffff;
background-color: #286090;
border-color: #204d74;
}
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
color: #ffffff;
background-color: #286090;
border-color: #204d74;
}
.btn-primary:active:hover,
.btn-primary.active:hover,
.open > .dropdown-toggle.btn-primary:hover,
.btn-primary:active:focus,
.btn-primary.active:focus,
.open > .dropdown-toggle.btn-primary:focus,
.btn-primary:active.focus,
.btn-primary.active.focus,
.open > .dropdown-toggle.btn-primary.focus {
color: #ffffff;
background-color: #204d74;
border-color: #122b40;
}
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
background-image: none;
}
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus {
background-color: #337ab7;
border-color: #2e6da4;
}
.btn-primary .badge {
color: #337ab7;
background-color: #ffffff;
}
.btn-success {
color: #ffffff;
background-color: #5cb85c;
border-color: #4cae4c;
}
.btn-success:focus,
.btn-success.focus {
color: #ffffff;
background-color: #449d44;
border-color: #255625;
}
.btn-success:hover {
color: #ffffff;
background-color: #449d44;
border-color: #398439;
}
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
color: #ffffff;
background-color: #449d44;
border-color: #398439;
}
.btn-success:active:hover,
.btn-success.active:hover,
.open > .dropdown-toggle.btn-success:hover,
.btn-success:active:focus,
.btn-success.active:focus,
.open > .dropdown-toggle.btn-success:focus,
.btn-success:active.focus,
.btn-success.active.focus,
.open > .dropdown-toggle.btn-success.focus {
color: #ffffff;
background-color: #398439;
border-color: #255625;
}
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
background-image: none;
}
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus {
background-color: #5cb85c;
border-color: #4cae4c;
}
.btn-success .badge {
color: #5cb85c;
background-color: #ffffff;
}
.btn-info {
color: #ffffff;
background-color: #5bc0de;
border-color: #46b8da;
}
.btn-info:focus,
.btn-info.focus {
color: #ffffff;
background-color: #31b0d5;
border-color: #1b6d85;
}
.btn-info:hover {
color: #ffffff;
background-color: #31b0d5;
border-color: #269abc;
}
.btn-info:active,
.btn-info.active,
.open > .dropdown-toggle.btn-info {
color: #ffffff;
background-color: #31b0d5;
border-color: #269abc;
}
.btn-info:active:hover,
.btn-info.active:hover,
.open > .dropdown-toggle.btn-info:hover,
.btn-info:active:focus,
.btn-info.active:focus,
.open > .dropdown-toggle.btn-info:focus,
.btn-info:active.focus,
.btn-info.active.focus,
.open > .dropdown-toggle.btn-info.focus {
color: #ffffff;
background-color: #269abc;
border-color: #1b6d85;
}
.btn-info:active,
.btn-info.active,
.open > .dropdown-toggle.btn-info {
background-image: none;
}
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled.focus,
.btn-info[disabled].focus,
fieldset[disabled] .btn-info.focus {
background-color: #5bc0de;
border-color: #46b8da;
}
.btn-info .badge {
color: #5bc0de;
background-color: #ffffff;
}
.btn-warning {
color: #ffffff;
background-color: #f0ad4e;
border-color: #eea236;
}
.btn-warning:focus,
.btn-warning.focus {
color: #ffffff;
background-color: #ec971f;
border-color: #985f0d;
}
.btn-warning:hover {
color: #ffffff;
background-color: #ec971f;
border-color: #d58512;
}
.btn-warning:active,
.btn-warning.active,
.open > .dropdown-toggle.btn-warning {
color: #ffffff;
background-color: #ec971f;
border-color: #d58512;
}
.btn-warning:active:hover,
.btn-warning.active:hover,
.open > .dropdown-toggle.btn-warning:hover,
.btn-warning:active:focus,
.btn-warning.active:focus,
.open > .dropdown-toggle.btn-warning:focus,
.btn-warning:active.focus,
.btn-warning.active.focus,
.open > .dropdown-toggle.btn-warning.focus {
color: #ffffff;
background-color: #d58512;
border-color: #985f0d;
}
.btn-warning:active,
.btn-warning.active,
.open > .dropdown-toggle.btn-warning {
background-image: none;
}
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled.focus,
.btn-warning[disabled].focus,
fieldset[disabled] .btn-warning.focus {
background-color: #f0ad4e;
border-color: #eea236;
}
.btn-warning .badge {
color: #f0ad4e;
background-color: #ffffff;
}
.btn-danger {
color: #ffffff;
background-color: #d9534f;
border-color: #d43f3a;
}
.btn-danger:focus,
.btn-danger.focus {
color: #ffffff;
background-color: #c9302c;
border-color: #761c19;
}
.btn-danger:hover {
color: #ffffff;
background-color: #c9302c;
border-color: #ac2925;
}
.btn-danger:active,
.btn-danger.active,
.open > .dropdown-toggle.btn-danger {
color: #ffffff;
background-color: #c9302c;
border-color: #ac2925;
}
.btn-danger:active:hover,
.btn-danger.active:hover,
.open > .dropdown-toggle.btn-danger:hover,
.btn-danger:active:focus,
.btn-danger.active:focus,
.open > .dropdown-toggle.btn-danger:focus,
.btn-danger:active.focus,
.btn-danger.active.focus,
.open > .dropdown-toggle.btn-danger.focus {
color: #ffffff;
background-color: #ac2925;
border-color: #761c19;
}
.btn-danger:active,
.btn-danger.active,
.open > .dropdown-toggle.btn-danger {
background-image: none;
}
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled.focus,
.btn-danger[disabled].focus,
fieldset[disabled] .btn-danger.focus {
background-color: #d9534f;
border-color: #d43f3a;
}
.btn-danger .badge {
color: #d9534f;
background-color: #ffffff;
}
.btn-link {
color: #337ab7;
font-weight: normal;
border-radius: 0;
}
.btn-link,
.btn-link:active,
.btn-link.active,
.btn-link[disabled],
fieldset[disabled] .btn-link {
background-color: transparent;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-link,
.btn-link:hover,
.btn-link:focus,
.btn-link:active {
border-color: transparent;
}
.btn-link:hover,
.btn-link:focus {
color: #23527c;
text-decoration: underline;
background-color: transparent;
}
.btn-link[disabled]:hover,
fieldset[disabled] .btn-link:hover,
.btn-link[disabled]:focus,
fieldset[disabled] .btn-link:focus {
color: #777777;
text-decoration: none;
}
.btn-lg {
padding: 10px 16px;
font-size: 18px;
line-height: 1.3333333;
border-radius: 6px;
}
.btn-sm {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
.btn-xs {
padding: 1px 5px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
.btn-block {
display: block;
width: 100%;
}
.btn-block + .btn-block {
margin-top: 5px;
}
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%;
}
.fade {
opacity: 0;
-webkit-transition: opacity 0.15s linear;
-o-transition: opacity 0.15s linear;
transition: opacity 0.15s linear;
}
.fade.in {
opacity: 1;
}
.collapse {
display: none;
}
.collapse.in {
display: block;
}
tr.collapse.in {
display: table-row;
}
tbody.collapse.in {
display: table-row-group;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition-property: height, visibility;
-o-transition-property: height, visibility;
transition-property: height, visibility;
-webkit-transition-duration: 0.35s;
-o-transition-duration: 0.35s;
transition-duration: 0.35s;
-webkit-transition-timing-function: ease;
-o-transition-timing-function: ease;
transition-timing-function: ease;
}
.close {
float: right;
font-size: 21px;
font-weight: bold;
line-height: 1;
color: #000000;
text-shadow: 0 1px 0 #ffffff;
opacity: 0.2;
filter: alpha(opacity=20);
}
.close:hover,
.close:focus {
color: #000000;
text-decoration: none;
cursor: pointer;
opacity: 0.5;
filter: alpha(opacity=50);
}
button.close {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
}
.modal-open {
overflow: hidden;
}
.modal {
display: none;
overflow: hidden;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1050;
-webkit-overflow-scrolling: touch;
outline: 0;
}
.modal.fade .modal-dialog {
-webkit-transform: translate(0, -25%);
-ms-transform: translate(0, -25%);
-o-transform: translate(0, -25%);
transform: translate(0, -25%);
-webkit-transition: -webkit-transform 0.3s ease-out;
-o-transition: -o-transform 0.3s ease-out;
transition: transform 0.3s ease-out;
}
.modal.in .modal-dialog {
-webkit-transform: translate(0, 0);
-ms-transform: translate(0, 0);
-o-transform: translate(0, 0);
transform: translate(0, 0);
}
.modal-open .modal {
overflow-x: hidden;
overflow-y: auto;
}
.modal-dialog {
position: relative;
width: auto;
margin: 10px;
}
.modal-content {
position: relative;
background-color: #3c3d41;
border: 1px solid #5566c2;
border-radius: 6px;
-webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
-webkit-background-clip: padding-box;
background-clip: padding-box;
outline: 0;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
background-color: #000000;
}
.modal-backdrop.fade {
opacity: 0;
filter: alpha(opacity=0);
}
.modal-backdrop.in {
opacity: 0.5;
filter: alpha(opacity=50);
}
.modal-header {
padding: 15px;
border-bottom: 1px solid #5566c2;
}
.modal-header .close {
margin-top: -2px;
}
.modal-title {
margin: 0;
line-height: 1.42857143;
}
.modal-body {
position: relative;
padding: 15px;
}
.modal-footer {
padding: 15px;
text-align: right;
border-top: 1px solid #5566c2;
}
.modal-footer .btn + .btn {
margin-left: 5px;
margin-bottom: 0;
}
.modal-footer .btn-group .btn + .btn {
margin-left: -1px;
}
.modal-footer .btn-block + .btn-block {
margin-left: 0;
}
.modal-scrollbar-measure {
position: absolute;
top: -9999px;
width: 50px;
height: 50px;
overflow: scroll;
}
@media (min-width: 768px) {
.modal-dialog {
width: 600px;
margin: 30px auto;
}
.modal-content {
-webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.modal-sm {
width: 300px;
}
}
@media (min-width: 992px) {
.modal-lg {
width: 900px;
}
}
.clearfix:before,
.clearfix:after,
.modal-header:before,
.modal-header:after,
.modal-footer:before,
.modal-footer:after {
content: " ";
display: table;
}
.clearfix:after,
.modal-header:after,
.modal-footer:after {
clear: both;
}
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
.pull-right {
float: right !important;
}
.pull-left {
float: left !important;
}
.hide {
display: none !important;
}
.show {
display: block !important;
}
.invisible {
visibility: hidden;
}
.text-hide {
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.hidden {
display: none !important;
}
.affix {
position: fixed;
}
@@ -1,31 +0,0 @@
td {
text-align: center;
}
td:hover {
background-color: #ef0813;
}
td.selected {
background-color: #e8810b;
}
td.today {
background-color: #efcb15;
}
th {
text-align: center;
background-color: white;
border: transparent;
width: 75px;
}
th.nav:hover {
background-color: #ef0813;
}
tr {
height: 75px;
width: 75px;
}
@@ -1,20 +0,0 @@
td {
text-align: center;
}
th {
text-align: center;
background-color: #b9b9b9;
border: transparent;
}
pre.code {
background-color: #061d2d;
color: white;
border: #2a292e 1px solid;
text-align: left;
font-family: monospace;
border-radius: 15px;
padding: 1%;
overflow: auto;
}
@@ -1,30 +0,0 @@
/* Handle input type number */
/* Remove controls from Firefox */
input[type=number] {
-moz-appearance: textfield;
}
/* Re-applies the controls on :hover and :focus */
input[type="number"]:hover,
input[type="number"]:focus {
-moz-appearance: textfield;
}
/* Remove controls from Safari and Chrome */
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0; /* Removes leftover margin */
}
/* Adds a box around the numeric value in Safari and Chrome */
input[type=number]::-webkit-textfield-decoration-container {
border: 1px #1b1f20 solid;
}
html:not([dir="rtl"]) input {
text-align: left;
}
/* End of handling input type number */
@@ -1,373 +0,0 @@
/* The basics */
html {
position: relative;
min-height: 100%;
overflow: auto;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
background: #242428;
min-height: 100%;
margin: 0 0 25px; /* bottom = footer height */
overflow-x: hidden;
}
footer {
position: absolute;
bottom: 0;
background: #1b1f20;
color: white;
width: 100%;
}
h1, h2, h3, h4, h5, h6 {
text-align: center;
color: #5566c2;
}
h1 {
font-size: 32pt;
}
h2 {
font-size: 28pt;
}
h3 {
font-size: 24pt
}
h4, h5, h6 {
font-size: 20pt;
}
p {
font-size: 18pt;
color: white;
margin: 20px;
}
footer p {
font-size: 12pt;
}
button {
font-size: 18px;
background-color: #5566c2;
color: white;
padding: 10px;
border: 2px black;
margin: 10px;
width: auto;
height: auto;
}
button:hover {
color: black;
}
button.danger {
font-size: 18px;
background-color: #ef0813;
color: white;
padding: 10px;
border: 2px black;
margin: 10px;
width: auto;
height: auto;
}
button.danger:hover {
color: #ef0813;
background-color: white;
}
hr {
color: #5566c2;
background-color: #5566c2;
border-color: transparent;
height: 1px;
max-width: 100%;
width: auto;
}
table {
max-width: 820px;
border: #ef0813 2px;
margin: auto;
}
td {
color: white;
}
textarea {
resize: none;
}
select {
border: 1px solid black;
border-radius: 2px;
padding-top: 6px;
padding-bottom: 6px;
width: 200px;
}
input.submit {
padding-top: 8px;
padding-bottom: 8px;
border: 1px solid #5566c2;
background: #5566c2;
}
input.submit:hover {
padding-top: 8px;
padding-bottom: 8px;
border: 1px solid white;
background: white;
color: black;
}
input.reset {
padding-top: 8px;
padding-bottom: 8px;
border: 1px solid black;
background: #ef0813;
color: white;
}
input.reset:hover {
padding-top: 8px;
padding-bottom: 8px;
border: 1px solid white;
background: white;
color: black;
}
label {
color: white;
}
/* Wrappers */
#content {
margin-left: 10%;
margin-right: 10%;
margin-bottom: 5%;
background-color: #3c3d41;
padding: 10px;
text-align: center;
display: flow-root;
}
.image-wrapper {
position: center;
margin: 10px;
display: inline-flex;
}
.image-wrapper img {
width: 100%;
display: inline-block;
}
.quote-block {
width: auto;
display: inline-flex;
position: center;
}
.quote {
margin: 5px;
padding: 5px;
float: left;
display: inline-block;
background: #bcbcbc;
border-radius: 6px;
border: 4px #5566c2;
max-width: 400px;
height: auto;
}
.quote p {
text-align: center;
color: #242428;
}
.quote h4 {
color: #ef0813;
}
#side-nav {
margin-left: 0;
margin-right: 10px;
margin-bottom: auto;
background-color: #3c3d41;
padding: 10px;
text-align: center;
float: left;
border: #5566c2 2px solid;
border-radius: 10px;
}
.announcement-edit-container-all {
display: inline-block;
}
.announcement-edit-container-single {
display: block;
margin-top: 2px;
margin-bottom: 2px;
}
/* Navigation bar */
.top-nav {
overflow: hidden;
background-color: #5566c2;
}
.top-nav h1 {
float: left;
color: white;
text-align: center;
margin: auto 15px;
}
.top-nav h1:hover {
color: #090809;
}
.top-nav a.title {
padding: 0;
margin: auto 15px;
}
.top-nav a.title:hover {
color: #090809;
background: transparent;
}
.top-nav a {
float: left;
color: white;
text-align: center;
padding: 15px 18px;
font-size: 20px;
text-decoration: none;
}
.top-nav a:hover {
background-color: white;
color: #090809;
}
.top-nav a.active {
background-color: #3c3d41;
color: white;
}
.top-nav a.account {
float: right;
text-align: center;
padding: 15px 18px;
font-size: 20px;
text-decoration: none;
}
.top-nav p.account {
float: right;
color: white;
text-align: center;
padding: 15px 18px;
font-size: 20px;
text-decoration: none;
}
/* snackbar */
#snackbar {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
left: 50%;
bottom: 30px;
}
/* Show the snackbar*/
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
animation: fadein 0.5s, fadeout 0.5s 2.5s;
}
/* Animations to fade the snackbar in and out */
@-webkit-keyframes fadein {
from {
bottom: 0;
opacity: 0;
}
to {
bottom: 30px;
opacity: 1;
}
}
@keyframes fadein {
from {
bottom: 0;
opacity: 0;
}
to {
bottom: 30px;
opacity: 1;
}
}
@-webkit-keyframes fadeout {
from {
bottom: 30px;
opacity: 1;
}
to {
bottom: 0;
opacity: 0;
}
}
@keyframes fadeout {
from {
bottom: 30px;
opacity: 1;
}
to {
bottom: 0;
opacity: 0;
}
}
@@ -1,237 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>About - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a class="active" href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>DisCal Bot - About</h1>
<div id="invite">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/logos/discord-logo-white.png" style="max-width: 300px; max-height: 300px;">
</div>
<h3>Invite To Discord Server</h3>
<p>
Seen enough of this amazing bot? Add it to your Discord server by clicking the button below!
<br><br>
Once you add, scroll down to the "DisCal Setup" Button and click it!
</p>
<a href="https://discordapp.com/oauth2/authorize?client_id=265523588918935552&scope=bot&permissions=201845824redirect_uri=https%3A%2F%2Fwww.discalbot.com%2Fpages%2Fsetup.html"
target="_blank">
<button>Invite to Server Now!</button>
</a>
<p>
Need to see more to convince you? Scroll down the page! You'll learn just how useful DisCal really
is and why you need it!
</p>
</div>
<hr>
<div id="commands">
<div class="image-wrapper" style="float: right">
<img src="/assets/images/examples/DisCal-Event-Creation.jpg"
style="max-width: 300px; max-height: 300px;">
</div>
<h3>Commands</h3>
<p>
DisCal is designed to be intuitive and powerful.
<br><br><br>
Discal uses simple to understand commands. With a customizable prefix, ability to mention DisCal
directly, and more DisCal's command system is designed for users in mind.
<br><br><br>
Because of this, DisCal has a ton of commands that allow you to fully utilize it! View all of the
documentation on the commands for DisCal by clicking the button below!
</p>
<a href="/pages/commands.html">
<button>View Commands</button>
</a>
</div>
<hr>
<div id="trello">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/other/discal-trello.png" style="max-width: 450px; max-height: 300px;">
</div>
<h3>Trello & To-Do</h3>
<p>
DisCal is meant to be useful, collaborative, and easy to use.
<br><br><br>
We use Trello to track everything we are currently working on. This way, you can see what our
progress is, comment on what you want us to work on, or add suggestions and requests.
<br><br><br>
</p>
<a href="https://trello.com/b/OuFo5aXu/discal" target="_blank">
<button>Check out DisCal's Trello</button>
</a>
</div>
<hr>
<div id="support">
<div class="image-wrapper" style="float: right">
<img src="/assets/images/other/support-server.png" style="max-width: 450px; max-height: 300px;">
</div>
<h3>Official Support Server</h3>
<p>
If DisCal was meant to be useful, so are we! Join our official DisCal Discord server for extra info
and help.
<br><br><br>
Need help with something? Visit our support channel!
<br><br>
Want to request a feature we somehow didn't think to add? Send us a message in our feature request
channel!
<br><br><br>
Just want to be part of the amazing community using this Bot? Join the discord!
</p>
<a href="https://discord.gg/2TFqyuy" target="_blank">
<button>Join The Support Server</button>
</a>
</div>
<hr>
<div id="source">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/other/discal-github.jpg" style="max-width: 450px; max-height: 300px;">
</div>
<h3>Source Code</h3>
<p>
DisCal was built upon open source APIs. It wouldn't be fair if we didn't open source DisCal.
<br><br><br>
All of the source code behind this amazing bot can be found on the GitHub repo linked below!
<br><br><br>
We encourage those who can to fork the repository and help code DisCal! We are community driven and
really love any help we can get. Even just a simple typo fix.
<br><br>
And of course, we will credit you with the changes and even give you a special contributor role!!!
</p>
<a href="https://github.com/NovaFox161/DisCal-Discord-Bot" target="_blank">
<button>DisCal GitHub</button>
</a>
</div>
<hr>
<div id="patreon">
<div class="image-wrapper" style="float: right">
<img src="/assets/images/other/novafox-patreon-page.png"
style="max-width: 450px; max-height: 300px;">
</div>
<h3>Become a Patron Today!</h3>
<p>
DisCal is developed freely, open source, and completely unlimited. However, we still need to support
ourselves.
<br> <br>
Rather than making DisCal limited for free users, we decided to open a patreon, by becoming a patron
you help support and fund the further development and support for DisCal. Please consider becoming a
patron!
</p>
<a target="_blank" href="https://www.patreon.com/Novafox">
<button>Become a Patron!</button>
</a>
<p>
By becoming a patron, you not only support us and DisCal's development, but will get exclusive
access to features early before anyone else!
</p>
</div>
<hr>
<div id="developer-api">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/examples/DisCal-Developer-API.jpg"
style="max-width: 450px; max-height: 300px;">
</div>
<h3>Developer API</h3>
<p>
With DisCal growing everyday, we decided that a developer API should exist. So, that's exactly what
we did!
<br>
We have built a fully RESTful API into DisCal for you to hook into! Use it for your bots, websites,
apps, and more!
<br>
<br>
Simply check out the API documentation and learn how you can easily use DisCal in your projects!
</p>
<a target="_blank" href="/docs/api/overview">
<button>View API Docs</button>
</a>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,629 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Commands - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a class="active" href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>DisCal Bot - About</h1>
<p>
Below is full documentation on DisCal commands.
<br> <br> <br>
This documentation includes the command, acceptable arguments, an example, and an explanation for each
and every command DisCal has to offer.
<br> <br>
Since many commands have sub-commands and functions, this page will be split into sections for each.
<br>
<br>
<br>
<strong>[] = required</strong>
<br>
<strong>() = optional</strong>
</p>
<hr>
<div class="image-wrapper" style="max-width: 900px; position: center;">
<img src="/assets/images/examples/event_demo.gif"
style="max-width: 300px; max-height: 300px; padding: 10px;">
<img src="/assets/images/examples/calendar_demo.gif"
style="max-width: 300px; max-height: 300px; padding: 10px;">
<img src="/assets/images/examples/announcement_demo.gif"
style="max-width: 300px; max-height: 300px; padding: 10px;">
</div>
<hr>
<div id="calendar">
<h2>!calendar commands</h2>
<h3>Alias: !cal</h3>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!cal create</td>
<td>!cal create [name w/ spaces]</td>
<td>!cal create cool calendar</td>
<td>Starts the calendar creator</td>
</tr>
<tr>
<td>!cal summary</td>
<td>!cal summary [summary w/ spaces]</td>
<td>!cal summary cool calendar</td>
<td>Sets the calendar's name/summary</td>
</tr>
<tr>
<td>!cal name</td>
<td>!cal name [name w/ spaces]</td>
<td>!cal name cool calendar</td>
<td>Sets the calendar's name/summary</td>
</tr>
<tr>
<td>!cal description</td>
<td>!cal description [desc. w/ spaces]</td>
<td>!cal description my awesome calendar</td>
<td>Sets the calendar's description</td>
</tr>
<tr>
<td>!cal timezone</td>
<td>!cal timezone [timezone]</td>
<td>!cal timezone America/Chicago</td>
<td>Sets the calendar's timezone.</td>
</tr>
<tr>
<td>!cal view</td>
<td>!cal view</td>
<td>!cal view</td>
<td>Displays the calendar currently in the editor/creator</td>
</tr>
<tr>
<td>!cal review</td>
<td>!cal review</td>
<td>!cal review</td>
<td>Displays the calendar currently in the editor/creator</td>
</tr>
<tr>
<td>!cal confirm</td>
<td>!cal confirm</td>
<td>!cal confirm</td>
<td>Confirms the creation/edits and updates on Google.</td>
</tr>
<tr>
<td>!cal cancel</td>
<td>!cal cancel</td>
<td>!cal cancel</td>
<td>Cancels the creation/edits of a calendar</td>
</tr>
<tr>
<td>!cal delete</td>
<td>!cal delete</td>
<td>!cal delete</td>
<td>Deletes the calendar from your Guild and Google</td>
</tr>
<tr>
<td>!cal remove</td>
<td>!cal remove</td>
<td>!cal remove</td>
<td>Deletes the calendar from your Guild and Google</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="event">
<h2>!event commands</h2>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!event create</td>
<td>!event create (name w/ spaces)</td>
<td>!event create my cool event</td>
<td>Start the event creator</td>
</tr>
<tr>
<td>!event summary</td>
<td>!event summary [summary w/ spaces]</td>
<td>!event summary my cool event</td>
<td>Sets the event name/summary</td>
</tr>
<tr>
<td>!event description</td>
<td>!event description [desc. w/ spaces]</td>
<td>!event description This is my super cool event</td>
<td>Sets the event description</td>
</tr>
<tr>
<td>!event start</td>
<td>!event start [yyyy/MM/dd-HH:mm:ss]</td>
<td>!event start 2018/03/21-14:30:00</td>
<td>Sets the event's start time (in 24 hour format)</td>
</tr>
<tr>
<td>!event end</td>
<td>!event end [yyyy/MM/dd-HH:mm:ss]</td>
<td>!event end 2018/03/21-20:00:00</td>
<td>Sets the event's end time (in 24 hour format)</td>
</tr>
<tr>
<td>!event color</td>
<td>!event color [color]</td>
<td>!event color GREEN</td>
<td>Set's the event's <a href="/docs/events/event-colors">Color</a></td>
</tr>
<tr>
<td>!event location</td>
<td>!event location [location]</td>
<td>!event location Room 253</td>
<td>Sets the event's location</td>
</tr>
<tr>
<td>!event image</td>
<td>!event image [link]</td>
<td>!event image <a href="https://life.has-destroyed.me/CoXnNvOVq.jpg">https://life.has-destroyed.me/CoXnNvOVq.jpg</a>
</td>
<td>Sets the event's image. Must be a valid link to image directly. NO GIFS!</td>
</tr>
<tr>
<td>!event confirm</td>
<td>!event confirm</td>
<td>!event confirm</td>
<td>Confirms the event's creation/edit.</td>
</tr>
<tr>
<td>!event review</td>
<td>!event review</td>
<td>!event review</td>
<td>Displays the event currently in the creator/editor</td>
</tr>
<tr>
<td>!event confirm</td>
<td>!event confirm</td>
<td>!event confirm</td>
<td>Confirms the event's creation/edit.</td>
</tr>
<tr>
<td>!event cancel</td>
<td>!event cancel</td>
<td>!event cancel</td>
<td>Cancels the event creation/edits.</td>
</tr>
<tr>
<td>!event recur</td>
<td>!event recur [true/false]</td>
<td>!event recur true</td>
<td>Set's whether or not the event will recur</td>
</tr>
<tr>
<td>!event freq</td>
<td>!event freq [frequency]</td>
<td>!event freq DAILY</td>
<td>Set's the event recurrence frequency to DAILY. Valid options: DAILY, WEEKLY, MONTHLY,
YEARLY
</td>
</tr>
<tr>
<td>!event count</td>
<td>!event count [count]</td>
<td>!event count -1</td>
<td>Sets how many times the event will recur. (Use 0 or -1 for infinite)</td>
</tr>
<tr>
<td>!event interval</td>
<td>!event interval [interval]</td>
<td>!event interval 2</td>
<td>Sets the recurrence interval. 1 is every time (according to frequency), 2 means every other
time, etc etc
</td>
</tr>
<tr>
<td>!event edit</td>
<td>!event edit [event ID]</td>
<td>!event edit eihctjdgmf</td>
<td>Starts the event editor for the specified event</td>
</tr>
<tr>
<td>!event copy</td>
<td>!event copy [event ID]</td>
<td>!event copy eihctjdgmf</td>
<td>Copies the specified event details into a new event creator</td>
</tr>
<tr>
<td>!event view</td>
<td>!event view [event ID]</td>
<td>!event view eihctjdgmf</td>
<td>Displays the specified event's details.</td>
</tr>
<tr>
<td>!event delete</td>
<td>!event delete [event ID]</td>
<td>!event delete eihctjdgmf</td>
<td>Deletes the specified event</td>
</tr>
<tr>
<td>!event remove</td>
<td>!event remove [event ID]</td>
<td>!event remove eihctjdgmf</td>
<td>Deletes the specified event</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="rsvp">
<h2>!rsvp commands</h2>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!rsvp ontime</td>
<td>!rsvp ontime [Event ID]</td>
<td>!rsvp ontime eihctjdgmf</td>
<td>RSVPs as going to the event on time.</td>
</tr>
<tr>
<td>!rsvp late</td>
<td>!rsvp late [Event ID]</td>
<td>!rsvp late eihctjdgmf</td>
<td>RSVPs as going to the event, but arriving late.</td>
</tr>
<tr>
<td>!rsvp not</td>
<td>!rsvp not [Event ID]</td>
<td>!rsvp not eihctjdgmf</td>
<td>RSVPs as not going to the event.</td>
</tr>
<tr>
<td>!rsvp unsure</td>
<td>!rsvp unsure [Event ID]</td>
<td>!rsvp unsure eihctjdgmf</td>
<td>RSVPs as unsure about whether or not you will attend.
</td>
</tr>
<tr>
<td>!rsvp remove</td>
<td>!rsvp remove [Event ID]</td>
<td>!rsvp remove eihctjdgmf</td>
<td>Removes your RSVP status from the event.</td>
</tr>
<tr>
<td>!rsvp list</td>
<td>!rsvp list [Event ID]</td>
<td>!rsvp list eihctjdgmf</td>
<td>Lists the users who have RSVPed to the event.</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="announcement">
<h2>!announcement commands</h2>
<h3>Aliases: !a !ann !announce !alert !alerts</h3>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!a create</td>
<td>!a create</td>
<td>!a create</td>
<td>Starts the announcement creator</td>
</tr>
<tr>
<td>!a type</td>
<td>!a type [type]</td>
<td>!a type UNIVERSAL</td>
<td>Sets the announcement type. Valid types: UNIVERSAL, SPECIFIC, COLOR, RECUR</td>
</tr>
<tr>
<td>!a event</td>
<td>!a event [event-id]</td>
<td>!a event eihctjdgmf</td>
<td>Sets the announcement's event. <strong>ONLY needed when using SPECIFIC or RECUR</strong>
</td>
</tr>
<tr>
<td>!a color</td>
<td>!a color [color]</td>
<td>!a color BLUE</td>
<td>Sets the announcement's color <strong>ONLY needed when using COLOR</strong></td>
</tr>
<tr>
<td>!a channel</td>
<td>!a channel [channel-name]</td>
<td>!a channel announcements</td>
<td>Sets the announcement's channel to post in.</td>
</tr>
<tr>
<td>!a minutes</td>
<td>!a minutes [minutes]</td>
<td>!a minutes 30</td>
<td>Sets the minutes before the event to announce. Added to hours</td>
</tr>
<tr>
<td>!a hours</td>
<td>!a hours [hours]</td>
<td>!a hours 2</td>
<td>Sets the hours before the event to announce. Added to minutes</td>
</tr>
<tr>
<td>!a review</td>
<td>!a review</td>
<td>!a review</td>
<td>Displays info about the announcement being edited/created.</td>
</tr>
<tr>
<td>!a confirm</td>
<td>!a confirm</td>
<td>!a confirm</td>
<td>Confirms the creation/edits and updates the database.</td>
</tr>
<tr>
<td>!a edit</td>
<td>!a edit [announcement-ID]</td>
<td>!a edit d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Starts the editor for the specified announcement</td>
</tr>
<tr>
<td>!a copy</td>
<td>!a copy [announcement-ID]</td>
<td>!a copy d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Copies the specified announcement's details to a new announcement</td>
</tr>
<tr>
<td>!a delete</td>
<td>!a delete [announcement-ID]</td>
<td>!a delete d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Deletes the specified announcement</td>
</tr>
<tr>
<td>!a view</td>
<td>!a view [announcement-ID]</td>
<td>!a view d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Displays the specified announcement's details</td>
</tr>
<tr>
<td>!a list</td>
<td>!a list [Amount or "all"]</td>
<td>!a list 10</td>
<td>Lists the specified amount of announcements view quick viewing</td>
</tr>
<tr>
<td>!a sub</td>
<td>!a sub [announcement-ID] (user(s) and/or role(s))</td>
<td>!a sub d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Subscribes yourself OR the specified users/roles to the announcement</td>
</tr>
<tr>
<td>!a unsub</td>
<td>!a unsub [announcement-ID] (user(s) and/or role(s))</td>
<td>!a unsub d9b0ab8d-7b1e-4f3f-aaa8-0a8399e3fc8c</td>
<td>Unsubscribes yourself OR the specified users/roles to the announcement</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="discal">
<h2>!discal commands</h2>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!discal</td>
<td>!discal</td>
<td>!discal</td>
<td>Displays DisCal's bot information</td>
</tr>
<tr>
<td>!discal settings</td>
<td>!discal settings</td>
<td>!discal settings</td>
<td>Displays the guild's settings for DisCal (like prefix)</td>
</tr>
<tr>
<td>!discal prefix</td>
<td>!discal prefix [prefix]</td>
<td>!discal prefix $$</td>
<td>Changes DisCal's prefix. <strong>Mentioning DisCal will always work no matter the
prefix</strong></td>
</tr>
<tr>
<td>!discal role</td>
<td>!discal role [role-name]</td>
<td>!discal role controllers</td>
<td>Sets the role (or higher) users must have in order to use certain DisCal commands. <strong>Reset
with "!discal role everyone"</strong></td>
</tr>
<tr>
<td>!discal channel</td>
<td>!discal channel [channel-name]</td>
<td>!discal channel discal-control</td>
<td>Sets the channel DisCal can respond in. <strong>Reset with "!discal channel all"</strong>
</td>
</tr>
<tr>
<td>!discal simpleAnnouncement</td>
<td>!discal simpleAnnouncement</td>
<td>!discal simpleAnnouncement</td>
<td>Makes announcements appear more user friendly</td>
</tr>
<tr>
<td>!discal brand</td>
<td>!discal brand</td>
<td>!discal brand</td>
<td>Uses the guild's name in DisCal embeds. <strong>Patron only!</strong></td>
</tr>
<tr>
<td>!discal lang</td>
<td>!discal lang [language]</td>
<td>!discal lang english</td>
<td>Set's DisCal's language</td>
</tr>
<tr>
<td>!discal invite</td>
<td>!discal invite</td>
<td>!discal invite</td>
<td>Displays the invite link to DisCal's Support Guild.</td>
</tr>
<tr>
<td>!discal dashboard</td>
<td>!discal dashboard</td>
<td>!discal dashboard</td>
<td>Displays the link to the Control dashboard on DisCal's website.</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div id="other">
<h2>All Other Commands</h2>
<table style="border-color: #ef0813;" border="#ef0813" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<th>Command</th>
<th>Acceptable Arguments</th>
<th>Example</th>
<th>Description</th>
</tr>
<tr>
<td>!linkCal</td>
<td>!linkCal</td>
<td>!linkCal</td>
<td>Displays the server's calendar info AND provides a link to view in browser</td>
</tr>
<tr>
<td>!time</td>
<td>!time</td>
<td>!time</td>
<td>Displays the current time of the calendar in the calendar's timezone</td>
</tr>
<tr>
<td>!events</td>
<td>!events (amount)</td>
<td>!events 2</td>
<td>Displays up to the specified amount of upcoming events</td>
</tr>
<tr>
<td>!help</td>
<td>!help (command) (sub-command)</td>
<td>!help event create</td>
<td>Displays help information for the specified commands/sub commands</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,330 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
<link href="/styles-old/bootstrap/modal-only.css" rel="stylesheet">
<script src="/scripts/dashboard/announcement.js"></script>
<!--Externally hosted-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body onload="handleVisibility()">
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div id="side-nav">
<h4>Main Settings</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="bot">
<button type="submit">Bot Settings</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="guild">
<button type="submit">Guild Settings</button>
</form>
<hr>
<h4>Components</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="calendar">
<button type="submit">Calendar</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="events">
<button type="submit">Events</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="announcements">
<button type="submit">Announcements</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="rsvp">
<button type="submit">RSVPs</button>
</form>
</div>
<div style="display: flow-root">
<img th:src="${selected.icon}"
style="display: flex;float: left;max-width: 64px;margin-right: 15px;">
<h3 th:text="'Managing Server: ' + ${selected.name}" style="text-align: left;"></h3>
<hr>
<p th:if="${settings} == null">Please select the settings to edit on the left.</p>
<div th:if="${settings} != null">
<!--Announcement Settings-->
<div th:if="${settings} == announcements">
<h6>Announcement Settings</h6>
<form method="post" action="/api/v1/dashboard/update/settings" style="text-align: left;">
<input type="hidden" name="simple-ann" value="simple-ann">
<label>Use Simple Announcements
<br>
<input type="checkbox" name="value"
th:checked="${selected.settings.simpleAnnouncements} == true"
onchange="this.form.submit()">
</label>
</form>
<br>
<br>
<hr>
<div class="announcement-edit-container-all">
<h6>Announcement List</h6>
<!--TODO: Add pagination for larger guilds....-->
<th:block th:each="ann : ${selected.announcements}">
<!--TODO: Implement permission handling-->
<div class="announcement-edit-container-single">
<p style="float: left" th:text="${ann.announcementId}"></p>
<button type="button" data-toggle="modal"
th:data-target="'#modal-' + ${ann.announcementId}" style="float: right">Edit
</button>
<form method="post" action="/api/v1/dashboard/delete/announcement"
style="float: right">
<input type="hidden" name="id" th:value="${ann.announcementId}">
<button class="danger" type="submit">Delete</button>
</form>
<!-- Edit Modal -->
<div class="modal fade" th:id="'modal-' + ${ann.announcementId}" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Editing Announcement</h4>
</div>
<div class="modal-body">
<form style="text-align: left;" method="post"
enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/announcement">
<label>Channel
<br>
<select name="channel">
<th:block th:each="chan : ${selected.channels}">
<th:block th:if="${chan.id} != 0">
<option th:value="${chan.id}"
th:text="${chan.name}"
th:selected="${ann.announcementChannelId} == ${chan.id}"></option>
</th:block>
</th:block>
</select>
</label>
<br>
<br>
<label>Type
<br>
<select name="type">
<th:block th:each="ty : ${anTypes}">
<option th:value="${ty.name}" th:text="${ty.name}"
th:selected="${ty.name} == ${ann.announcementType.name}"></option>
</th:block>
</select>
</label>
<br>
<br>
<label>Event ID (only needed if type of RECUR or SPECIFIC)
<br>
<input name="event-id" type="text"
th:value="${ann.eventId}">
</label>
<br>
<br>
<label>Color (Only needed if type of COLOR)
<br>
<select name="color">
<th:block th:each="c : ${eventColors}">
<option th:value="${c.id}" th:text="${c.name}"
th:selected="${c.id} == ${ann.eventColor.id}"></option>
</th:block>
</select>
</label>
<br>
<br>
<label>Minutes Before
<br>
<input name="minutes" type="number"
th:value="${ann.minutesBefore}">
</label>
<br>
<br>
<label>Hours Before
<br>
<input name="hours" type="number"
th:value="${ann.hoursBefore}">
</label>
<br>
<br>
<label>Info (Leave as "None" if you don't want it to display).
<br>
<input name="info" type="text" th:value="${ann.info}">
</label>
<br>
<br>
<input type="hidden" name="id" th:value="${ann.announcementId}">
<input type="submit" class="submit" value="Update Announcement!"
th:disabled="${selected.discalRole} == false">
</form>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<br>
</div>
<br>
</th:block>
</div>
<br>
<br>
<hr>
<div id="create-announcement">
<h6>Create An Announcement Below!</h6>
<form style="text-align: left;" method="post"
enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/create/announcement" name="announcement-create">
<label>Channel
<br>
<select name="channel">
<th:block th:each="chan : ${selected.channels}">
<th:block th:if="${chan.id} != 0">
<option th:value="${chan.id}" th:text="${chan.name}"></option>
</th:block>
</th:block>
</select>
</label>
<br>
<br>
<label>Type
<br>
<select name="type" id="create-ann-type" onchange="handleVisibility()">
<th:block th:each="ty : ${anTypes}">
<option th:value="${ty.name}" th:text="${ty.name}"></option>
</th:block>
</select>
</label>
<br>
<br>
<label id="create-ann-event">Event ID
<br>
<input name="event-id" type="text">
</label>
<br>
<br>
<label id="create-ann-color">Color
<br>
<select name="color">
<th:block th:each="c : ${eventColors}">
<option th:value="${c.id}" th:text="${c.name}"></option>
</th:block>
</select>
</label>
<br>
<br>
<label>Minutes Before
<br>
<input name="minutes" type="number" value="0">
</label>
<br>
<br>
<label>Hours Before
<br>
<input name="hours" type="number" value="0">
</label>
<br>
<br>
<label>Info (Leave as "None" if you don't want it to display).
<br>
<input name="info" type="text" value="None">
</label>
<br>
<br>
<input type="submit" class="submit" value="Create Announcement!"
th:disabled="${selected.discalRole} == false">
</form>
</div>
</div>
</div>
</div>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,238 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div th:if="${loggedIn}">
<div id="side-nav">
<h4>Main Settings</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="bot">
<button type="submit">Bot Settings</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="guild">
<button type="submit">Guild Settings</button>
</form>
<hr>
<h4>Components</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="calendar">
<button type="submit">Calendar</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="events">
<button type="submit">Events</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="announcements">
<button type="submit">Announcements</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="rsvp">
<button type="submit">RSVPs</button>
</form>
</div>
<div style="display: flow-root">
<img th:src="${selected.icon}"
style="display: flex;float: left;max-width: 64px;margin-right: 15px;">
<h3 th:text="'Managing Server: ' + ${selected.name}" style="text-align: left;"></h3>
<hr>
<p th:if="${settings} == null">Please select the settings to edit on the left.</p>
<div th:if="${settings} != null">
<!--Calendar Settings-->
<div th:if="${settings} == calendar">
<h6>Calendar Settings</h6>
<form style="text-align: left">
<label> Using External Calendar
<br>
<input type="checkbox" name="ext-cal" disabled
th:checked="${selected.settings.externalCalendar} == true">
</label>
</form>
<br>
<br>
<form style="text-align: left">
<label> Maximum Calendars Allowed
<br>
<input type="text" maxlength="2" th:value="${selected.settings.maxCalendars}"
disabled>
</label>
</form>
<br>
<br>
<!--TODO: Add support for multiple calendars-->
<!--Does NOT have a calendar-->
<div th:if="${selected.calendar.id} == primary" style="text-align: left">
<hr>
<h6>Create A Calendar Below!</h6>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/create/calendar" name="calendar-create">
<label>Calendar Name/Summary
<br>
<input type="text" name="cal-name" value="Calendar Name">
</label>
<br>
<br>
<label>Calendar Description
<br>
<input type="text" name="cal-desc" value="Calendar Description">
</label>
<br>
<br>
<label>Calendar Timezone
<br>
<select name="cal-tz">
<th:block th:each="tz : ${goodTz}">
<option th:value="${tz.name}" th:text="${tz.name}"></option>
</th:block>
</select>
</label>
<br>
<br>
<input type="submit" class="submit" value="Create Calendar!"
th:disabled="${selected.discalRole} == false">
</form>
</div>
<!--Has MAIN calendar-->
<div th:unless="${selected.calendar.id} == primary">
<hr>
<h6>Edit Your Calendar Below</h6>
<a th:href="${selected.calendar.link}" target="_blank">
<button>View Calendar!</button>
</a>
<br><br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/calendar" style="text-align: left">
<label>Calendar Name/Summary
<br>
<input type="text" name="cal-name" th:value="${selected.calendar.name}">
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.discalRole} == false">
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/calendar" style="text-align: left">
<label>Calendar Description
<br>
<input type="text" name="cal-desc" th:value="${selected.calendar.description}">
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.discalRole} == false">
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/calendar" style="text-align: left">
<label>Calendar Timezone
<br>
<select name="cal-tz">
<th:block th:each="tz : ${goodTz}">
<option th:value="${tz.name}" th:text="${tz.name}"
th:selected="${tz.name} == ${selected.calendar.timezone}"></option>
</th:block>
</select>
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.discalRole} == false">
</form>
<br>
<br>
<form th:if="${selected.manageServer} == true" method="post"
action="/api/v1/dashboard/delete/calendar">
<input type="hidden" name="calendar-id" th:value="${selected.calendar.id}">
<button class="danger" type="submit">Delete Calendar</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,334 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
<link href="/styles-old/calendar.css" rel="stylesheet">
<link href="/styles-old/bootstrap/modal-only.css" rel="stylesheet">
<script src="/scripts/dashboard/calendar.js"></script>
<script src="/scripts/snackbar.js"></script>
<!--Externally hosted-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"
integrity="sha256-obZACiHd7gkOk9iIL/pimWMTJ4W/pBsKu+oZnSeBIek=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/is_js/0.9.0/is.min.js"
integrity="sha256-lnJeulOa3e5IO2EzHr8jKJ3CbT80MBwkS5a+n2ooIr4=" crossorigin="anonymous"></script>
</head>
<body onload="init()">
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div th:if="${loggedIn}">
<div id="side-nav">
<h4>Main Settings</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="bot">
<button type="submit">Bot Settings</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="guild">
<button type="submit">Guild Settings</button>
</form>
<hr>
<h4>Components</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="calendar">
<button type="submit">Calendar</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="events">
<button type="submit">Events</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="announcements">
<button type="submit">Announcements</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="rsvp">
<button type="submit">RSVPs</button>
</form>
</div>
<div style="display: flow-root">
<img th:src="${selected.icon}"
style="display: flex;float: left;max-width: 64px;margin-right: 15px;">
<h3 th:text="'Managing Server: ' + ${selected.name}" style="text-align: left;"></h3>
<hr>
<p th:if="${settings} == null">Please select the settings to edit on the left.</p>
<div th:if="${settings} != null">
<!--Event Settings-->
<div th:if="${settings} == events">
<h6>Event Settings</h6>
<!--TODO: Add support for more calendars-->
<!--No calendar-->
<div th:if="${selected.calendar.id} == primary" style="text-align: left">
<br>
<p>You do not have a calendar! Please make a calendar in order to use this page!</p>
</div>
<!--Has calendar-->
<div th:unless="${selected.calendar.id} == primary" style="text-align: left">
<div id="calendar-container">
<table id="calendar" style="border-color: #ef0813; margin: auto;" border="#ef0813"
cellpadding="4"
cellspacing="0">
<tbody>
<tr style="height: 50px;">
<th class="nav" onclick="previousMonth()"><</th>
<th></th>
<th></th>
<th id="month-display"></th>
<th></th>
<th></th>
<th class="nav" onclick="nextMonth()">></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 onclick="selectDate(this.id)" id="r1c1"></td>
<td onclick="selectDate(this.id)" id="r1c2"></td>
<td onclick="selectDate(this.id)" id="r1c3"></td>
<td onclick="selectDate(this.id)" id="r1c4"></td>
<td onclick="selectDate(this.id)" id="r1c5"></td>
<td onclick="selectDate(this.id)" id="r1c6"></td>
<td onclick="selectDate(this.id)" id="r1c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r2c1"></td>
<td onclick="selectDate(this.id)" id="r2c2"></td>
<td onclick="selectDate(this.id)" id="r2c3"></td>
<td onclick="selectDate(this.id)" id="r2c4"></td>
<td onclick="selectDate(this.id)" id="r2c5"></td>
<td onclick="selectDate(this.id)" id="r2c6"></td>
<td onclick="selectDate(this.id)" id="r2c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r3c1"></td>
<td onclick="selectDate(this.id)" id="r3c2"></td>
<td onclick="selectDate(this.id)" id="r3c3"></td>
<td onclick="selectDate(this.id)" id="r3c4"></td>
<td onclick="selectDate(this.id)" id="r3c5"></td>
<td onclick="selectDate(this.id)" id="r3c6"></td>
<td onclick="selectDate(this.id)" id="r3c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r4c1"></td>
<td onclick="selectDate(this.id)" id="r4c2"></td>
<td onclick="selectDate(this.id)" id="r4c3"></td>
<td onclick="selectDate(this.id)" id="r4c4"></td>
<td onclick="selectDate(this.id)" id="r4c5"></td>
<td onclick="selectDate(this.id)" id="r4c6"></td>
<td onclick="selectDate(this.id)" id="r4c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r5c1"></td>
<td onclick="selectDate(this.id)" id="r5c2"></td>
<td onclick="selectDate(this.id)" id="r5c3"></td>
<td onclick="selectDate(this.id)" id="r5c4"></td>
<td onclick="selectDate(this.id)" id="r5c5"></td>
<td onclick="selectDate(this.id)" id="r5c6"></td>
<td onclick="selectDate(this.id)" id="r5c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r6c1"></td>
<td onclick="selectDate(this.id)" id="r6c2"></td>
<td onclick="selectDate(this.id)" id="r6c3"></td>
<td onclick="selectDate(this.id)" id="r6c4"></td>
<td onclick="selectDate(this.id)" id="r6c5"></td>
<td onclick="selectDate(this.id)" id="r6c6"></td>
<td onclick="selectDate(this.id)" id="r6c7"></td>
</tr>
</tbody>
</table>
<p style="text-align: center; font-size: 20px" id="local-time-display">All Dates and
Times are displayed in your local timezone!</p>
</div>
<hr>
<br>
<h6>Events for Selected Date</h6>
<!--Add events for selected date via JS and JQuery-->
<div id="event-container">
</div>
<hr>
<br>
<div id="create-event-container">
<h6>Create New Event Below</h6>
<form style="text-align: left;" id="create-form"
action="javascript:createNewEvent()">
<label>Summary/Name
<br>
<input required type="text" name="summary" id="create-summary">
</label>
<br>
<br>
<label>Description
<br>
<input required type="text" name="description" id="create-description">
</label>
<br>
<br>
<label>Location
<br>
<input name="location" type="text" id="create-location" value="N/a">
</label>
<br>
<br>
<label>Color
<br>
<select name="color" id="create-color">
<th:block th:each="c : ${eventColors}">
<option th:value="${c.name}" th:text="${c.name}"></option>
</th:block>
</select>
</label>
<br>
<br>
<label>Image
<br>
<input name="image" type="text" id="create-image">
</label>
<br>
<br>
<label>Start Date/Time
<input required type="date" name="start-date" id="create-start-date">
<input required type="time" name="start-time" id="create-start-time">
</label>
<br>
<br>
<label>End Date/Time
<input required type="date" name="end-date" id="create-end-date">
<input required type="time" name="end-time" id="create-end-time">
</label>
<br>
<br>
<label>Recurrence
<br>
<input type="checkbox" id="create-enableRecur"
onclick="changeRecurrenceCreateDisplays(this)">
</label>
<br>
<label>Recurrence - Frequency
<br>
<select name="frequency" id="create-frequency" disabled>
<option value="DAILY" selected>DAILY</option>
<option value="WEEKLY">WEEKLY</option>
<option value="MONTHLY">MONTHLY</option>
<option value="YEARLY">YEARLY</option>
</select>
</label>
<br>
<br>
<label>Recurrence - Count
<br>
<input name="count" disabled type="number" min="-1" value="-1"
id="create-count">
</label>
<br>
<br>
<label>Recurrence - Interval
<br>
<input name="interval" disabled type="number" min="1" value="1"
id="create-interval">
</label>
<br>
<br>
<input type="submit" class="submit" value="Create Event!">
</form>
</div>
<div id="snackbar"></div>
</div>
</div>
</div>
</div>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,138 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div th:if="${loggedIn}">
<div id="side-nav">
<h4>Main Settings</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="bot">
<button type="submit">Bot Settings</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="guild">
<button type="submit">Guild Settings</button>
</form>
<hr>
<h4>Components</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="calendar">
<button type="submit">Calendar</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="events">
<button type="submit">Events</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="announcements">
<button type="submit">Announcements</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="rsvp">
<button type="submit">RSVPs</button>
</form>
</div>
<div style="display: flow-root">
<img th:src="${selected.icon}"
style="display: flex;float: left;max-width: 64px;margin-right: 15px;">
<h3 th:text="'Managing Server: ' + ${selected.name}" style="text-align: left;"></h3>
<hr>
<p th:if="${settings} == null">Please select the settings to edit on the left.</p>
<div th:if="${settings} != null">
<!--RSVP Settings-->
<div th:if="${settings} == rsvp">
<h6>RSVP Settings</h6>
<br>
<p>
It's a work in progress. Soon you will be able to control RSVPs from here!!
</p>
</div>
</div>
</div>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,118 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div th:if="${loggedIn}">
<h1 th:text="'Welcome, ' + ${username} + '!'"></h1>
<h3>Select a guild below!</h3>
<!--TODO: Do this in JS so that it is dynamic!!!-->
<th:block th:each="guild : ${guilds}">
<!--TODO: Remove patron/dev only on full release-->
<th:block th:if="${guild.settings.patronGuild} == true or ${guild.settings.devGuild} == true">
<th:block th:if="${guild.manageServer} == true or ${guild.discalRole} == true">
<form method="post" action="/api/v1/dashboard/select/guild">
<input type="hidden" name="guild" th:value="${guild.id}">
<button type="submit" class="guild" th:text="${guild.name}"></button>
</form>
<br>
</th:block>
<th:block th:unless="${guild.manageServer} == true or ${guild.discalRole} == true">
<form method="post" action="" disabled="true">
<input type="hidden" name="guild" th:value="${guild.id}">
<button disabled type="submit" class="guild" th:text="${guild.name}"></button>
</form>
<br>
</th:block>
</th:block>
</th:block>
<br>
<br>
<br>
<p>
*Guild not listed? Until the full release, only patron guilds are supported!
<br>
**Button grayed out/not working? You don't have high enough permissions to manage that server!
</p>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,230 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Dashboard - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a class="active" href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--Check if logged in, if not, handle login...-->
<div th:if="${loggedIn}">
<div id="side-nav">
<h4>Main Settings</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="bot">
<button type="submit">Bot Settings</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="guild">
<button type="submit">Guild Settings</button>
</form>
<hr>
<h4>Components</h4>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="calendar">
<button type="submit">Calendar</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="events">
<button type="submit">Events</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="announcements">
<button type="submit">Announcements</button>
</form>
<br>
<form method="post" action="/api/v1/dashboard/select/settings">
<input type="hidden" name="settings" value="rsvp">
<button type="submit">RSVPs</button>
</form>
</div>
<div style="display: flow-root">
<img th:src="${selected.icon}"
style="display: flex;float: left;max-width: 64px;margin-right: 15px;">
<h3 th:text="'Managing Server: ' + ${selected.name}" style="text-align: left;"></h3>
<hr>
<p th:if="${settings} == null">Please select the settings to edit on the left.</p>
<div th:if="${settings} != null">
<!--Bot Settings-->
<div th:if="${settings} == bot">
<h6>Bot Settings</h6>
<form action="/api/v1/dashboard/update/settings" method="post"
enctype="application/x-www-form-urlencoded" style="text-align: left">
<label>Bot Nickname
<br>
<input type="text" name="bot-nick" maxlength="32" th:value="${selected.botNick}">
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.manageServer} == false">
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/settings" style="text-align: left">
<label>Bot Prefix
<br>
<input type="text" name="prefix" maxlength="32"
th:value="${selected.settings.prefix}">
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.manageServer} == false">
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/settings" style="text-align: left">
<label>Bot Language
<br>
<select name="lang" disabled>
<option th:value="${selected.settings.lang}" selected
th:text="${selected.settings.lang}"></option>
<option value="ENGLISH" th:unless="${selected.settings.lang} == ENGLISH">
English
</option>
</select>
</label>
<input disabled type="submit" class="submit" value="Update"
th:disabled="${selected.manageServer} == false">
</form>
<br>
</div>
<!--Guild Settings-->
<div th:if="${settings} == guild">
<h6>Guild Settings</h6>
<form style="text-align: left">
<label>Patron Guild
<br>
<input type="checkbox" name="patron" disabled
th:checked="${selected.settings.patronGuild} == true">
</label>
</form>
<br>
<br>
<form method="post" action="/api/v1/dashboard/update/settings" style="text-align: left;">
<input type="hidden" name="branding" value="branding">
<label>Enable Server Branding (Patron Only)
<br>
<input type="checkbox" name="value"
th:disabled="${selected.settings.patronGuild} != true"
th:checked="${selected.settings.branded} == true"
onchange="this.form.submit()">
</label>
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/settings" style="text-align: left">
<label>Control Role
<br>
<select name="con-role">
<th:block th:each="role : ${selected.roles}">
<option th:value="${role.id}" th:text="${role.name}"
th:selected="${role.controlRole} == true"></option>
</th:block>
</select>
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.manageServer} == false">
</form>
<br>
<br>
<form method="post" enctype="application/x-www-form-urlencoded"
action="/api/v1/dashboard/update/settings" style="text-align: left">
<label>DisCal Channel
<br>
<select name="discal-channel">
<th:block th:each="chan : ${selected.channels}">
<option th:value="${chan.id}" th:text="${chan.name}"
th:selected="${chan.discalChannel} == true"></option>
</th:block>
</select>
</label>
<input type="submit" class="submit" value="Update"
th:disabled="${selected.discalRole} == false">
</form>
<br>
<br>
</div>
</div>
</div>
</div>
<div th:unless="${loggedIn}">
<h1>YOU ARE NOT LOGGED IN!</h1>
<p>Please login to continue.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,199 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<hr>
<h4>Jump</h4>
<a href="/docs/api/errors#405">
<button>405</button>
</a>
<br>
<a href="/docs/api/errors#404">
<button>404</button>
</a>
<br>
<a href="/docs/api/errors#401">
<button>401</button>
</a>
<br>
<a href="/docs/api/errors#400">
<button>400</button>
</a>
<br>
<a href="/docs/api/errors#500">
<button>500</button>
</a>
</div>
<h1>API Docs - Errors</h1>
<p>
When using the API provided by DisCal, it is good to be aware of, and be able to correctly handle
various errors.
</p>
<br>
<br>
<hr>
<h2 id="405">405 - Method not allowed</h2>
<p>
If you receive this error, it means you are improperly accessing the API.
<br>
DisCal's REST API requires <strong>POST</strong> requests. This is to securely handle various data with
ease.
</p>
<br>
<br>
<hr>
<h2 id="404">404 - Not Found</h2>
<p>
The requested object was not found on our servers. The object may have been deleted or the ID used was
invalid.
</p>
<br>
<br>
<hr>
<h2 id="401">401 - Unauthorized</h2>
<p>
If you receive this error, it means you either forgot to include the authorization header with a valid
auth key or you are not allowed to use the API endpoint you are accessing (for example the login/logout
endpoints).
<br>
<br>
To correct this, make sure you include the <strong>Authorization</strong> header with a valid auth key.
<br>
Furthermore, make sure you are allowed to access the API endpoint.
</p>
<br>
<br>
<hr>
<h2 id="400">400 - Bad Request</h2>
<p>
This error means your request was invalid in some form. Make sure the POST request's content type is set
to <strong>"application/json"</strong> and that you are not missing any required values in the request
body.
</p>
<br>
<br>
<hr>
<h2 id="500">500 - Internal Server Exception</h2>
<p>
An error occurred on our end. Everything you did was likely right, but our system failed in some way.
<br>
<br>
We log all errors that occur and will do our best to correct them. Should you get this error numerous
times, contact the development team for further help.
</p>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,129 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
</div>
<h1>API Docs - Overview</h1>
<p>
DisCal provides an extensive and powerful REST API for you to integrate into your website or discord
bot.
<br>
<br>
These docs provide examples of requests, responses, and various info about what is required and
returned.
<br>
<br>
<br>
All requests and responses are done via HTTP POST and must be in JSON. All requests must also contain an
"Authorization" header with your API key. You can get an API key by contacting the DisCal development
team.
<br>
<br>
Current API version: v1
</p>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,722 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<hr>
<h4>Jump</h4>
<a href="/docs/api/v1/announcement#get">
<button>/get</button>
</a>
<br>
<a href="/docs/api/v1/announcement#create">
<button>/create</button>
</a>
<br>
<a href="/docs/api/v1/announcement#update">
<button>/update</button>
</a>
<br>
<a href="/docs/api/v1/announcement#delete">
<button>/delete</button>
</a>
<br>
<a href="/docs/api/v1/announcement#list">
<button>/list</button>
</a>
</div>
<h1>API v1 Docs - Announcement Endpoint</h1>
<p>
The announcement endpoints allows you to create, edit, delete, and list announcements for a specific
guild.
</p>
<br>
<hr>
<h2 id="get">/get</h2>
<p>
Returns the specified announcement's data.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"id": "b067378e-2565-4116-aa20-08cc144d1fdb"
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"channel": "266666669542342656",
"event_id": "divq9ihqhoq9hbm2tncj8set04_20180317T030000Z",
"event_color": "NONE",
"type": "RECUR",
"hours": 1,
"minutes": 30,
"info": "Event is in 1 hour and thirty minutes!",
"enabled": true,
"info_only:: false,
"subscribers_role": ["everyone", "378479752186560512"],
"subscribers_user": ["130510525770629121"]
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The ID of the announcement</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>channel</td>
<td>String</td>
<td>ID of the channel the announcement will announce in</td>
</tr>
<tr>
<td>event_id</td>
<td>String</td>
<td>ID of the event the announcement is for</td>
</tr>
<tr>
<td>event_color</td>
<td>String</td>
<td>Event Color the announcement will check for</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td>The announcement's type</td>
</tr>
<tr>
<td>event_color</td>
<td>String</td>
<td>Event Color the announcement will check for</td>
</tr>
<tr>
<td>hours</td>
<td>int</td>
<td>The amount of hours before the event to fire (added to minutes)</td>
</tr>
<tr>
<td>minutes</td>
<td>int</td>
<td>The amount of minutes before the event to fire (added to hours)</td>
</tr>
<tr>
<td>info</td>
<td>String</td>
<td>Additional info for the announcement</td>
</tr>
<tr>
<td>enabled</td>
<td>Boolean</td>
<td>Whether or not the announcement is enabled</td>
</tr>
<tr>
<td>info_only</td>
<td>Boolean</td>
<td>Whether or not the announcement will display just the "info" box</td>
</tr>
<tr>
<td>subscribers_role</td>
<td>List(of Strings)</td>
<td>List of roles subscribed to the announcement</td>
</tr>
<tr>
<td>subscribers_user</td>
<td>List(of Strings)</td>
<td>List of users subscribed to the announcement</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="create">/create</h2>
<p>
Creates a new announcement with the specified information
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 266063520112574464,
"channel": "266666669542342656",
"event_id": "divq9ihqhoq9hbm2tncj8set04",
"type": "RECUR",
"hours": 1,
"minutes": 30,
"info": ""
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully created announcement",
"id": "b067378e-2565-4116-aa20-08cc144d1fdb"
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>channel</td>
<td>String</td>
<td>ID of channel to post announcement in</td>
<td>True</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td>The announcement type</td>
<td>True</td>
</tr>
<tr>
<td>event_id</td>
<td>String</td>
<td>ID of event for announcement to check</td>
<td>Required if type equals "RECUR" or "SPECIFIC"</td>
</tr>
<tr>
<td>event_color</td>
<td>String</td>
<td>Color of events to check</td>
<td>Required if type equals "COLOR"</td>
</tr>
<tr>
<td>hours</td>
<td>int</td>
<td>Amount of hours before event to announce (added to minutes)</td>
<td>True</td>
</tr>
<tr>
<td>minutes</td>
<td>int</td>
<td>Amount of minutes before event to announce (added to hours)</td>
<td>True</td>
</tr>
<tr>
<td>info</td>
<td>String</td>
<td>Additional announcement info (leave blank to ignore)</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of Creation</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>ID of the new announcement</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="update">/update</h2>
<p>
Updates an announcement with the specified information
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 266063520112574464,
"id": "b067378e-2565-4116-aa20-08cc144d1fdb",
"channel": "266666669542342656",
"event_id": "divq9ihqhoq9hbm2tncj8set04",
"type": "RECUR",
"hours": 4,
"info": "I just updated this announcement through the API!",
"enabled": true,
"info_only": false
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully updated announcement"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The Announcement ID</td>
<td>True</td>
</tr>
<tr>
<td>channel</td>
<td>String</td>
<td>ID of channel to post announcement in</td>
<td>False</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td>The announcement type</td>
<td>False</td>
</tr>
<tr>
<td>event_id</td>
<td>String</td>
<td>ID of event for announcement to check</td>
<td>Required if type changed AND equals "RECUR" or "SPECIFIC"</td>
</tr>
<tr>
<td>event_color</td>
<td>String</td>
<td>Color of events to check</td>
<td>Required if type changed AND equals "COLOR"</td>
</tr>
<tr>
<td>hours</td>
<td>int</td>
<td>Amount of hours before event to announce (added to minutes)</td>
<td>False</td>
</tr>
<tr>
<td>minutes</td>
<td>int</td>
<td>Amount of minutes before event to announce (added to hours)</td>
<td>False</td>
</tr>
<tr>
<td>info</td>
<td>String</td>
<td>Additional announcement info</td>
<td>False</td>
</tr>
<tr>
<td>enabled</td>
<td>Boolean</td>
<td>Whether or not the announcement is enabled</td>
<td>False</td>
</tr>
<tr>
<td>info_only</td>
<td>Boolean</td>
<td>Whether or not it will display just the "info" box</td>
<td>False</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of update</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="delete">/delete</h2>
<p>
Deletes the specified announcement if it exists
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 266063520112574464,
"id": "b067378e-2565-4116-aa20-08cc144d1fdb",
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully deleted announcement"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The announcement ID</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of deletion</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="list">/list</h2>
<p>
Lists the specified amount of announcements from the guild.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 266063520112574464,
"amount": -1,
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"amount": 1,
"announcements": [{
"id": "b067378e-2565-4116-aa20-08cc144d1fdb",
"channel": "266666669542342656",
"event_id": "divq9ihqhoq9hbm2tncj8set04",
"event_color": "NONE",
"type": "RECUR",
"hours": 4,
"minutes": 30,
"info": "4 hours and 30 minutes until event!",
"enabled": true,
"info_only": false,
"subscribers_role": ["everyone", "378479752186560512"],
"subscribers_user": ["130510525770629121"]
}]
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>amount</td>
<td>int</td>
<td>Amount of announcements to list, "-1" for all</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>amount</td>
<td>int</td>
<td>Amount of announcements returned</td>
</tr>
<tr>
<td>announcements.channel</td>
<td>String</td>
<td>ID of channel to post announcement in</td>
</tr>
<tr>
<td>announcements.type</td>
<td>String</td>
<td>The announcement type</td>
</tr>
<tr>
<td>announcements.event_id</td>
<td>String</td>
<td>ID of event for announcement to check</td>
</tr>
<tr>
<td>announcements.event_color</td>
<td>String</td>
<td>Color of events to check</td>
</tr>
<tr>
<td>announcements.hours</td>
<td>int</td>
<td>Amount of hours before event to announce (added to minutes)</td>
</tr>
<tr>
<td>announcements.minutes</td>
<td>int</td>
<td>Amount of minutes before event to announce (added to hours)</td>
</tr>
<tr>
<td>announcements.info</td>
<td>String</td>
<td>Additional announcement info.</td>
</tr>
<tr>
<td>announcements.enabled</td>
<td>Boolean</td>
<td>Whether or not the announcement is enabled</td>
</tr>
<tr>
<td>announcements.info_only</td>
<td>Boolean</td>
<td>Whether or not the announcement will only display the "info" box</td>
</tr>
<tr>
<td>announcements.subscribers_role</td>
<td>List(of Strings)</td>
<td>List of roles subscribed to the announcement</td>
</tr>
<tr>
<td>announcements.subscribers_user</td>
<td>List(of Strings)</td>
<td>List of users subscribed to the announcement</td>
</tr>
</tbody>
</table>
<br>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,294 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<hr>
<h4>Jump</h4>
<a href="/docs/api/v1/calendar#get">
<button>/get</button>
</a>
<br>
<a href="/docs/api/v1/calendar#list">
<button>/list</button>
</a>
</div>
<h1>API v1 Docs - Calendar Endpoint</h1>
<p>
The calendar endpoints allows you to get, edit, and list calendars for a specific
guild.
</p>
<br>
<hr>
<h2 id="get">/get</h2>
<p>
Returns the specified calendar's data.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"number": 1
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"external": false,
"id": "m105ipacns28o6ke995qon90e0@group.calendar.google.com"
"address": "m105ipacns28o6ke995qon90e0@group.calendar.google.com"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>number</td>
<td>int</td>
<td>The calendar's number (1 for the main calendar)</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>external</td>
<td>Boolean</td>
<td>Whether or not the calendar is an external calendar</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The calendar's google ID</td>
</tr>
<tr>
<td>address</td>
<td>String</td>
<td>The calendar's google Address</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="list">/list</h2>
<p>
Returns a list of all the guild's calendars.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"count": 1,
"calendars": [{
"number": 1,
"external": false,
"id": "m105ipacns28o6ke995qon90e0@group.calendar.google.com",
"address": "m105ipacns28o6ke995qon90e0@group.calendar.google.com"
}]
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>count</td>
<td>int</td>
<td>Amount of calendars the guild has</td>
</tr>
<tr>
<td>calendars.number</td>
<td>int</td>
<td>Calendar index. (1 for main calendar)</td>
</tr>
<tr>
<td>calendars.external</td>
<td>Boolean</td>
<td>Whether or not the calendar is an external calendar</td>
</tr>
<tr>
<td>calendars.id</td>
<td>String</td>
<td>The calendar's google ID</td>
</tr>
<tr>
<td>calendars.address</td>
<td>String</td>
<td>The calendar's google Address</td>
</tr>
</tbody>
</table>
<br>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,760 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<hr>
<h4>Jump</h4>
<a href="/docs/api/v1/events#list-month">
<button>/list/month</button>
</a>
<br>
<a href="/docs/api/v1/events#list-date">
<button>/list/date</button>
</a>
<br>
<a href="/docs/api/v1/events#create">
<button>/create</button>
</a>
<br>
<a href="/docs/api/v1/events#update">
<button>/update</button>
</a>
<br>
<a href="/docs/api/v1/events#delete">
<button>/delete</button>
</a>
</div>
<h1>API v1 Docs - Events Endpoint</h1>
<p>
The events endpoint allows you to create events, get events for the date or month, edit, and delete
events.
</p>
<br>
<hr>
<h2 id="list-month">/events/list/month</h2>
<p>
Returns a list of events for the specified month.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"DaysInMonth": 31,
"EpochStart": 1519884000000
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"count": 1,
"events": [{
"id": "e7gqkup5l8",
"epochStart": 1521732600000,
"epochEnd": 1521761400000
}]
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>DaysInMonth</td>
<td>int</td>
<td>Days in the month</td>
<td>True</td>
</tr>
<tr>
<td>EpochStart</td>
<td>long</td>
<td>First unix millisecond of the month</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Count</td>
<td>int</td>
<td>Amount of events in month</td>
</tr>
<tr>
<td>events</td>
<td>List</td>
<td>List of events in month</td>
</tr>
<tr>
<td>events.id</td>
<td>String</td>
<td>The event's ID</td>
</tr>
<tr>
<td>events.epochStart</td>
<td>long</td>
<td>Unix start time of event</td>
</tr>
<tr>
<td>events.epochEnd</td>
<td>long</td>
<td>Unix end time of event</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="list-date">/events/list/date</h2>
<p>
Returns a list of events for the specified date. Automatically adds 24 hours to the start time.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"startEpoch": 1521694800000
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"count": 1,
"events": [{
"id": "e7gqkup5l8",
"epochStart": 1521732600000,
"epochEnd": 1521732600000,
"timezone": "America/Chicago",
"summary": "Made in the dashboard!",
"description": "This event was created using the new dashboard",
"location": "The void",
"color": "BLUE",
"isParent": true,
"recurrence": {
"recur": false,
"frequency": "DAILY",
"count": -1,
"interval": 1,
},
"image": "https://goo.gl/nqi64A"
}]
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>StartEpoch</td>
<td>long</td>
<td>First unix millisecond of the date</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Count</td>
<td>int</td>
<td>Amount of events in month</td>
</tr>
<tr>
<td>events</td>
<td>List</td>
<td>List of events in month</td>
</tr>
<tr>
<td>events.id</td>
<td>String</td>
<td>The event's ID</td>
</tr>
<tr>
<td>events.epochStart</td>
<td>long</td>
<td>Unix start time of event</td>
</tr>
<tr>
<td>events.epochEnd</td>
<td>long</td>
<td>Unix end time of event</td>
</tr>
<tr>
<td>events.timezone</td>
<td>String</td>
<td>The Timezone of the event/calendar</td>
</tr>
<tr>
<td>events.summary</td>
<td>String</td>
<td>The summary/name of the event</td>
</tr>
<tr>
<td>events.description</td>
<td>String</td>
<td>The description of the event</td>
</tr>
<tr>
<td>events.location</td>
<td>String</td>
<td>The location the event takes place</td>
</tr>
<tr>
<td>events.color</td>
<td>String</td>
<td>The name of the event color, "NONE" if no color used</td>
</tr>
<tr>
<td>events.image</td>
<td>String/URL</td>
<td>URL of the event's image</td>
</tr>
<tr>
<td>events.isParent</td>
<td>Boolean</td>
<td>Whether or not the event is a parent. (default true)</td>
</tr>
<tr>
<td>events.recurrence.recur</td>
<td>Boolean</td>
<td>Whether or not the event is set to recur.</td>
</tr>
<tr>
<td>events.recurrence.frequency</td>
<td>String</td>
<td>The frequency of the event's recurrence.</td>
</tr>
<tr>
<td>events.recurrence.recurCount</td>
<td>int</td>
<td>The amount of times the event recurs. (-1 or 0 for infinite)</td>
</tr>
<tr>
<td>events.recurrence.interval</td>
<td>int</td>
<td>Interval at which the event recurs (compliant to the above values)</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="create">/events/create</h2>
<p>
Creates a new event with the specified data.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"epochStart": 1521732600000,
"epochEnd": 1521732600000,
"summary": "My cool event!",
"description": "Event edited via REST API",
"location": "The nether",
"color": "RED",
"recurrence": {
"recur": false,
"frequency": "DAILY",
"count": -1,
"interval": 1,
},
"image": "https://goo.gl/nqi64A"
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully created event!",
"id": "e7gqkup5l8"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>epochStart</td>
<td>long</td>
<td>Unix time of event start</td>
<td>True</td>
</tr>
<tr>
<td>epochEnd</td>
<td>long</td>
<td>Unix time of event start</td>
<td>True</td>
</tr>
<tr>
<td>summary</td>
<td>String</td>
<td>The Summary/Name of the event</td>
<td>True</td>
</tr>
<tr>
<td>description</td>
<td>String</td>
<td>The description of event</td>
<td>True</td>
</tr>
<tr>
<td>location</td>
<td>String</td>
<td>Where the event takes place</td>
<td>True</td>
</tr>
<tr>
<td>color</td>
<td>String</td>
<td>The color of the event (1 of 12 supported colors)</td>
<td>True</td>
</tr>
<tr>
<td>image</td>
<td>String/URL</td>
<td>The URL to the event's image</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.recur</td>
<td>Boolean</td>
<td>Whether or not the event should recur</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.frequency</td>
<td>String</td>
<td>The frequency at which the event should recur</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.count</td>
<td>int</td>
<td>How many times the event should recur (-1 or 0 for infinite)</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.interval</td>
<td>int</td>
<td>The interval for which the event should recur (compliant to above values)</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of creation</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>ID of the event created</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="update">/events/update</h2>
<p>
Updates the specified event with the provided data.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"id": e7gqkup5l8,
"epochStart": 1521732600000,
"epochEnd": 1521732600000,
"summary": "My cool event!",
"description": "Event edited via REST API",
"location": "The nether",
"color": "RED",
"recurrence": {
"recur": false,
"count": -1,
"interval": 1,
},
"image": "https://goo.gl/nqi64A"
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully updated event!"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>ID of the event to edit</td>
<td>True</td>
</tr>
<tr>
<td>epochStart</td>
<td>long</td>
<td>Unix time of event start</td>
<td>True</td>
</tr>
<tr>
<td>epochEnd</td>
<td>long</td>
<td>Unix time of event start</td>
<td>True</td>
</tr>
<tr>
<td>summary</td>
<td>String</td>
<td>The Summary/Name of the event</td>
<td>True</td>
</tr>
<tr>
<td>description</td>
<td>String</td>
<td>The description of event</td>
<td>True</td>
</tr>
<tr>
<td>location</td>
<td>String</td>
<td>Where the event takes place</td>
<td>True</td>
</tr>
<tr>
<td>color</td>
<td>String</td>
<td>The color of the event (1 of 12 supported colors)</td>
<td>True</td>
</tr>
<tr>
<td>image</td>
<td>String/URL</td>
<td>The URL to the event's image</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.recur</td>
<td>Boolean</td>
<td>Whether or not the event should recur</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.frequency</td>
<td>String</td>
<td>The frequency at which the event should recur</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.count</td>
<td>int</td>
<td>How many times the event should recur (-1 or 0 for infinite)</td>
<td>True</td>
</tr>
<tr>
<td>recurrence.interval</td>
<td>int</td>
<td>The interval for which the event should recur (compliant to above values)</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of update.</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="delete">/events/delete</h2>
<p>
Deletes the specified event.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"id": e7gqkup5l8
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully deleted event!"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>ID of the event to delete</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of deletion</td>
</tr>
</tbody>
</table>
<br>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,331 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<hr>
<h4>Jump</h4>
<a href="/docs/api/v1/guild#settings-get">
<button>/settings/get</button>
</a>
<br>
<a href="/docs/api/v1/guild#settings-update">
<button>/settings/update</button>
</a>
</div>
<h1>API v1 Docs - Guild Endpoint</h1>
<p>
The Guild endpoints allows you to get and edit guild settings for the specified guild.
</p>
<br>
<hr>
<h2 id="settings-get">/settings/get</h2>
<p>
Returns the specified guild's settings.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"external_calendar": false,
"control_role": "everyone",
"discal_channel": "all",
"simple_announcement": false,
"lang": "ENGLISH",
"prefix": "!",
"patron_guild": false,
"dev_guild": true,
"max_calendars": 1
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>external_calendar</td>
<td>Boolean</td>
<td>Whether or not the guild has an external calendar</td>
</tr>
<tr>
<td>control_role</td>
<td>String</td>
<td>Role ID of the role required to use DisCal ("everyone") for no role</td>
</tr>
<tr>
<td>discal_channel</td>
<td>String</td>
<td>Channel ID of the channel DisCal can be used in. ("all" for no channel limits)</td>
</tr>
<tr>
<td>simple_announcement</td>
<td>Boolean</td>
<td>Whether or not the guild has simple announcements enabled</td>
</tr>
<tr>
<td>lang</td>
<td>String</td>
<td>The language DisCal will post messages in (default "ENGLISH")</td>
</tr>
<tr>
<td>prefix</td>
<td>String</td>
<td>Prefix to be used for DisCal commands (default "!")</td>
</tr>
<tr>
<td>patron_guild</td>
<td>Boolean</td>
<td>Whether or not the guild has access to patron only features</td>
</tr>
<tr>
<td>dev_guild</td>
<td>Boolean</td>
<td>Whether or not the guild has access to features currently being developed</td>
</tr>
<tr>
<td>max_calendars</td>
<td>int</td>
<td>The maximum amount of calendars the guild can have (default 1)</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="settings-update">/settings/update</h2>
<p>
Updates the specified guild's settings.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"control_role": "everyone",
"discal_channel": "all",
"simple_announcement": true,
"lang", "ENGLISH",
"prefix": "?"
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"Message": "Successfully updated guild settings"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>control_role</td>
<td>String</td>
<td>Role ID of the role required to use DisCal ("everyone") for no role</td>
<td>False</td>
</tr>
<tr>
<td>discal_channel</td>
<td>String</td>
<td>Channel ID of the channel DisCal can be used in. ("all" for no channel limits)</td>
<td>False</td>
</tr>
<tr>
<td>simple_announcement</td>
<td>Boolean</td>
<td>Whether or not the guild has simple announcements enabled</td>
<td>False</td>
</tr>
<tr>
<td>lang</td>
<td>String</td>
<td>The language DisCal will post messages in (default "ENGLISH")</td>
<td>False</td>
</tr>
<tr>
<td>prefix</td>
<td>String</td>
<td>Prefix to be used for DisCal commands (default "!")</td>
<td>False</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of settings update</td>
</tr>
</tbody>
</table>
<br>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,306 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>API Docs - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/docs.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="side-nav">
<h4>API</h4>
<a href="/docs/api/overview">
<button>Overview</button>
</a>
<br>
<a href="/docs/api/errors">
<button>Errors</button>
</a>
<hr>
<h4>v1 Endpoints</h4>
<a href="/docs/api/v1/announcement">
<button>Announcements</button>
</a>
<br>
<a href="/docs/api/v1/calendar">
<button>Calendar</button>
</a>
<br>
<a href="/docs/api/v1/events">
<button>Events</button>
</a>
<br>
<a href="/docs/api/v1/guild">
<button>Guild</button>
</a>
<br>
<a href="/docs/api/v1/rsvp">
<button>RSVP</button>
</a>
<h4>Jump</h4>
<a href="/docs/api/v1/rsvp#get">
<button>/get</button>
</a>
<br>
<a href="/docs/api/v1/rsvp#update">
<button>/update</button>
</a>
</div>
<h1>API v1 Docs - RSVP Endpoint</h1>
<p>
The RSVP endpoints allows you to get and edit RSVP status for events in a guild.
</p>
<br>
<hr>
<h2 id="get">/get</h2>
<p>
Returns the specified event's RSVP details.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"id": "divq9ihqhoq9hbm2tncj8set04"
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"on_time": ["130510525770629121"],
"late": ["233611560545812480", "142107863307780097"],
"undecided": [],
"not_going": []
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The Event ID</td>
<td>True</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>on_time</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "on time"</td>
</tr>
<tr>
<td>late</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "late"</td>
</tr>
<tr>
<td>undecided</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "unsure"/"undecided"</td>
</tr>
<tr>
<td>not_going</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "not going"</td>
</tr>
</tbody>
</table>
<br>
<hr>
<h2 id="update">/update</h2>
<p>
Updates the specified event's RSVP data.
</p>
<br>
<h6>Example Request Body</h6>
<pre class="code"><code>
{
"guild_id": 375357265198317579,
"id": "divq9ihqhoq9hbm2tncj8set04",
"on_time": ["130510525770629121"],
"late": ["233611560545812480", "142107863307780097"]
}
</code></pre>
<br>
<h6>Example Response</h6>
<br>
<pre class="code"><code>
{
"message": "Successfully updated RSVP data"
}
</code></pre>
<br>
<h6>Supported Values in Request</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
<th>Required</th>
</tr>
<tr>
<td>guild_id</td>
<td>long</td>
<td>The Guild ID</td>
<td>True</td>
</tr>
<tr>
<td>id</td>
<td>String</td>
<td>The Event ID</td>
<td>True</td>
</tr>
<tr>
<td>on_time</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "on time"</td>
<td>False</td>
</tr>
<tr>
<td>late</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "late"</td>
<td>False</td>
</tr>
<tr>
<td>undecided</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "unsure"/"undecided"</td>
<td>False</td>
</tr>
<tr>
<td>not_going</td>
<td>List (of Strings)</td>
<td>List of users that RSVPed as "not going"</td>
<td>False</td>
</tr>
</tbody>
</table>
<br>
<h6>Returned Values</h6>
<table style="border-color: #ef0813; margin: auto;" border="#ef0813" cellpadding="4" cellspacing="0">
<tbody>
<tr>
<th>Key</th>
<th>Value Type</th>
<th>Info</th>
</tr>
<tr>
<td>Message</td>
<td>String</td>
<td>Status of the update</td>
</tr>
</tbody>
</table>
<br>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,85 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Home - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>Supported Event Colors</h1>
<a href="/assets/images/event/event-color-chart.jpg" style="align-content: center; margin: auto;">
<img src="/assets/images/event/event-color-chart.jpg" alt="Event Color Chart">
</a>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,201 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Calendar - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
<link href="/styles-old/fix.css" rel="stylesheet">
<link href="/styles-old/calendar.css" rel="stylesheet">
<link href="/styles-old/bootstrap/modal-only.css" rel="stylesheet">
<script src="/scripts/embed/calendar.js"></script>
<script src="/scripts/snackbar.js"></script>
<!--Externally hosted-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"
integrity="sha256-obZACiHd7gkOk9iIL/pimWMTJ4W/pBsKu+oZnSeBIek=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/is_js/0.9.0/is.min.js"
integrity="sha256-lnJeulOa3e5IO2EzHr8jKJ3CbT80MBwkS5a+n2ooIr4=" crossorigin="anonymous"></script>
</head>
<body onload="init()">
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<!--No calendar-->
<div th:if="${embed.calendar.id} == primary" style="text-align: left">
<br>
<p>The guild does not have a calendar!</p>
</div>
<!--Has calendar-->
<div th:unless="${embed.calendar.id} == primary" style="text-align: left">
<div id="calendar-container">
<table id="calendar" style="border-color: #ef0813; margin: auto;" border="#ef0813"
cellpadding="4"
cellspacing="0">
<tbody>
<tr style="height: 50px;">
<th class="nav" onclick="previousMonth()"><</th>
<th></th>
<th></th>
<th id="month-display"></th>
<th></th>
<th></th>
<th class="nav" onclick="nextMonth()">></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 onclick="selectDate(this.id)" id="r1c1"></td>
<td onclick="selectDate(this.id)" id="r1c2"></td>
<td onclick="selectDate(this.id)" id="r1c3"></td>
<td onclick="selectDate(this.id)" id="r1c4"></td>
<td onclick="selectDate(this.id)" id="r1c5"></td>
<td onclick="selectDate(this.id)" id="r1c6"></td>
<td onclick="selectDate(this.id)" id="r1c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r2c1"></td>
<td onclick="selectDate(this.id)" id="r2c2"></td>
<td onclick="selectDate(this.id)" id="r2c3"></td>
<td onclick="selectDate(this.id)" id="r2c4"></td>
<td onclick="selectDate(this.id)" id="r2c5"></td>
<td onclick="selectDate(this.id)" id="r2c6"></td>
<td onclick="selectDate(this.id)" id="r2c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r3c1"></td>
<td onclick="selectDate(this.id)" id="r3c2"></td>
<td onclick="selectDate(this.id)" id="r3c3"></td>
<td onclick="selectDate(this.id)" id="r3c4"></td>
<td onclick="selectDate(this.id)" id="r3c5"></td>
<td onclick="selectDate(this.id)" id="r3c6"></td>
<td onclick="selectDate(this.id)" id="r3c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r4c1"></td>
<td onclick="selectDate(this.id)" id="r4c2"></td>
<td onclick="selectDate(this.id)" id="r4c3"></td>
<td onclick="selectDate(this.id)" id="r4c4"></td>
<td onclick="selectDate(this.id)" id="r4c5"></td>
<td onclick="selectDate(this.id)" id="r4c6"></td>
<td onclick="selectDate(this.id)" id="r4c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r5c1"></td>
<td onclick="selectDate(this.id)" id="r5c2"></td>
<td onclick="selectDate(this.id)" id="r5c3"></td>
<td onclick="selectDate(this.id)" id="r5c4"></td>
<td onclick="selectDate(this.id)" id="r5c5"></td>
<td onclick="selectDate(this.id)" id="r5c6"></td>
<td onclick="selectDate(this.id)" id="r5c7"></td>
</tr>
<tr>
<td onclick="selectDate(this.id)" id="r6c1"></td>
<td onclick="selectDate(this.id)" id="r6c2"></td>
<td onclick="selectDate(this.id)" id="r6c3"></td>
<td onclick="selectDate(this.id)" id="r6c4"></td>
<td onclick="selectDate(this.id)" id="r6c5"></td>
<td onclick="selectDate(this.id)" id="r6c6"></td>
<td onclick="selectDate(this.id)" id="r6c7"></td>
</tr>
</tbody>
</table>
<p style="text-align: center; font-size: 20px" id="local-time-display">All Dates and Times are
displayed in your local timezone!</p>
<br>
<br>
<a target="_blank"
th:href="'https://calendar.google.com/calendar/embed?src=' + ${embed.calendar.id}">
<button>View on Google Calendar</button>
</a>
</div>
<hr>
<br>
<h6>Events for Selected Date</h6>
<!--Add events for selected date via JS and JQuery-->
<div id="event-container">
</div>
<div id="snackbar"></div>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,119 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Home - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png"
style="max-width: 200px; max-height: 200px;">
</div>
<h1>DisCal Bot</h1>
<h3>The Best Discord Calendar Bot</h3>
<p>
DisCal is a powerful Discord bot allowing you to connect Google Calendar to Discord in a seamless
fashion. With superior support and features such as custom calendars, events, automated announcements,
RSVPs and more, DisCal is the ultimate calendar bot.
</p>
<a href="https://discordapp.com/oauth2/authorize?client_id=265523588918935552&scope=bot&permissions=201845824&redirect_uri=https://www.discalbot.com/setup"
target="_blank">
<button>Add To Discord!</button>
</a>
<hr>
<h2>See What Actual Users Are Saying</h2>
<div class="quote-block">
<div class="quote">
<h4>Casey#8173</h4>
<p>"Keep up the good work guys, this is so desperately needed!"</p>
</div>
<div class="quote">
<h4>ConfigSys.boy!#0189</h4>
<p>"Kudos for finally doing something I've been waiting for since my first day in Discord. Our
multi-game community has been using Google Docs, Images and Calendars for years and linking the
Calendar to Discord will be a huge boon."</p>
</div>
<div class="quote">
<h4>Bank_CW [DD-R]#3927</h4>
<p>"It is a bot that I see a great demand for"</p>
</div>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,113 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Lazy DisCal - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a class="active" href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<div id="about">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/lazy-discal/lazy-discal-program.jpg"
style="max-width: 300px; max-height: 300px;">
</div>
<h3>About Lazy DisCal</h3>
<p>
Lazy DisCal is an application scripted by Callador using Auto Hotkey. This application helps to make
it easy to create events, announcements, and calendars for DisCal with a very simple and easy to use
GUI.
<br>
<br>
Built for one purpose: Making your life easier by remembering all the DisCal commands for you! Can't
remember what format to put your start date? No problem!
<br>
<br>
All you have to do is fill out the various fields in LD and then click one of the submit buttons. LD
will wait a few seconds for you to bring up discord and then send all the appropriate commands to
your channel for you.
<br>
<br>
It supports saving and loading of events as text files for quick event creation. It can build events
and announcements separately or together and has the capability to build up to 50 announcements at
one time.
</p>
<a download="" href="/assets/files/Lazy-DisCal/Windows/Lazy_Discal_GUI-latest.exe">
<button>Windows</button>
</a>
<hr>
<p>*Note: until Lazy DisCal is developed for linux/mac you can run it via Wine.</p>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,105 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Privacy Policy - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>Privacy Policy</h1>
<p>
Personal information collected includes full name, email address, age, credit and/or debit card
information, billing address, and/or IP addresses. This information is only collected when needed, such
as when registering for an account or purchasing a product via the online web-store provided by
DreamExposure.
<br>
<br>
Personal information is never shared or sold to any third parties or services. Personal information is
stored on internal services and encrypted. Any credit/debit card information is not stored or accessible
by DreamExposure. Billing information is handled directly by the service DreamExposure may utilize for
handling billing (SquareUp, Stripe, PayPal, Patreon).
<br>
<br>
IP Addresses are only collected for debugging purposes and deleted every rolling 24 hour period. In
order to debug various API endpoints and pages, IP addresses may be logged. This information is vital to
assessing issues within DreamExposure's websites and services.
<br>
<br>
Passwords for DreamExposure websites are stored in a database and are hashed and salted. Passwords are
never stored in plaintext.
<br>
<br>
Last Updated: August 29, 2018.
</p>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,132 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Terms of Service - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>Terms of Service</h1>
<p>
DisCal's development team and parent, DreamExposure, puts user privacy, safety, and comfort above all
else.
<br>
In using DisCal, directly or indirectly, the user agrees to the following points.
</p>
<h3>Definitions</h3>
<p>
"Users" refers to any individual that directly utilizes DisCal. Either via the official website,
https://www.discalbot.com, command interaction with DisCal via Discord, and/or any form of communication
whereas the user talks/texts to the DisCal bot.
<br>
"Us/We" refers to DreamExposure, the group that develops and maintains DisCal. DreamExposure is
comprised of multiple members who program the bot, aid users with support and help in regards to the
DisCal bot and/or DisCal website
<br>
"Data" refers to any user entered information provided to DisCal. This information includes dates/times,
timezones, locations, event details, Discord user information, and other public data.
</p>
<h3>Agreements</h3>
<p>
We prioritize privacy and security, therefore the servers and systems that DreamExposure manages
relating to DisCal are kept encrypted behind firewalls. Regular virus scans are conducted to ensure the
system is not compromised.
<br>
Data entered into the DisCal system is kept on an encrypted drive. This data is not accessible by anyone
but the user directly entering the information, and the users in the Discord Server that the user is in.
<br>
Users, whether using DisCal directly or indirectly will not attempt to bypass or otherwise compromise
DreamExposure's servers, systems, or products. Any attempt to render DreamExposure undue harm can result
in legal action.
<br>
DisCal provides the ability to attach images to calendar events. These images are not stored or hosted
on DreamExposure systems. DreamExposure is not liable and does not allow for any illegal content
submitted by the user, including but not limited to proof of drug use, child pornography, etc. Should
DreamExposure find this content, the user will can and will be reported to the appropriate authorities.
<br>
Users are directly liable, legal or otherwise, for all content and data entered into DisCal.
<br>
DisCal utilizes the Google Calendar APIs and Discord APIs. DisCal is simply a bridge between the two. By
using DisCal the user also agrees to the Google Terms or Service and Discord Terms of Service.
<br>
DreamExposure reserves the right to revoke access to DisCal if a user attempts to break the above Terms
of Service.
</p>
<br>
<br>
<br>
<p>
Last edited: August 29, 2018.
</p>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,164 +0,0 @@
<!DOCTYPE html>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Setup - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a class="active" href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>DisCal Bot - Setup</h1>
<p>
The following page is a step by step instruction for how to properly setup DisCal.
<br><br>
It's quite simple, but you must create a new calendar in order for DisCal to function fully.
</p>
<div id="invite">
<h3>1. Add DisCal to your Discord server</h3>
<div class="image-wrapper" style="float: left">
<img src="/assets/images/examples/DisCal-Invite-Perms.jpg"
style="max-width: 300px; max-height: 300px;">
</div>
<p>
<strong>Skip this step if you have just added DisCal to your server.</strong>
<br><br><br>
Click the button below to authorize DisCal and select the server you want it on.
<br><br><br><br>
You must have the "Manage Server" permission to add the bot. Contact the server owner or admin to
invite DisCal if you cannot.
<br><br><br>
</p>
<a href="https://discordapp.com/oauth2/authorize?client_id=265523588918935552&scope=bot&permissions=201845824&redirect_uri=https://www.discalbot.com/setup"
target="_blank">
<button>Add DisCal to Discord Server</button>
</a>
</div>
<hr>
<div id="role">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/examples/DisCal-Role-Perms.jpg"
style="max-width: 300px; max-height: 300px;">
</div>
<h3>2. Give DisCal permissions at server level and not at channel level (channel permissions don't
always work right)</h3>
<p>
If you have a Bot permission group, assign DisCal that permission.
<br><br>
If not, create a new permission role with the following permissions so that DisCal may read and send
messages based on its commands:
<br><br>
- Read Messages*
<br>
- Send Messages
<br>
- Embed Links
<br>
- Mention Everyone
<br>
- Manager Messages
<br>
- Reactions/External Emojis
<br><br><br>
* DisCal will not log or save any messages.
<br><br>
</p>
</div>
<hr>
<div id="calendar">
<div class="image-wrapper" style="float: left">
<img src="/assets/images/examples/DisCal-Calendar-Creation.jpg"
style="max-width: 300px; max-height: 300px;">
</div>
<h3>3. Create a Calendar for your Discord</h3>
<p>
DisCal currently only allows 1 calendar per server. Use the command "!calendar create [calendar
name]" in any channel. (You can create a special channel just for DisCal commands if you want.)
<br> <br>
Once that command is issued, DisCal will handle the rest and walk you through a step by step guide
into creating your new calendar!
<br> <br>
Optionally you may attach an external calendar. (This feature is currently in open testing for
Patreon supporters. Visit our Discord server for more information.)
<br><br><br>
For all information on existing commands as well as some tutorial .gifs, click the button below.
</p>
<a href="commands.html">
<button>View Commands</button>
</a>
</div>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>
@@ -1,116 +0,0 @@
<!DOCTYPE HTML>
<!--suppress HtmlUnknownTarget -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<!--Meta stuffs-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="DisCal is a bot that implements Google Calendar seamlessly into Discord">
<meta property="og:title" content="DisCal Bot"/>
<meta property="og:url" content="https://discalbot.com"/>
<meta property="og:description"
content="DisCal is a bot that implements Google Calendar seamlessly into Discord"/>
<meta property="og:image" content="/assets/images/logos/Dark/Opaque/Logo%20Dark%20+bg.png">
<!-- ****** faviconit.com favicons ****** -->
<link rel="shortcut icon" href="/assets/images/favicon/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/assets/images/favicon.ico">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/images/favicon/favicon-192.png">
<link rel="icon" type="image/png" sizes="160x160" href="/assets/images/favicon/favicon-160.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/images/favicon/favicon-96.png">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/images/favicon/favicon-64.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/images/favicon/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/images/favicon/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/images/favicon/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/images/favicon/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/images/favicon/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/images/favicon/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/images/favicon/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/images/favicon/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicon/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/assets/images/favicon/favicon-144.png">
<meta name="msapplication-config" content="/assets/images/favicon/browserconfig.xml">
<!-- ****** faviconit.com favicons ****** -->
<title>Status - DisCal</title>
<!--Locally hosted-->
<link href="/styles-old/global.css" rel="stylesheet">
</head>
<body>
<div class="top-nav">
<a href="/" class="title"><h1>DISCAL</h1></a>
<a href="/about">About</a>
<a href="/commands">Commands</a>
<a href="/setup">Setup</a>
<a href="/lazy-discal">Lazy DisCal</a>
<a href="/dashboard">Dashboard</a>
<a href="https://discord.gg/2TFqyuy" target="_blank">Support</a>
<a href="https://www.patreon.com/Novafox" target="_blank">Patreon</a>
<a class="active" href="/status">Status</a>
<a class="account" th:if="${loggedIn}" href="/account/logout">Log out</a>
<a class="account" th:unless="${loggedIn}"
th:href="'https://discordapp.com/oauth2/authorize?client_id=' + ${client} + '&scope=guilds+identify&permissions=0&response_type=code&redirect_uri=' + ${redirUri}">Log
In</a>
</div>
<div id="content">
<h1>DisCal Network and Services Status</h1>
<h2>Server</h2>
<p th:text="'Connected Clients: ' + ${status.clientCount}"></p>
<p th:text="'Uptime: ' + ${status.uptime}"></p>
<p th:text="'Total Guilds: ' + ${status.totalGuildCount}"></p>
<p th:text="'Total Calendars: ' + ${status.calendarCount}"></p>
<p th:text="'Total Announcements: ' + ${status.announcementCount}"></p>
<br>
<hr>
<br>
<h2>API</h2>
<p>Uptime: Not yet tracked</p>
<p>Ping: Not yet tracked</p>
<p>Requests Processed: not yet tracked</p>
<br>
<hr>
<br>
<h2>Clients</h2>
<th:block th:each="client : ${status.clients}">
<div th:id="'client-' + ${client.clientIndex}">
<h3 th:text="'Client Index: ' + ${client.clientIndex}"></h3>
<p th:text="'Guilds: ' + ${client.connectedServers}"></p>
<p th:text="'RAM Used: ' + ${client.memUsed} + 'MB'"></p>
<p>Announcements: Not Yet Tracked</p>
<p th:text="'Uptime: ' + ${client.uptime}"></p>
<p th:text="'Last KeepAlive: ' + ${client.lastKeepAliveHumanReadable}"></p>
<p>Announcement Service: Not yet tracked</p>
<p>Creator Cleaner Service: Not yet tracked</p>
</div>
<br>
</th:block>
</div>
</body>
<footer id="footer">
<p>
<span th:text="'© DreamExposure ' + ${year} + '. All rights reserved.'"></span>
<span> | </span>
<a href="/policy/privacy">Privacy Policy</a>
<span> | </span>
<a href="/policy/tos">Terms of Service</a>
<span> | </span>
<a href="/docs/api/overview">Developer API</a>
<span> | </span>
<a href="https://www.dreamexposure.org">Powered By DreamExposure</a>
<span> | </span>
<span>DisCal is not endorsed or supported by Discord</span>
</p>
</footer>
</html>