-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d7b51eb
commit 5576202
Showing
72 changed files
with
3,439 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright 2023 Ben Fortuna | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.coucal.api; | ||
|
||
import net.fortuna.ical4j.util.RandomUidGenerator; | ||
import net.fortuna.ical4j.util.UidGenerator; | ||
import org.coucal.core.RepositoryManager; | ||
import org.coucal.core.WorkspaceManager; | ||
import org.glassfish.jersey.internal.inject.AbstractBinder; | ||
import org.ical4j.connector.CalendarStore; | ||
import org.ical4j.connector.CardStore; | ||
import org.ical4j.connector.local.LocalCalendarStore; | ||
import org.ical4j.connector.local.LocalCardStore; | ||
|
||
import java.io.File; | ||
|
||
public class ControllerBinder extends AbstractBinder { | ||
|
||
@Override | ||
protected void configure() { | ||
bind(RepositoryManager.class).to(RepositoryManager.class); | ||
bind(WorkspaceManager.class).to(WorkspaceManager.class); | ||
bind(new LocalCalendarStore(new File("build/calendar/store"))).to(CalendarStore.class); | ||
bind(new LocalCardStore(new File("build/card/store"))).to(CardStore.class); | ||
bind(RandomUidGenerator.class).to(UidGenerator.class); | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
src/main/java/org/coucal/api/controller/channel/ChannelOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package org.coucal.api.controller.channel; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import jakarta.ws.rs.*; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Request; | ||
import jakarta.ws.rs.core.Response; | ||
import net.fortuna.ical4j.model.property.Uid; | ||
import net.fortuna.ical4j.vcard.VCard; | ||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
import java.util.Collections; | ||
|
||
/** | ||
* Channels control the ingress and egress of content stored in repositories. Specifically channels can transform | ||
* content to alternate formats for publishing and conform with update mechanisms defined externally. | ||
* | ||
* Channels are managed globally, however each channel definition is specifically linked to a single repository. This | ||
* ensures the internal content structure is not leaked externally, but external updates can still be linked back to | ||
* the corresponding repository. | ||
*/ | ||
public interface ChannelOperations extends ICalendarResponseVariants { | ||
|
||
@GET | ||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) | ||
@Operation(summary = "List channels", | ||
description = "List channel identifiers") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Operation successful"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response listChannels(@Context Request req) { | ||
return ok(Collections::emptyList, req); | ||
} | ||
|
||
@POST | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Operation(summary = "Create a new channel", | ||
description = "Create a new channel from the specified identifier") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "201", description = "Successfully created"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response createChannel(VCard channel, @Context Request req) { | ||
return ok(() -> channel, req); | ||
} | ||
|
||
@GET | ||
@Path("{uid}") | ||
@Operation(summary = "Retrieve a single channel", | ||
description = "Return the latest revision of the channel object with the specified UID property") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Operation successful"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The channel was not found") | ||
}) | ||
default Response getChannel(@PathParam("uid") String uid, @Context Request req) { | ||
VCard channel = new VCard().add(new Uid(uid)); | ||
return ok(() -> channel, req); | ||
} | ||
|
||
@POST | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Path("{uid}") | ||
@Operation(summary = "Create a new revision of an existing channel object", | ||
description = "Create a new revision of an existing channel with the specified UID property.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Successfully updated"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The channel was not found") | ||
}) | ||
default Response updateChannel(@PathParam("uid") String uid, VCard channelMods, @Context Request req) { | ||
channelMods.add(new Uid(uid)); | ||
return ok(() -> channelMods, req); | ||
} | ||
|
||
// @PUT | ||
// @Consumes(MediaType.APPLICATION_JSON) | ||
// @Path("{uid}") | ||
// @Operation(summary = "Overwrite a channel object", | ||
// description = "Replace all revisions of a channel (if it exists) with the specified UID property" + | ||
// " using the specified payload") | ||
// @ApiResponses(value = { | ||
// @ApiResponse(responseCode = "200", description = "Successfully replaced"), | ||
// @ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
// }) | ||
default Response setChannel(@PathParam("uid") String uid, VCard channel, @Context Request req) { | ||
channel.add(new Uid(uid)); | ||
return ok(() -> channel, req); | ||
} | ||
|
||
@DELETE | ||
@Path("{uid}") | ||
@Operation(summary = "Delete a channel object", | ||
description = "Remove all revisions of an existing channel with the specified UID property.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Successfully deleted"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response deleteChannel(@PathParam("uid") String uid, @Context Request req) { | ||
VCard channel = new VCard().add(new Uid(uid)); | ||
return ok(() -> channel, req); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/org/coucal/api/controller/channel/ChannelsController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.coucal.api.controller.channel; | ||
|
||
import jakarta.ws.rs.Path; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
@Path("/channels") | ||
public class ChannelsController implements ChannelOperations { | ||
|
||
private static final String CHANNELS_COLLECTION = "channels"; | ||
|
||
private static final String CHANNELS_WORKSPACE = "system"; | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(ChannelsController.class); | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/org/coucal/api/controller/channel/chat/ChatOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package org.coucal.api.controller.channel.chat; | ||
|
||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
public interface ChatOperations extends ICalendarResponseVariants { | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/org/coucal/api/controller/channel/email/EmailQuarantineController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.coucal.api.controller.channel.email; | ||
|
||
import jakarta.ws.rs.Path; | ||
|
||
@Path("/channels/{channel}/email") | ||
public class EmailQuarantineController implements EmailQuarantineOperations { | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/org/coucal/api/controller/channel/email/EmailQuarantineOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.coucal.api.controller.channel.email; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.PathParam; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Request; | ||
import jakarta.ws.rs.core.Response; | ||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
import java.util.Collections; | ||
|
||
/** | ||
* An Email channel differs from other channels in that content is not transferred via HTTP, but via SMTP and | ||
* other Email-related protocols. However, Email channels still require some API functionality for triggering | ||
* send, receive and other workflows. | ||
* | ||
* Also unlike most channel types, Email channels require an approval step for specific content updates, such as | ||
* registering new events. This is required to combat potential spam content from unknown sources. | ||
*/ | ||
public interface EmailQuarantineOperations extends ICalendarResponseVariants { | ||
|
||
@GET | ||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) | ||
@Operation(summary = "List quarantine queue", | ||
description = "List content that has been quarantined pending approval") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Operation successful"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response listQuarantineQueue(@PathParam("channel") String channel, @Context Request req) { | ||
return ok(Collections::emptyList, req); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/java/org/coucal/api/controller/channel/webhooks/IFTTTWebhookOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package org.coucal.api.controller.channel.webhooks; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Request; | ||
import jakarta.ws.rs.core.Response; | ||
import net.fortuna.ical4j.model.component.VEvent; | ||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
/** | ||
* An IFTTT Webhook supports requests and updates from an "If this, then that (IFTTT)" applet. | ||
* | ||
* An IFTTT Webhook requires authentication so that content is implicitly verified and can be applied to the | ||
* target repository without an approval step. | ||
*/ | ||
public interface IFTTTWebhookOperations extends ICalendarResponseVariants { | ||
|
||
@POST | ||
@Path("create_event") | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Operation(summary = "Create a new event", | ||
description = "Create a new event from an IFTT invocation") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Success"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response createEvent(VEvent event, @Context Request req) { | ||
return ok(() -> null, req); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/org/coucal/api/controller/channel/webhooks/IFTTTWebhooksController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.coucal.api.controller.channel.webhooks; | ||
|
||
import jakarta.ws.rs.Path; | ||
|
||
@Path("/channels/{channel}/ifttt/v1/actions") | ||
public class IFTTTWebhooksController implements IFTTTWebhookOperations { | ||
} |
100 changes: 100 additions & 0 deletions
100
src/main/java/org/coucal/api/controller/channel/webmention/WebMentionOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package org.coucal.api.controller.channel.webmention; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import jakarta.ws.rs.*; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Request; | ||
import jakarta.ws.rs.core.Response; | ||
import net.fortuna.ical4j.model.component.VToDo; | ||
import net.fortuna.ical4j.model.property.Status; | ||
import net.fortuna.ical4j.model.property.Uid; | ||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
import java.util.Collections; | ||
|
||
/** | ||
* When an external site registers a new Webmention via a POST call to the registration endpoint, a new | ||
* VTODO object is created with concept LINK_REGISTRATION. Periodically the repository owner(s) should check | ||
* for new registrations and approve or reject accordingly. | ||
* | ||
* Upon approval the content corresponding to the source URL (i.e. has a matching URL property) will be updated | ||
* with a new LINK property of type "replies". | ||
* | ||
* A Webmention channel differs from most other channels in that it requires an approval step to apply incoming | ||
* changes. This is because the endpoint is unauthenticated and the validity of link registrations must be | ||
* verified. | ||
*/ | ||
public interface WebMentionOperations extends ICalendarResponseVariants { | ||
|
||
@GET | ||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) | ||
@Operation(summary = "List link registrations", | ||
description = "List link registrations for the specified repository") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Operation successful"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response listLinkRegistrations(@PathParam("channel") String channel, @Context Request req) { | ||
return ok(Collections::emptyList, req); | ||
} | ||
|
||
@POST | ||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) | ||
@Operation(summary = "Register a Webmention link", | ||
description = "Create a new link from the specified form data") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "201", description = "Successfully created"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response registerLink(@PathParam("channel") String channel, @FormParam("source") String source, | ||
@FormParam("target") String target, @Context Request req) { | ||
VToDo linkRegistration = new VToDo(); | ||
return ok(() -> linkRegistration, req); | ||
} | ||
|
||
@GET | ||
@Path("{uid}") | ||
@Operation(summary = "Retrieve a single link registration", | ||
description = "Return the latest revision of the link registration with the specified UID property") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Operation successful"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The registration was not found") | ||
}) | ||
default Response getLinkRegistration(@PathParam("channel") String channel, @PathParam("uid") String uid, | ||
@Context Request req) { | ||
VToDo linkRegistration = new VToDo().withProperty(new Uid(uid)).getFluentTarget(); | ||
return ok(() -> linkRegistration, req); | ||
} | ||
|
||
@POST | ||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) | ||
@Path("{uid}") | ||
@Operation(summary = "Create a new revision of an existing link registration", | ||
description = "Create a new revision of an existing link registration with the specified UID property.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Successfully updated"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The link registration was not found") | ||
}) | ||
default Response updateLinkRegistrationStatus(@PathParam("channel") String channel, @PathParam("uid") String uid, | ||
@FormParam("status") String status, @Context Request req) { | ||
VToDo linkRegistration = new VToDo().add(new Uid(uid)).replace(new Status(status)); | ||
return ok(() -> linkRegistration, req); | ||
} | ||
|
||
@DELETE | ||
@Path("{uid}") | ||
@Operation(summary = "Delete a link registration", | ||
description = "Remove all revisions of an existing link registration with the specified UID property.") | ||
@ApiResponses(value = { | ||
@ApiResponse(responseCode = "200", description = "Successfully deleted"), | ||
@ApiResponse(responseCode = "404", description = "Not found - The repository was not found") | ||
}) | ||
default Response deleteLinkRegistration(@PathParam("channel") String channel, @PathParam("uid") String uid, | ||
@Context Request req) { | ||
VToDo linkRegistration = new VToDo().withProperty(new Uid(uid)).getFluentTarget(); | ||
return ok(() -> linkRegistration, req); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/org/coucal/api/controller/channel/webmention/WebMentionsController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.coucal.api.controller.channel.webmention; | ||
|
||
import jakarta.ws.rs.Path; | ||
|
||
@Path("/channels/{channel}/webmention") | ||
public class WebMentionsController implements WebMentionOperations { | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/org/coucal/api/controller/channel/websub/HubController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.coucal.api.controller.channel.websub; | ||
|
||
/** | ||
* Responsible for subscription management such as subscribe/unsubscribe requests. | ||
*/ | ||
public class HubController { | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/org/coucal/api/controller/channel/websub/SubController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.coucal.api.controller.channel.websub; | ||
|
||
/** | ||
* Responsible for managing incoming content distribution from active subscriptions. | ||
*/ | ||
public class SubController { | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/org/coucal/api/controller/channel/websub/WebSubOperations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package org.coucal.api.controller.channel.websub; | ||
|
||
import org.coucal.api.controller.ICalendarResponseVariants; | ||
|
||
public interface WebSubOperations extends ICalendarResponseVariants { | ||
} |
Oops, something went wrong.