Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add update onboarding endpoint to GuildManager #687

Merged
merged 2 commits into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/nyxx.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export 'src/builders/guild/scheduled_event.dart' show ScheduledEventBuilder, Sch
export 'src/builders/guild/template.dart' show GuildTemplateBuilder, GuildTemplateUpdateBuilder;
export 'src/builders/guild/auto_moderation.dart'
show AutoModerationRuleBuilder, AutoModerationRuleUpdateBuilder, ActionMetadataBuilder, AutoModerationActionBuilder;
export 'src/builders/guild/onboarding.dart' show OnboardingPromptBuilder, OnboardingPromptOptionBuilder, OnboardingUpdateBuilder;
export 'src/builders/role.dart' show RoleBuilder, RoleUpdateBuilder;
export 'src/builders/voice.dart' show CurrentUserVoiceStateUpdateBuilder, VoiceStateUpdateBuilder, GatewayVoiceStateBuilder;
export 'src/builders/presence.dart' show PresenceBuilder, CurrentUserStatus, ActivityBuilder;
Expand Down Expand Up @@ -185,7 +186,7 @@ export 'src/models/guild/guild.dart'
UserGuild;
export 'src/models/guild/integration.dart' show PartialIntegration, Integration, IntegrationAccount, IntegrationApplication, IntegrationExpireBehavior;
export 'src/models/guild/member.dart' show Member, MemberFlags, PartialMember;
export 'src/models/guild/onboarding.dart' show Onboarding, OnboardingPrompt, OnboardingPromptOption, OnboardingPromptType;
export 'src/models/guild/onboarding.dart' show Onboarding, OnboardingPrompt, OnboardingPromptOption, OnboardingPromptType, OnboardingMode;
export 'src/models/guild/welcome_screen.dart' show WelcomeScreen, WelcomeScreenChannel;
export 'src/models/guild/scheduled_event.dart' show EntityMetadata, PartialScheduledEvent, ScheduledEvent, ScheduledEventUser, EventStatus, ScheduledEntityType;
export 'src/models/guild/audit_log.dart' show AuditLogChange, AuditLogEntry, AuditLogEntryInfo, PartialAuditLogEntry, AuditLogEvent;
Expand Down
95 changes: 95 additions & 0 deletions lib/src/builders/guild/onboarding.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:nyxx/src/builders/builder.dart';
import 'package:nyxx/src/models/emoji.dart';
import 'package:nyxx/src/models/guild/onboarding.dart';
import 'package:nyxx/src/models/snowflake.dart';

class OnboardingUpdateBuilder extends UpdateBuilder<Onboarding> {
List<OnboardingPromptBuilder> prompts;

List<Snowflake> defaultChannelIds;

bool isEnabled;

OnboardingMode mode;

OnboardingUpdateBuilder({
required this.prompts,
required this.defaultChannelIds,
required this.isEnabled,
required this.mode,
});

@override
Map<String, Object?> build() => {
'prompts': prompts.map((prompt) => prompt.build()).toList(),
'default_channel_ids': defaultChannelIds.map((channelId) => channelId.toString()).toList(),
'enabled': isEnabled,
'mode': mode.value,
};
}

class OnboardingPromptBuilder extends CreateBuilder<OnboardingPrompt> {
OnboardingPromptType type;

List<OnboardingPromptOptionBuilder> options;

String title;

bool isSingleSelect;

bool isRequired;

bool isInOnboarding;

OnboardingPromptBuilder({
required this.type,
required this.options,
required this.title,
required this.isSingleSelect,
required this.isRequired,
required this.isInOnboarding,
});

@override
Map<String, Object?> build() => {
'type': type.value,
'options': options.map((option) => option.build()).toList(),
'title': title,
'single_select': isSingleSelect,
'required': isRequired,
'in_onboarding': isInOnboarding,
};
}

class OnboardingPromptOptionBuilder extends CreateBuilder<OnboardingPromptOption> {
List<Snowflake> channelIds;

List<Snowflake> roleIds;

Emoji? emoji;

String title;

String? description;

OnboardingPromptOptionBuilder({
required this.channelIds,
required this.roleIds,
this.emoji,
required this.title,
this.description,
});

@override
Map<String, Object?> build() => {
'channel_ids': channelIds.map((id) => id.toString()).toList(),
'role_ids': roleIds.map((id) => id.toString()).toList(),
if (emoji case final emoji?) 'emoji_name': emoji.name,
if (emoji case GuildEmoji emoji) ...{
'emoji_id': emoji.id,
'emoji_animated': emoji.isAnimated,
},
'title': title,
'description': description,
};
}
13 changes: 13 additions & 0 deletions lib/src/http/managers/guild_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:typed_data';
import 'package:nyxx/src/builders/channel/channel_position.dart';
import 'package:nyxx/src/builders/channel/guild_channel.dart';
import 'package:nyxx/src/builders/guild/guild.dart';
import 'package:nyxx/src/builders/guild/onboarding.dart';
import 'package:nyxx/src/builders/guild/template.dart';
import 'package:nyxx/src/builders/guild/welcome_screen.dart';
import 'package:nyxx/src/builders/guild/widget.dart';
Expand Down Expand Up @@ -256,6 +257,7 @@ class GuildManager extends Manager<Guild> {
prompts: parseMany(raw['prompts'] as List, (Map<String, Object?> raw) => parseOnboardingPrompt(raw, guildId: guildId)),
defaultChannelIds: parseMany(raw['default_channel_ids'] as List, Snowflake.parse),
isEnabled: raw['enabled'] as bool,
mode: OnboardingMode(raw['mode'] as int),
);
}

