Skip to content

Commit

Permalink
Fix #1155 and support missing Scheduled event features
Browse files Browse the repository at this point in the history
Add missing name, description, imageUrl in ScheduledEvent

Add image parameter to create and modify spec

Add status parameter to modify spec

Update our example code
  • Loading branch information
quanticc committed Jun 19, 2023
1 parent b8b955f commit fa81c5b
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 35 deletions.
67 changes: 51 additions & 16 deletions core/src/main/java/discord4j/core/object/entity/ScheduledEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
import discord4j.core.object.entity.channel.GuildChannel;
import discord4j.core.spec.ScheduledEventEditMono;
import discord4j.core.spec.ScheduledEventEditSpec;
import discord4j.core.util.ImageUtil;
import discord4j.discordjson.json.GuildScheduledEventData;
import discord4j.discordjson.possible.Possible;
import discord4j.rest.util.Image;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;
Expand All @@ -42,6 +45,8 @@
*/
public class ScheduledEvent implements Entity {

private static final String EVENT_COVER_IMAGE_PATH = "guild-events/%s/%s";

/**
* The gateway associated to this object
*/
Expand All @@ -56,7 +61,7 @@ public class ScheduledEvent implements Entity {
* Constructs a {@code ScheduledEvent} with an associated {@link GatewayDiscordClient} and Discord data.
*
* @param gateway The {@link GatewayDiscordClient} associated to this object, must be non-null.
* @param data The raw data as represented by Discord, must be non-null.
* @param data The raw data as represented by Discord, must be non-null.
*/
public ScheduledEvent(final GatewayDiscordClient gateway, final GuildScheduledEventData data) {
this.gateway = Objects.requireNonNull(gateway);
Expand Down Expand Up @@ -97,7 +102,7 @@ public Snowflake getGuildId() {
* @return The ID of the creator of the event.
*/
public Optional<Snowflake> getCreatorId() {
return data.creatorId().map(Snowflake::of);
return Possible.flatOpt(data.creatorId()).map(Snowflake::of);
}

/**
Expand Down Expand Up @@ -131,8 +136,26 @@ public Optional<Snowflake> getChannelId() {
*/
public Mono<GuildChannel> getChannel() {
return Mono.justOrEmpty(getChannelId())
.flatMap(gateway::getChannelById)
.ofType(GuildChannel.class);
.flatMap(gateway::getChannelById)
.ofType(GuildChannel.class);
}

/**
* Return the name of this scheduled event.
*
* @return the scheduled event name
*/
public String getName() {
return data.name();
}

/**
* Return the description of this scheduled event.
*
* @return the scheduled event description, if present
*/
public Optional<String> getDescription() {
return Possible.flatOpt(data.description());
}

/**
Expand Down Expand Up @@ -173,6 +196,17 @@ public Status getStatus() {
return Status.of(data.status());
}

/**
* Returns the cover image URL of this scheduled event, if present.
*
* @param format the format for the URL
* @return the cover image URL, if present.
*/
public Optional<String> getImageUrl(Image.Format format) {
return Possible.flatOpt(data.image())
.map(hash -> ImageUtil.getUrl(String.format(EVENT_COVER_IMAGE_PATH, getId().asString(), hash), format));
}

/**
* Gets the entity type of the event.
*
Expand Down Expand Up @@ -236,36 +270,37 @@ public Flux<ScheduledEventUser> getSubscribedUsers(boolean withMemberData) {
Map<String, Object> queryParams = new HashMap<>();
queryParams.put("with_member", withMemberData);

return gateway.getRestClient().getGuildService().getScheduledEventUsers(getGuildId().asLong(), getId().asLong(), queryParams)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
return gateway.getRestClient().getGuildService().getScheduledEventUsers(getGuildId().asLong(),
getId().asLong(), queryParams)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
}

/**
* Requests to retrieve the users subscribed to this event <li>before</li> the given user ID.
*
* @param userId the ID of the <li>newest</li> user to retrieve
* @param userId the ID of the <li>newest</li> user to retrieve
* @param withMemberData requests to return member data along with user data
* @return A {@link Flux} that continually emits <i>all</i> {@link ScheduledEventUser users} <i>after</i>
* the specified ID. If an error is received, it is emitted through the {@code Flux}.
*/
public Flux<ScheduledEventUser> getSubscribedUsersBefore(Snowflake userId, boolean withMemberData) {
return gateway.getRestClient().getScheduledEventById(getGuildId(), getId())
.getSubscribedUsersBefore(userId, withMemberData)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
.getSubscribedUsersBefore(userId, withMemberData)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
}

/**
* Requests to retrieve the users subscribed to this event <li>after</li> the given user ID.
*
* @param userId the ID of the <li>oldest</li> user to retrieve
* @param userId the ID of the <li>oldest</li> user to retrieve
* @param withMemberData requests to return member data along with user data
* @return A {@link Flux} that continually emits <i>all</i> {@link ScheduledEventUser users} <i>after</i>
* the specified ID. If an error is received, it is emitted through the {@code Flux}.
*/
public Flux<ScheduledEventUser> getSubscribedUsersAfter(Snowflake userId, boolean withMemberData) {
return gateway.getRestClient().getScheduledEventById(getGuildId(), getId())
.getSubscribedUsersAfter(userId, withMemberData)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
.getSubscribedUsersAfter(userId, withMemberData)
.map(data -> new ScheduledEventUser(gateway, data, getGuildId()));
}

/**
Expand All @@ -288,7 +323,7 @@ public ScheduledEventEditMono edit() {
public Mono<ScheduledEvent> edit(ScheduledEventEditSpec spec) {
Objects.requireNonNull(spec);
return Mono.defer(() -> gateway.getRestClient().getScheduledEventById(getGuildId(), getId()).edit(spec.asRequest(), spec.reason())
.map(data -> new ScheduledEvent(gateway, data)));
.map(data -> new ScheduledEvent(gateway, data)));
}

/**
Expand All @@ -297,9 +332,9 @@ public Mono<ScheduledEvent> edit(ScheduledEventEditSpec spec) {
* @param reason the reason explaining why this event is being deleted
* @return A {@link Mono} which completes when the event is deleted.
*/
public Mono<Void> delete(@Nullable String reason) {
return gateway.getRestClient().getScheduledEventById(getGuildId(), getId())
.delete(reason);
public Mono<Void> delete(@Nullable String reason) {
return gateway.getRestClient().getScheduledEventById(getGuildId(), getId())
.delete(reason);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import discord4j.discordjson.Id;
import discord4j.discordjson.json.GuildScheduledEventCreateRequest;
import discord4j.discordjson.possible.Possible;
import discord4j.rest.util.Image;
import org.immutables.value.Value;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -34,7 +35,7 @@ public interface ScheduledEventCreateSpecGenerator extends AuditSpec<GuildSchedu

ScheduledEvent.EntityType entityType();

//TODO Add image support
Possible<Image> image();

@Override
default GuildScheduledEventCreateRequest asRequest() {
Expand All @@ -47,6 +48,7 @@ default GuildScheduledEventCreateRequest asRequest() {
.scheduledEndTime(scheduledEndTime())
.description(description())
.entityType(entityType().getValue())
.image(mapPossible(image(), Image::getDataUri))
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import discord4j.discordjson.Id;
import discord4j.discordjson.json.GuildScheduledEventModifyRequest;
import discord4j.discordjson.possible.Possible;
import discord4j.rest.util.Image;
import org.immutables.value.Value;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -34,20 +35,24 @@ public interface ScheduledEventEditSpecGenerator extends AuditSpec<GuildSchedule

Possible<ScheduledEvent.EntityType> entityType();

//TODO Add image support
Possible<ScheduledEvent.Status> status();

Possible<Image> image();

@Override
default GuildScheduledEventModifyRequest asRequest() {
return GuildScheduledEventModifyRequest.builder()
.channelId(mapPossible(channelId(), optional -> optional.map(snowflake -> Id.of(snowflake.asLong()))))
.entityMetadata(mapPossible(entityMetadata(), ScheduledEventEntityMetadataSpecGenerator::asRequest))
.name(name())
.privacyLevel(mapPossible(privacyLevel(), ScheduledEvent.PrivacyLevel::getValue))
.scheduledStartTime(scheduledStartTime())
.scheduledEndTime(scheduledEndTime())
.description(description())
.entityType(mapPossible(entityType(), ScheduledEvent.EntityType::getValue))
.build();
.channelId(mapPossible(channelId(), optional -> optional.map(snowflake -> Id.of(snowflake.asLong()))))
.entityMetadata(mapPossible(entityMetadata(), ScheduledEventEntityMetadataSpecGenerator::asRequest))
.name(name())
.privacyLevel(mapPossible(privacyLevel(), ScheduledEvent.PrivacyLevel::getValue))
.scheduledStartTime(scheduledStartTime())
.scheduledEndTime(scheduledEndTime())
.description(description())
.entityType(mapPossible(entityType(), ScheduledEvent.EntityType::getValue))
.status(mapPossible(status(), ScheduledEvent.Status::getValue))
.image(mapPossible(image(), Image::getDataUri))
.build();
}
}

Expand Down
19 changes: 12 additions & 7 deletions core/src/test/java/discord4j/core/ExampleGuildScheduledEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import discord4j.core.event.domain.lifecycle.ReadyEvent;
import discord4j.core.object.entity.ScheduledEvent;
import discord4j.core.spec.ScheduledEventCreateSpec;
import discord4j.core.spec.ScheduledEventEditSpec;
import discord4j.core.spec.ScheduledEventEntityMetadataSpec;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -34,29 +35,33 @@ public static void main(String[] args) {
DiscordClient.create(token)
.withGateway(client -> {



// Logic to create a scheduled event on ready event
Publisher<?> createOnReady = client.on(ReadyEvent.class)
// Fetch the given guild
.flatMap(ignored -> client.getGuildById(Snowflake.of(guildId)))
// Create the event
.flatMap(guild -> guild.createScheduledEvent(ScheduledEventCreateSpec.builder()
.name(EVENT_NAME)
.description(EVENT_DESCRIPTION)
.privacyLevel(ScheduledEvent.PrivacyLevel.GUILD_ONLY)
.entityType(ScheduledEvent.EntityType.EXTERNAL)
.entityMetadata(ScheduledEventEntityMetadataSpec.builder()
.location(EVENT_LOCATION)
.build())
.scheduledStartTime(Instant.now().plusSeconds(3600)) // Start in one hour
.scheduledEndTime(Instant.now().plusSeconds(7200)) // End in two hours (required
// for external events)
.scheduledEndTime(Instant.now().plusSeconds(7200)) // End in two hours (required for external events)
.build()
))
// Update the event
.flatMap(event -> event.edit().withName("Edited " + EVENT_NAME))
// Advertise our event
.doOnNext(event -> System.out.format("The created event ID is %d\n",
event.getId().asLong()))
.doOnNext(event -> System.out.format("The created event ID is %d\n", event.getId().asLong()))
// Wait 10 seconds, then update the event
.delayElements(Duration.ofSeconds(10))
.flatMap(event -> event.edit(ScheduledEventEditSpec.builder()
.name("Edited " + EVENT_NAME)
.description(EVENT_DESCRIPTION)
.status(ScheduledEvent.Status.ACTIVE)
.build()))
// Wait a minute before deleting it
.delayElements(Duration.ofMinutes(1))
// Delete it
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
org.gradle.caching=true
systemProp.org.gradle.internal.publish.checksums.insecure=true
version=3.2.6-SNAPSHOT
discordJsonVersion=1.6.17
discordJsonVersion=1.6.18-SNAPSHOT
storesVersion=3.2.2

0 comments on commit fa81c5b

Please sign in to comment.