fix: prevent creation of course with invalid avatar url (#5364)

This commit is contained in:
ggurdin 2026-01-22 16:18:36 -05:00 committed by GitHub
parent a34103793f
commit f4311535b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 35 additions and 25 deletions

View file

@ -44,8 +44,9 @@ class ActivityPlanModel {
_roles = roles,
_imageURL = imageURL;
String? get imageURL =>
_imageURL != null ? "${Environment.cmsApi}$_imageURL" : null;
Uri? get imageURL => _imageURL != null
? Uri.tryParse("${Environment.cmsApi}$_imageURL")
: null;
Map<String, ActivityRole> get roles {
if (_roles != null) return _roles!;

View file

@ -204,8 +204,7 @@ class EditCourseController extends State<EditCourse> {
fit: BoxFit.cover,
)
: ImageByUrl(
imageUrl:
_room?.avatar?.toString(),
imageUrl: _room?.avatar,
width: 200.0,
borderRadius:
BorderRadius.circular(0.0),

View file

@ -11,7 +11,7 @@ import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
class ImageByUrl extends StatelessWidget {
final String? imageUrl;
final Uri? imageUrl;
final double width;
final BorderRadius borderRadius;
final Widget? replacement;
@ -41,19 +41,19 @@ class ImageByUrl extends StatelessWidget {
height: width,
child: ClipRRect(
borderRadius: borderRadius,
child: imageUrl!.startsWith("mxc")
child: imageUrl!.toString().startsWith("mxc")
? MxcImage(
uri: Uri.parse(imageUrl!),
uri: imageUrl,
width: width,
height: width,
cacheKey: imageUrl,
cacheKey: imageUrl.toString(),
fit: BoxFit.cover,
)
: CachedNetworkImage(
width: width,
height: width,
fit: BoxFit.cover,
imageUrl: imageUrl!,
imageUrl: imageUrl.toString(),
placeholder: (
context,
url,

View file

@ -57,7 +57,9 @@ class CourseChatsController extends State<CourseChats>
@override
void initState() {
loadHierarchy(reload: true);
loadHierarchy(reload: true).then(
(_) => _joinDefaultChats(),
);
// Listen for changes to the activeSpace's hierarchy,
// and reload the hierarchy when they come through
@ -212,7 +214,6 @@ class CourseChatsController extends State<CourseChats>
try {
await _loadHierarchy(activeSpace: room, reload: reload);
if (mounted) await _joinDefaultChats();
if (mounted) {
final futures = [
loadRoomSummaries(

View file

@ -1,4 +1,5 @@
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/spaces/space_constants.dart';
enum CourseDefaultChatsEnum {
@ -26,4 +27,11 @@ enum CourseDefaultChatsEnum {
CourseDefaultChatsEnum.introductions => l10n.introChatDesc,
CourseDefaultChatsEnum.announcements => l10n.announcementsChatDesc,
};
dynamic powerLevels(String userID) => switch (this) {
CourseDefaultChatsEnum.introductions =>
RoomDefaults.defaultPowerLevels(userID),
CourseDefaultChatsEnum.announcements =>
RoomDefaults.restrictedPowerLevels(userID),
};
}

View file

@ -109,7 +109,7 @@ class SelectedCourseController extends State<SelectedCourse>
},
),
],
avatarUrl: course.imageUrl,
avatarUrl: course.imageUrl.toString(),
spaceChild: 0,
)
.then((spaceId) => completer.complete(spaceId))

View file

@ -75,9 +75,8 @@ class SelectedCourseView extends StatelessWidget {
ClipPath(
clipper: MapClipper(),
child: ImageByUrl(
imageUrl: controller
.widget.roomChunk?.avatarUrl
?.toString() ??
imageUrl: controller.widget
.roomChunk?.avatarUrl ??
course.imageUrl,
width: 100.0,
borderRadius:

View file

@ -79,9 +79,9 @@ class CourseTopicModel {
return allLocationMedia;
}
String? get imageUrl => loadedLocationMediaIds.isEmpty
Uri? get imageUrl => loadedLocationMediaIds.isEmpty
? null
: "${Environment.cmsApi}${loadedLocationMediaIds.first}";
: Uri.tryParse("${Environment.cmsApi}${loadedLocationMediaIds.first}");
bool get activityListComplete =>
activityIds.length == loadedActivities.length;

View file

@ -127,9 +127,11 @@ class CoursePlanModel {
uuids: mediaIds,
),
);
String? get imageUrl => loadedMediaUrls.mediaUrls.isEmpty
Uri? get imageUrl => loadedMediaUrls.mediaUrls.isEmpty
? loadedTopics.values
.lastWhereOrNull((topic) => topic.imageUrl != null)
?.imageUrl
: "${Environment.cmsApi}${loadedMediaUrls.mediaUrls.first.url}";
: Uri.tryParse(
"${Environment.cmsApi}${loadedMediaUrls.mediaUrls.first.url}",
);
}

View file

@ -193,13 +193,14 @@ extension CoursePlanRoomExtension on Room {
preset: CreateRoomPreset.publicChat,
visibility: Visibility.private,
name: name,
roomAliasName: "${type.alias}_${id.localpart}",
roomAliasName:
"${type.alias}_${id.localpart}_${DateTime.now().millisecondsSinceEpoch}",
initialState: [
StateEvent(
type: EventTypes.RoomAvatar,
content: {'url': uploadURL},
),
RoomDefaults.defaultPowerLevels(client.userID!),
type.powerLevels(client.userID!),
await client.pangeaJoinRules(
'knock_restricted',
allow: [

View file

@ -274,8 +274,7 @@ class PublicCoursesPageState extends State<PublicCoursesPage> {
spacing: 8.0,
children: [
ImageByUrl(
imageUrl:
roomChunk.avatarUrl?.toString(),
imageUrl: roomChunk.avatarUrl,
width: 58.0,
borderRadius:
BorderRadius.circular(10.0),

View file

@ -108,7 +108,7 @@ class Avatar extends StatelessWidget {
// #Pangea
: !(mxContent.toString().startsWith('mxc://'))
? ImageByUrl(
imageUrl: mxContent.toString(),
imageUrl: mxContent,
width: size,
replacement: Center(
child: Icon(

View file

@ -6,7 +6,7 @@ description: Learn a language while texting your friends.
# Pangea#
publish_to: none
# On version bump also increase the build number for F-Droid
version: 4.1.16+2
version: 4.1.16+3
environment:
sdk: ">=3.0.0 <4.0.0"