Expand Down Expand Up @@ -694,6 +696,17 @@ class GuildManager extends Manager<Guild> {
return parseOnboarding(response.jsonBody as Map<String, Object?>);
}

/// Update a guild's onboarding.
Future<Onboarding> updateOnboarding(Snowflake id, OnboardingUpdateBuilder builder, {String? auditLogReason}) async {
final route = HttpRoute()
..guilds(id: id.toString())
..onboarding();
final request = BasicRequest(route, method: 'PUT', body: jsonEncode(builder.build()), auditLogReason: auditLogReason);

final response = await client.httpHandler.executeSafe(request);
return parseOnboarding(response.jsonBody as Map<String, Object?>);
}

/// Update the current user's voice state in a guild.
Future<void> updateCurrentUserVoiceState(Snowflake id, CurrentUserVoiceStateUpdateBuilder builder) async {
final route = HttpRoute()
Expand Down
5 changes: 5 additions & 0 deletions lib/src/models/guild/guild.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:typed_data';

import 'package:nyxx/src/builders/channel/channel_position.dart';
import 'package:nyxx/src/builders/channel/guild_channel.dart';
import 'package:nyxx/src/builders/guild/onboarding.dart';
import 'package:nyxx/src/builders/guild/template.dart';
import 'package:nyxx/src/builders/guild/welcome_screen.dart';
import 'package:nyxx/src/builders/guild/widget.dart';
Expand Down Expand Up @@ -168,6 +169,10 @@ class PartialGuild extends WritableSnowflakeEntity<Guild> {
/// Fetch the onboarding information for this guild.
Future<Onboarding> fetchOnboarding() => manager.fetchOnboarding(id);

/// Update this guild's onboarding.
Future<Onboarding> updateOnboarding(OnboardingUpdateBuilder builder, {String? auditLogReason}) =>
manager.updateOnboarding(id, builder, auditLogReason: auditLogReason);

/// Update the current user's voice state in this guild.
Future<void> updateCurrentUserVoiceState(CurrentUserVoiceStateUpdateBuilder builder) => manager.updateCurrentUserVoiceState(id, builder);

Expand Down
23 changes: 23 additions & 0 deletions lib/src/models/guild/onboarding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class Onboarding with ToStringHelper {
/// Whether onboarding is enabled for this guild.
final bool isEnabled;

/// The current onboarding mode.
final OnboardingMode mode;

/// {@macro onboarding}
/// @nodoc
Onboarding({
Expand All @@ -33,6 +36,7 @@ class Onboarding with ToStringHelper {
required this.prompts,
required this.defaultChannelIds,
required this.isEnabled,
required this.mode,
});

/// The guild this onboarding is for.
Expand Down Expand Up @@ -111,6 +115,9 @@ class OnboardingPromptOption with ToStringHelper {
final List<Snowflake> roleIds;

/// The emoji associated with this onboarding prompt.
// The `emoji_id`, `emoji_name`, and `emoji_animated` fields never seem to be
// included in this structure when it is returned from the API. Since the
// `emoji` object contains this information anyway, we don't include them.
final Emoji? emoji;

/// The title of this option.
Expand All @@ -134,3 +141,19 @@ class OnboardingPromptOption with ToStringHelper {
/// The channels the user is granted access to.
List<PartialChannel> get channels => channelIds.map((e) => manager.client.channels[e]).toList();
}

/// The mode under which onboarding constraints operate when creating an
/// [Onboarding].
///
/// These constraints are that there must be at least 7 Default Channels and
/// at least 5 of them must allow sending messages to the @everyone role.
final class OnboardingMode extends EnumLike<int, OnboardingMode> {
/// Only default channels count towards the constraints.
static const defaultMode = OnboardingMode(0);

/// Both default channels and questions count towards the constraints,
static const advanced = OnboardingMode(1);

/// @nodoc
const OnboardingMode(super.value);
}
21 changes: 20 additions & 1 deletion test/unit/http/managers/guild_manager_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,10 @@ final sampleOnboarding = {
"998678683592171602",
"998678699715067986"
],
"enabled": true
"enabled": true,

// The docs say these fields are present, but they aren't in the sample onboarding Discord provides
"mode": 0,
};

void checkOnboarding(Onboarding onboarding) {
Expand Down Expand Up @@ -730,6 +733,22 @@ void main() {
execute: (manager) => manager.fetchOnboarding(Snowflake.zero),
check: checkOnboarding,
),
EndpointTest<GuildManager, Onboarding, Map<String, Object?>>(
name: 'updateOnboarding',
source: sampleOnboarding,
urlMatcher: '/guilds/0/onboarding',
method: 'PUT',
execute: (manager) => manager.updateOnboarding(
Snowflake.zero,
OnboardingUpdateBuilder(
prompts: [],
defaultChannelIds: [],
isEnabled: true,
mode: OnboardingMode.defaultMode,
),
),
check: checkOnboarding,
),
EndpointTest<GuildManager, void, void>(
name: 'updateCurrentUserVoiceState',
method: 'PATCH',
Expand Down
Loading