mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Migrate REST classes to Kotlin and upgrade Javalin
This commit is contained in:
9
.idea/codeStyles/Project.xml
generated
9
.idea/codeStyles/Project.xml
generated
@@ -36,6 +36,9 @@
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
@@ -258,11 +261,7 @@
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="1" />
|
||||
|
||||
@@ -14,11 +14,12 @@ dependencies {
|
||||
implementation project(path: ':briar-core', configuration: 'default')
|
||||
implementation project(path: ':bramble-java', configuration: 'default')
|
||||
|
||||
implementation 'io.javalin:javalin:1.7.0'
|
||||
implementation 'io.javalin:javalin:2.1.0'
|
||||
implementation 'org.slf4j:slf4j-simple:1.7.25'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
|
||||
|
||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
|
||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.briarproject.bramble.identity;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class OutputAuthor {
|
||||
|
||||
public final byte[] id;
|
||||
public final String name;
|
||||
public final byte[] publicKey;
|
||||
|
||||
public OutputAuthor(Author author) {
|
||||
this.id = author.getId().getBytes();
|
||||
this.name = author.getName();
|
||||
this.publicKey = author.getPublicKey();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.briarproject.bramble.identity
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Immutable
|
||||
@Suppress("unused")
|
||||
class OutputAuthor(author: Author) {
|
||||
|
||||
val id: ByteArray = author.id.bytes
|
||||
val name: String = author.name
|
||||
val publicKey: ByteArray = author.publicKey
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.briarproject.briar.headless
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author
|
||||
import org.briarproject.bramble.identity.OutputAuthor
|
||||
import org.briarproject.briar.api.blog.MessageType
|
||||
|
||||
fun Author.output() = OutputAuthor(this)
|
||||
|
||||
fun Author.Status.output() = name.toLowerCase()
|
||||
|
||||
fun MessageType.output() = name.toLowerCase()
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
package org.briarproject.briar.headless;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.briar.headless.blogs.BlogController;
|
||||
import org.briarproject.briar.headless.contact.ContactController;
|
||||
import org.briarproject.briar.headless.forums.ForumController;
|
||||
import org.briarproject.briar.headless.messaging.MessagingController;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.javalin.Javalin;
|
||||
|
||||
import static io.javalin.ApiBuilder.get;
|
||||
import static io.javalin.ApiBuilder.path;
|
||||
import static io.javalin.ApiBuilder.post;
|
||||
import static io.javalin.event.EventType.SERVER_START_FAILED;
|
||||
import static io.javalin.event.EventType.SERVER_STOPPED;
|
||||
import static java.lang.Runtime.getRuntime;
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class Router {
|
||||
|
||||
private final BriarService briarService;
|
||||
private final ContactController contactController;
|
||||
private final MessagingController messagingController;
|
||||
private final ForumController forumController;
|
||||
private final BlogController blogController;
|
||||
|
||||
@Inject
|
||||
public Router(BriarService briarService,
|
||||
ContactController contactController,
|
||||
MessagingController messagingController,
|
||||
ForumController forumController,
|
||||
BlogController blogController) {
|
||||
this.briarService = briarService;
|
||||
this.contactController = contactController;
|
||||
this.messagingController = messagingController;
|
||||
this.forumController = forumController;
|
||||
this.blogController = blogController;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
briarService.start();
|
||||
getRuntime().addShutdownHook(new Thread(briarService::stop));
|
||||
|
||||
Javalin app = Javalin.create()
|
||||
.port(7000)
|
||||
.disableStartupBanner()
|
||||
.enableStandardRequestLogging()
|
||||
.enableRouteOverview("/")
|
||||
.enableDynamicGzip()
|
||||
.event(SERVER_START_FAILED, event -> briarService.stop())
|
||||
.event(SERVER_STOPPED, event -> briarService.stop())
|
||||
.start();
|
||||
|
||||
app.routes(() -> {
|
||||
path("/contacts", () -> get(contactController::list));
|
||||
path("/messages/:contactId", () -> {
|
||||
get(messagingController::list);
|
||||
post(messagingController::write);
|
||||
});
|
||||
path("/forums", () -> {
|
||||
get(forumController::list);
|
||||
post(forumController::create);
|
||||
});
|
||||
path("/blogs", () -> path("/posts", () -> {
|
||||
get(blogController::listPosts);
|
||||
post(blogController::createPost);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.briarproject.briar.headless
|
||||
|
||||
import io.javalin.Javalin
|
||||
import io.javalin.JavalinEvent.SERVER_START_FAILED
|
||||
import io.javalin.JavalinEvent.SERVER_STOPPED
|
||||
import io.javalin.apibuilder.ApiBuilder.*
|
||||
import org.briarproject.briar.headless.blogs.BlogController
|
||||
import org.briarproject.briar.headless.contact.ContactController
|
||||
import org.briarproject.briar.headless.forums.ForumController
|
||||
import org.briarproject.briar.headless.messaging.MessagingController
|
||||
import java.lang.Runtime.getRuntime
|
||||
import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
class Router @Inject
|
||||
constructor(
|
||||
private val briarService: BriarService,
|
||||
private val contactController: ContactController,
|
||||
private val messagingController: MessagingController,
|
||||
private val forumController: ForumController,
|
||||
private val blogController: BlogController
|
||||
) {
|
||||
|
||||
fun start() {
|
||||
briarService.start()
|
||||
getRuntime().addShutdownHook(Thread(Runnable { briarService.stop() }))
|
||||
|
||||
val app = Javalin.create()
|
||||
.port(7000)
|
||||
.disableStartupBanner()
|
||||
.enableDebugLogging()
|
||||
.enableCaseSensitiveUrls()
|
||||
.enableRouteOverview("/")
|
||||
.event(SERVER_START_FAILED) { stop() }
|
||||
.event(SERVER_STOPPED) { stop() }
|
||||
.start()
|
||||
|
||||
app.routes {
|
||||
path("/contacts") {
|
||||
get { ctx -> contactController.list(ctx) }
|
||||
}
|
||||
path("/messages/:contactId") {
|
||||
get { ctx -> messagingController.list(ctx) }
|
||||
post { ctx -> messagingController.write(ctx) }
|
||||
}
|
||||
path("/forums") {
|
||||
get { ctx -> forumController.list(ctx) }
|
||||
post { ctx -> forumController.create(ctx) }
|
||||
}
|
||||
path("/blogs") {
|
||||
path("/posts") {
|
||||
get { ctx -> blogController.listPosts(ctx) }
|
||||
post { ctx -> blogController.createPost(ctx) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stop() {
|
||||
briarService.stop()
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package org.briarproject.briar.headless.blogs;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.briar.api.blog.Blog;
|
||||
import org.briarproject.briar.api.blog.BlogManager;
|
||||
import org.briarproject.briar.api.blog.BlogPost;
|
||||
import org.briarproject.briar.api.blog.BlogPostFactory;
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.javalin.Context;
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BlogController {
|
||||
|
||||
private final BlogManager blogManager;
|
||||
private final BlogPostFactory blogPostFactory;
|
||||
private final IdentityManager identityManager;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
public BlogController(BlogManager blogManager,
|
||||
BlogPostFactory blogPostFactory, IdentityManager identityManager,
|
||||
Clock clock) {
|
||||
this.blogManager = blogManager;
|
||||
this.blogPostFactory = blogPostFactory;
|
||||
this.identityManager = identityManager;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public Context listPosts(Context ctx) throws DbException {
|
||||
List<OutputBlogPost> posts = new ArrayList<>();
|
||||
for (Blog b : blogManager.getBlogs()) {
|
||||
Collection<BlogPostHeader> headers =
|
||||
blogManager.getPostHeaders(b.getId());
|
||||
for (BlogPostHeader header : headers) {
|
||||
String body = blogManager.getPostBody(header.getId());
|
||||
OutputBlogPost post = new OutputBlogPost(header, body);
|
||||
posts.add(post);
|
||||
}
|
||||
}
|
||||
return ctx.json(posts);
|
||||
}
|
||||
|
||||
public Context createPost(Context ctx)
|
||||
throws DbException, GeneralSecurityException, FormatException {
|
||||
String text = ctx.formParam("text");
|
||||
if (text == null || text.length() < 1) {
|
||||
return ctx.status(500).result("Expecting Blog text");
|
||||
} else {
|
||||
LocalAuthor author = identityManager.getLocalAuthor();
|
||||
Blog blog = blogManager.getPersonalBlog(author);
|
||||
long now = clock.currentTimeMillis();
|
||||
BlogPost post = blogPostFactory
|
||||
.createBlogPost(blog.getId(), now, null, author, text);
|
||||
blogManager.addLocalPost(post);
|
||||
BlogPostHeader header = blogManager
|
||||
.getPostHeader(blog.getId(), post.getMessage().getId());
|
||||
OutputBlogPost outputPost = new OutputBlogPost(header, text);
|
||||
return ctx.json(outputPost);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.briarproject.briar.headless.blogs
|
||||
|
||||
import io.javalin.BadRequestResponse
|
||||
import io.javalin.Context
|
||||
import org.briarproject.bramble.api.identity.IdentityManager
|
||||
import org.briarproject.bramble.api.system.Clock
|
||||
import org.briarproject.briar.api.blog.BlogManager
|
||||
import org.briarproject.briar.api.blog.BlogPostFactory
|
||||
import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
class BlogController @Inject
|
||||
constructor(
|
||||
private val blogManager: BlogManager,
|
||||
private val blogPostFactory: BlogPostFactory,
|
||||
private val identityManager: IdentityManager,
|
||||
private val clock: Clock
|
||||
) {
|
||||
|
||||
fun listPosts(ctx: Context): Context {
|
||||
val posts = blogManager.blogs.flatMap { blog ->
|
||||
blogManager.getPostHeaders(blog.id).map { header ->
|
||||
val body = blogManager.getPostBody(header.id)
|
||||
header.output(body)
|
||||
}
|
||||
}
|
||||
return ctx.json(posts)
|
||||
}
|
||||
|
||||
fun createPost(ctx: Context): Context {
|
||||
val text = ctx.formParam("text")
|
||||
if (text == null || text.isEmpty())
|
||||
throw BadRequestResponse("Expecting Blog text")
|
||||
|
||||
val author = identityManager.localAuthor
|
||||
val blog = blogManager.getPersonalBlog(author)
|
||||
val now = clock.currentTimeMillis()
|
||||
val post = blogPostFactory.createBlogPost(blog.id, now, null, author, text)
|
||||
blogManager.addLocalPost(post)
|
||||
val header = blogManager.getPostHeader(blog.id, post.message.id)
|
||||
return ctx.json(header.output(text))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.briarproject.briar.headless.blogs
|
||||
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader
|
||||
|
||||
internal fun BlogPostHeader.output(body: String) = OutputBlogPost(this, body)
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.briarproject.briar.headless.blogs;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.identity.OutputAuthor;
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
class OutputBlogPost {
|
||||
|
||||
public final String body;
|
||||
public final OutputAuthor author;
|
||||
public final String authorStatus, type;
|
||||
public final byte[] id;
|
||||
@Nullable
|
||||
public final byte[] parentId;
|
||||
public final boolean read, rssFeed;
|
||||
public final long timestamp, timestampReceived;
|
||||
|
||||
OutputBlogPost(BlogPostHeader header, String body) {
|
||||
this.body = body;
|
||||
this.author = new OutputAuthor(header.getAuthor());
|
||||
this.authorStatus = header.getAuthorStatus().name().toLowerCase();
|
||||
this.type = header.getType().name().toLowerCase();
|
||||
this.id = header.getId().getBytes();
|
||||
this.parentId = header.getParentId() == null ? null :
|
||||
header.getParentId().getBytes();
|
||||
this.read = header.isRead();
|
||||
this.rssFeed = header.isRssFeed();
|
||||
this.timestamp = header.getTimestamp();
|
||||
this.timestampReceived = header.getTimeReceived();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.briarproject.briar.headless.blogs
|
||||
|
||||
import org.briarproject.bramble.identity.OutputAuthor
|
||||
import org.briarproject.briar.api.blog.BlogPostHeader
|
||||
import org.briarproject.briar.headless.output
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Immutable
|
||||
@Suppress("unused")
|
||||
internal class OutputBlogPost(header: BlogPostHeader, val body: String) {
|
||||
|
||||
val author: OutputAuthor = OutputAuthor(header.author)
|
||||
val authorStatus: String = header.authorStatus.output()
|
||||
val type = header.type.output()
|
||||
val id: ByteArray = header.id.bytes
|
||||
val parentId = header.parentId?.bytes
|
||||
val read = header.isRead
|
||||
val rssFeed = header.isRssFeed
|
||||
val timestamp = header.timestamp
|
||||
val timestampReceived = header.timeReceived
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.briarproject.briar.headless.contact;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.javalin.Context;
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
@NotNullByDefault
|
||||
public class ContactController {
|
||||
|
||||
private final ContactManager contactManager;
|
||||
|
||||
@Inject
|
||||
public ContactController(ContactManager contactManager) {
|
||||
this.contactManager = contactManager;
|
||||
}
|
||||
|
||||
public Context list(Context ctx) throws DbException {
|
||||
Collection<Contact> contacts = contactManager.getActiveContacts();
|
||||
List<OutputContact> outputContacts = new ArrayList<>(contacts.size());
|
||||
for (Contact c : contacts) {
|
||||
outputContacts.add(new OutputContact(c));
|
||||
}
|
||||
return ctx.json(outputContacts);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.briar.headless.contact
|
||||
|
||||
import io.javalin.Context
|
||||
import org.briarproject.bramble.api.contact.ContactManager
|
||||
import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
class ContactController @Inject
|
||||
constructor(private val contactManager: ContactManager) {
|
||||
|
||||
fun list(ctx: Context): Context {
|
||||
val contacts = contactManager.activeContacts.map { contact ->
|
||||
contact.output()
|
||||
}
|
||||
return ctx.json(contacts)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.briarproject.briar.headless.contact
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact
|
||||
|
||||
internal fun Contact.output() = OutputContact(this)
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.briarproject.briar.headless.contact;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.identity.OutputAuthor;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class OutputContact {
|
||||
|
||||
public final int id;
|
||||
public final OutputAuthor author;
|
||||
public final boolean verified;
|
||||
|
||||
public OutputContact(Contact c) {
|
||||
this.id = c.getId().getInt();
|
||||
this.author = new OutputAuthor(c.getAuthor());
|
||||
this.verified = c.isVerified();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.briarproject.briar.headless.contact
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact
|
||||
import org.briarproject.briar.headless.output
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Immutable
|
||||
@Suppress("unused")
|
||||
internal class OutputContact(c: Contact) {
|
||||
|
||||
val id = c.id.int
|
||||
val author = c.author.output()
|
||||
val verified = c.isVerified
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.briarproject.briar.headless.forums
|
||||
|
||||
import org.briarproject.briar.api.forum.Forum
|
||||
|
||||
internal fun Forum.output() = OutputForum(this)
|
||||
|
||||
internal fun Collection<Forum>.output() = map { it.output() }
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.briarproject.briar.headless.forums;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.briar.api.forum.Forum;
|
||||
import org.briarproject.briar.api.forum.ForumManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.javalin.Context;
|
||||
|
||||
import static io.javalin.translator.json.JavalinJsonPlugin.getObjectToJsonMapper;
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class ForumController {
|
||||
|
||||
private final ForumManager forumManager;
|
||||
|
||||
@Inject
|
||||
public ForumController(ForumManager forumManager) {
|
||||
this.forumManager = forumManager;
|
||||
}
|
||||
|
||||
public Context list(Context ctx) throws DbException {
|
||||
Collection<Forum> forums = forumManager.getForums();
|
||||
return ctx.result(getObjectToJsonMapper().map(forums));
|
||||
}
|
||||
|
||||
public Context create(Context ctx) throws DbException {
|
||||
String name = ctx.formParam("name");
|
||||
if (name == null || name.length() < 1) {
|
||||
return ctx.status(500).result("Expecting Forum Name");
|
||||
} else {
|
||||
Forum forum = forumManager.addForum(name);
|
||||
return ctx.result(getObjectToJsonMapper().map(forum));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.briar.headless.forums
|
||||
|
||||
import io.javalin.BadRequestResponse
|
||||
import io.javalin.Context
|
||||
import org.briarproject.briar.api.forum.ForumManager
|
||||
import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
class ForumController @Inject
|
||||
constructor(private val forumManager: ForumManager) {
|
||||
|
||||
fun list(ctx: Context): Context {
|
||||
return ctx.json(forumManager.forums.output())
|
||||
}
|
||||
|
||||
fun create(ctx: Context): Context {
|
||||
val name = ctx.formParam("name")
|
||||
if (name == null || name.isEmpty())
|
||||
throw BadRequestResponse("Expecting Forum Name")
|
||||
return ctx.json(forumManager.addForum(name).output())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.briar.headless.forums
|
||||
|
||||
import org.briarproject.briar.api.forum.Forum
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Immutable
|
||||
@Suppress("unused")
|
||||
internal class OutputForum(forum: Forum) {
|
||||
|
||||
val name: String = forum.name
|
||||
val id: ByteArray = forum.id.bytes
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.briarproject.briar.headless.messaging
|
||||
|
||||
import org.briarproject.briar.api.messaging.PrivateMessage
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
||||
|
||||
internal fun PrivateMessageHeader.output(body: String) = OutputPrivateMessage(this, body)
|
||||
|
||||
internal fun PrivateMessage.output(body: String) = OutputPrivateMessage(this, body)
|
||||
@@ -1,97 +0,0 @@
|
||||
package org.briarproject.briar.headless.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import io.javalin.Context;
|
||||
|
||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
@NotNullByDefault
|
||||
public class MessagingController {
|
||||
|
||||
private final MessagingManager messagingManager;
|
||||
private final PrivateMessageFactory privateMessageFactory;
|
||||
private final ContactManager contactManager;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
public MessagingController(MessagingManager messagingManager,
|
||||
PrivateMessageFactory privateMessageFactory,
|
||||
ContactManager contactManager,
|
||||
Clock clock) {
|
||||
this.messagingManager = messagingManager;
|
||||
this.privateMessageFactory = privateMessageFactory;
|
||||
this.contactManager = contactManager;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public Context list(Context ctx) throws DbException {
|
||||
Contact contact = getContact(ctx);
|
||||
if (contact == null) return ctx.status(404);
|
||||
|
||||
Collection<PrivateMessageHeader> headers =
|
||||
messagingManager.getMessageHeaders(contact.getId());
|
||||
List<OutputPrivateMessage> messages = new ArrayList<>(headers.size());
|
||||
for (PrivateMessageHeader header : headers) {
|
||||
String body = messagingManager.getMessageBody(header.getId());
|
||||
messages.add(new OutputPrivateMessage(header, body));
|
||||
}
|
||||
return ctx.json(messages);
|
||||
}
|
||||
|
||||
public Context write(Context ctx) throws DbException, FormatException {
|
||||
Contact contact = getContact(ctx);
|
||||
if (contact == null) return ctx.status(404);
|
||||
|
||||
String message = ctx.formParam("message");
|
||||
if (message == null || message.length() < 1)
|
||||
return ctx.status(500).result("Expecting Message text");
|
||||
if (message.length() > MAX_PRIVATE_MESSAGE_BODY_LENGTH)
|
||||
return ctx.status(500).result("Message text too large");
|
||||
|
||||
Group group = messagingManager.getContactGroup(contact);
|
||||
long now = clock.currentTimeMillis();
|
||||
PrivateMessage m = privateMessageFactory
|
||||
.createPrivateMessage(group.getId(), now, message);
|
||||
|
||||
messagingManager.addLocalMessage(m);
|
||||
return ctx.json(new OutputPrivateMessage(m, message));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Contact getContact(Context ctx) throws DbException {
|
||||
String contactString = ctx.param("contactId");
|
||||
if (contactString == null) return null;
|
||||
int contactInt = Integer.parseInt(contactString);
|
||||
ContactId contactId = new ContactId(contactInt);
|
||||
try {
|
||||
return contactManager.getContact(contactId);
|
||||
} catch (NoSuchContactException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.briarproject.briar.headless.messaging
|
||||
|
||||
import io.javalin.BadRequestResponse
|
||||
import io.javalin.Context
|
||||
import io.javalin.NotFoundResponse
|
||||
import org.briarproject.bramble.api.contact.Contact
|
||||
import org.briarproject.bramble.api.contact.ContactId
|
||||
import org.briarproject.bramble.api.contact.ContactManager
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException
|
||||
import org.briarproject.bramble.api.system.Clock
|
||||
import org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH
|
||||
import org.briarproject.briar.api.messaging.MessagingManager
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageFactory
|
||||
import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
class MessagingController @Inject
|
||||
constructor(
|
||||
private val messagingManager: MessagingManager,
|
||||
private val privateMessageFactory: PrivateMessageFactory,
|
||||
private val contactManager: ContactManager,
|
||||
private val clock: Clock
|
||||
) {
|
||||
|
||||
fun list(ctx: Context): Context {
|
||||
val contact = getContact(ctx)
|
||||
|
||||
val messages = messagingManager.getMessageHeaders(contact.id).map { header ->
|
||||
val body = messagingManager.getMessageBody(header.id)
|
||||
header.output(body)
|
||||
}
|
||||
return ctx.json(messages)
|
||||
}
|
||||
|
||||
fun write(ctx: Context): Context {
|
||||
val contact = getContact(ctx)
|
||||
|
||||
val message = ctx.formParam("message")
|
||||
if (message == null || message.isEmpty())
|
||||
throw BadRequestResponse("Expecting Message text")
|
||||
if (message.length > MAX_PRIVATE_MESSAGE_BODY_LENGTH)
|
||||
throw BadRequestResponse("Message text too large")
|
||||
|
||||
val group = messagingManager.getContactGroup(contact)
|
||||
val now = clock.currentTimeMillis()
|
||||
val m = privateMessageFactory.createPrivateMessage(group.id, now, message)
|
||||
|
||||
messagingManager.addLocalMessage(m)
|
||||
return ctx.json(m.output(message))
|
||||
}
|
||||
|
||||
private fun getContact(ctx: Context): Contact {
|
||||
val contactString = ctx.pathParam("contactId")
|
||||
val contactInt = Integer.parseInt(contactString)
|
||||
val contactId = ContactId(contactInt)
|
||||
return try {
|
||||
contactManager.getContact(contactId)
|
||||
} catch (e: NoSuchContactException) {
|
||||
throw NotFoundResponse()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package org.briarproject.briar.headless.messaging;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class OutputPrivateMessage {
|
||||
|
||||
public final String body;
|
||||
public final long timestamp;
|
||||
public final boolean read, seen, sent, local;
|
||||
public final byte[] id, groupId;
|
||||
|
||||
OutputPrivateMessage(PrivateMessageHeader header, String body) {
|
||||
this.body = body;
|
||||
this.timestamp = header.getTimestamp();
|
||||
this.read = header.isRead();
|
||||
this.seen = header.isSeen();
|
||||
this.sent = header.isSent();
|
||||
this.local = header.isLocal();
|
||||
this.id = header.getId().getBytes();
|
||||
this.groupId = header.getGroupId().getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only meant for own {@link PrivateMessage}s directly after creation.
|
||||
*/
|
||||
OutputPrivateMessage(PrivateMessage m, String body) {
|
||||
this.body = body;
|
||||
this.timestamp = m.getMessage().getTimestamp();
|
||||
this.read = true;
|
||||
this.seen = true;
|
||||
this.sent = false;
|
||||
this.local = true;
|
||||
this.id = m.getMessage().getId().getBytes();
|
||||
this.groupId = m.getMessage().getGroupId().getBytes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.briarproject.briar.headless.messaging
|
||||
|
||||
import org.briarproject.briar.api.messaging.PrivateMessage
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
||||
@Immutable
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
internal class OutputPrivateMessage {
|
||||
|
||||
val body: String
|
||||
val timestamp: Long
|
||||
val read: Boolean
|
||||
val seen: Boolean
|
||||
val sent: Boolean
|
||||
val local: Boolean
|
||||
val id: ByteArray
|
||||
val groupId: ByteArray
|
||||
|
||||
internal constructor(header: PrivateMessageHeader, body: String) {
|
||||
this.body = body
|
||||
this.timestamp = header.timestamp
|
||||
this.read = header.isRead
|
||||
this.seen = header.isSeen
|
||||
this.sent = header.isSent
|
||||
this.local = header.isLocal
|
||||
this.id = header.id.bytes
|
||||
this.groupId = header.groupId.bytes
|
||||
}
|
||||
|
||||
/**
|
||||
* Only meant for own [PrivateMessage]s directly after creation.
|
||||
*/
|
||||
internal constructor(m: PrivateMessage, body: String) {
|
||||
this.body = body
|
||||
this.timestamp = m.message.timestamp
|
||||
this.read = true
|
||||
this.seen = true
|
||||
this.sent = false
|
||||
this.local = true
|
||||
this.id = m.message.id.bytes
|
||||
this.groupId = m.message.groupId.bytes
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ dependencyVerification {
|
||||
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||
'io.javalin:javalin:1.7.0:javalin-1.7.0.jar:d97d2044a7b050a3b6564c9a99a0a94a4c6d8c57818033cf0d8236bc90a8069b',
|
||||
'io.javalin:javalin:2.1.0:javalin-2.1.0.jar:d52264afbecddd1a8926a6d3b6f84ca534afa4d3997176c99e96ca2e0874577a',
|
||||
'io.mockk:mockk-agent-api:1.8.6:mockk-agent-api-1.8.6.jar:613512c66538e6349e03df641a868f4ee324f13e2e1dbd67a0ed388aa664a444',
|
||||
'io.mockk:mockk-agent-common:1.8.6:mockk-agent-common-1.8.6.jar:cb7cb26fae5bfd3c89090858548990f311b27f673b9efa9d0c94f97c463b2863',
|
||||
'io.mockk:mockk-agent-jvm:1.8.6:mockk-agent-jvm-1.8.6.jar:3f30b98d23ada8b5a44d75b43cd58fc03252fcb96939ff31e7ad659818af1e5d',
|
||||
@@ -20,29 +20,28 @@ dependencyVerification {
|
||||
'net.bytebuddy:byte-buddy-agent:1.8.8:byte-buddy-agent-1.8.8.jar:dc1a2dcefe72731fa89ae84e32231c74d545ccf8216c79865096e546f20c57e8',
|
||||
'net.bytebuddy:byte-buddy:1.8.8:byte-buddy-1.8.8.jar:30aed1ae2ee5261b1d2f0e98ec3fcb40755c3f61b378089fb65d56098df1f16b',
|
||||
'org.apiguardian:apiguardian-api:1.0.0:apiguardian-api-1.0.0.jar:1f58b77470d8d147a0538d515347dd322f49a83b9e884b8970051160464b65b3',
|
||||
'org.eclipse.jetty.websocket:websocket-api:9.4.9.v20180320:websocket-api-9.4.9.v20180320.jar:985b737f5c0928d48fc9890b261cbed096625350b9c0e321f44bde8a803c85ec',
|
||||
'org.eclipse.jetty.websocket:websocket-client:9.4.9.v20180320:websocket-client-9.4.9.v20180320.jar:2f5c6a64987ac27a21862a6349bd2b1d25545cba9aa68084e50ef77af7adcd7d',
|
||||
'org.eclipse.jetty.websocket:websocket-common:9.4.9.v20180320:websocket-common-9.4.9.v20180320.jar:26fc6bba6ad8e6522b27d5f397429c349264bcea076bd186ad885ef0cd0a73c8',
|
||||
'org.eclipse.jetty.websocket:websocket-server:9.4.9.v20180320:websocket-server-9.4.9.v20180320.jar:93ebcfa8e8af9876491d1524b4e8d273be8a7576e18b75ef699bad9564f76de2',
|
||||
'org.eclipse.jetty.websocket:websocket-servlet:9.4.9.v20180320:websocket-servlet-9.4.9.v20180320.jar:cac3f46db4917722b860e194907c36c251d2765ca1ce8323085c47cefafec52b',
|
||||
'org.eclipse.jetty:jetty-client:9.4.9.v20180320:jetty-client-9.4.9.v20180320.jar:d6d8eca17806261a96137f64ad14c33feed26ba031c92180162961589141072d',
|
||||
'org.eclipse.jetty:jetty-http:9.4.9.v20180320:jetty-http-9.4.9.v20180320.jar:823e76a9565f8a98c96542745f34560e2a6a9dfa6fbe320614061ad9b17b950b',
|
||||
'org.eclipse.jetty:jetty-io:9.4.9.v20180320:jetty-io-9.4.9.v20180320.jar:fffa35ca529d3267ad80d87f83ad4f6796b0981ae21d3ff621151bbe0a8f4155',
|
||||
'org.eclipse.jetty:jetty-security:9.4.9.v20180320:jetty-security-9.4.9.v20180320.jar:5cbaeb9837aa331a8ee918724786655c6f60f8cc65ab84e03ff587bc212a2327',
|
||||
'org.eclipse.jetty:jetty-server:9.4.9.v20180320:jetty-server-9.4.9.v20180320.jar:b45869789b8f8081c1c75c059b4fd262d2fd440fa676c54bc753365fdd1f82d6',
|
||||
'org.eclipse.jetty:jetty-servlet:9.4.9.v20180320:jetty-servlet-9.4.9.v20180320.jar:a96f8711d4f9d5d4c3fcafa046fb5caefec17eefcbfcd35b6c2e1d5a0549edfc',
|
||||
'org.eclipse.jetty:jetty-util:9.4.9.v20180320:jetty-util-9.4.9.v20180320.jar:86ccb5e178e7001f26a12ec4bf56c522911424a0edf60424f15add8601355fc5',
|
||||
'org.eclipse.jetty:jetty-webapp:9.4.9.v20180320:jetty-webapp-9.4.9.v20180320.jar:7d6c6af12f10a47524e8eabc607226b038100680612ea569f92c030158bd5566',
|
||||
'org.eclipse.jetty:jetty-xml:9.4.9.v20180320:jetty-xml-9.4.9.v20180320.jar:2a0c8e64364cb8d0f483e5e050db6fbd26f0ad9e5098367f8af7928887fa5ece',
|
||||
'org.eclipse.jetty.websocket:websocket-api:9.4.11.v20180605:websocket-api-9.4.11.v20180605.jar:924edcf7fb17f2ff2e541afce7fd692305235e51b5a16f7223d7e8b4de77559d',
|
||||
'org.eclipse.jetty.websocket:websocket-client:9.4.11.v20180605:websocket-client-9.4.11.v20180605.jar:d3c812f80ac18d7031ffe2a324f2f83d8b260a99863be81b81668184ad5f2cca',
|
||||
'org.eclipse.jetty.websocket:websocket-common:9.4.11.v20180605:websocket-common-9.4.11.v20180605.jar:f00731b8f9d2f2155bd87a2040cdef991fbcd24ff843ff4ba1ab1829bf62c04c',
|
||||
'org.eclipse.jetty.websocket:websocket-server:9.4.11.v20180605:websocket-server-9.4.11.v20180605.jar:0cfa90029d46618116f986cc6aea1c4f2e7408f3c97ad3eb2f92f74aff37279b',
|
||||
'org.eclipse.jetty.websocket:websocket-servlet:9.4.11.v20180605:websocket-servlet-9.4.11.v20180605.jar:76f52b482ad174944e07f552cbfaaa2ccf498063e0a3837bb930eee8a06373aa',
|
||||
'org.eclipse.jetty:jetty-client:9.4.11.v20180605:jetty-client-9.4.11.v20180605.jar:b096ea6ee2607886323791930a470b2e04fb3327459b287ef99647226bd7a09c',
|
||||
'org.eclipse.jetty:jetty-http:9.4.11.v20180605:jetty-http-9.4.11.v20180605.jar:963b75730aa92b0dfbe65fe8a2e413edc88aeb53e8686ba6b1617d7caeb14067',
|
||||
'org.eclipse.jetty:jetty-io:9.4.11.v20180605:jetty-io-9.4.11.v20180605.jar:75c82d6e542a3518e2517c4084c83d8216ec2d2458f8747b8b5c944355ebd732',
|
||||
'org.eclipse.jetty:jetty-security:9.4.11.v20180605:jetty-security-9.4.11.v20180605.jar:5a12b1c69264466004baff33b14fc1555007c86fb2fece2a420c480aa7f8ef56',
|
||||
'org.eclipse.jetty:jetty-server:9.4.11.v20180605:jetty-server-9.4.11.v20180605.jar:b74af5ac482b05c242ed231e00b7c08a0b6649f76f2e039a0885de0cf1376ef8',
|
||||
'org.eclipse.jetty:jetty-servlet:9.4.11.v20180605:jetty-servlet-9.4.11.v20180605.jar:e24f145a6d95c7653ad2fe0c34cf8ce7311effb7eb8ed9399fae63d8af63eaf4',
|
||||
'org.eclipse.jetty:jetty-util:9.4.11.v20180605:jetty-util-9.4.11.v20180605.jar:936e5ed74275c16164cc1eccaeae55900eb00edd9f1b1d3b83d70782dd25f505',
|
||||
'org.eclipse.jetty:jetty-webapp:9.4.11.v20180605:jetty-webapp-9.4.11.v20180605.jar:858f3f16cecb0891f07a4e8d82554201c513bf058c0f65969b366936155b6a36',
|
||||
'org.eclipse.jetty:jetty-xml:9.4.11.v20180605:jetty-xml-9.4.11.v20180605.jar:1780bdaee2b1908e032fbc286bb856d730c4d0c9de39d5e14a1b9c48028c295e',
|
||||
'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.2.61:kotlin-compiler-embeddable-1.2.61.jar:f8165810c61f440a2de6003ed9857d28a1dfc990bacbecee1436610c8ebe565b',
|
||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.41:kotlin-reflect-1.2.41.jar:1bab75771dfa2bb5949cd383ceaedf6f8d354fa0d677804fc5a39e320bab70d3',
|
||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.61:kotlin-reflect-1.2.61.jar:a4f1ed542390f9bf967fb9aff2c232b90988f7ce138a4b7bcc70b754821a8943',
|
||||
'org.jetbrains.kotlin:kotlin-script-runtime:1.2.61:kotlin-script-runtime-1.2.61.jar:793e4c54a8d59cf1f1cda68a7bc6be1ad54c41d771a08d308aa28c2cd304f1b1',
|
||||
'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.2.61:kotlin-scripting-compiler-embeddable-1.2.61.jar:99e0ee865f9c7c8ddcc0975185c69392182311067fe2a6faa72e942185631c1c',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.61:kotlin-stdlib-common-1.2.61.jar:54a6fab7dae0cd7528208e95868fe1869b01b613c3018f2e53dbbad2604f6595',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.41:kotlin-stdlib-jdk7-1.2.41.jar:169ee5879cba8444499243ceea5e6a2cb6ecea5424211cc819f0704501154b35',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.41:kotlin-stdlib-jdk8-1.2.41.jar:b306e0e6735841e31e320bf3260c71d60fc35057cfa87895f23251ee260a64a8',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.41:kotlin-stdlib-1.2.41.jar:f0595b9ed88ddc6fd66bddf68c56c6f2f6c4b17faa51e43e478acad32b05303e',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.61:kotlin-stdlib-jdk7-1.2.61.jar:f02ed7a640323b162c798a7834b35c10590880151e104eeb83acd84b364ef030',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.61:kotlin-stdlib-jdk8-1.2.61.jar:1fdeec7f74c2bae97a2205bb4aff0c6fe9d133bd619d069a0928156098d1b927',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.61:kotlin-stdlib-1.2.61.jar:62eaf9cc6e746cef4593abe7cdb4dd48694ef5f817c852e0d9fbbd11fcfc564e',
|
||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||
'org.junit.jupiter:junit-jupiter-api:5.2.0:junit-jupiter-api-5.2.0.jar:47f7d71b35dc331210b9ab219bbb00d54332981aa12eb5effe817de17e1ae7b3',
|
||||
|
||||
Reference in New Issue
Block a user