Skip to content
Open
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
25 changes: 25 additions & 0 deletions Quotient/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1972,3 +1972,28 @@ bool Connection::allSessionsSelfVerified(const QString& userId) const
database()->execute(query);
return !query.next();
}

bool Connection::canChangeProfileFields() const
{
return !d->capabilities.profileFields || d->capabilities.profileFields->enabled;
}

bool Connection::profileFieldAllowed(const QString& key) const
{
// If the capability is missing, assume we are allowed to edit any profile field
if (!d->capabilities.profileFields) {
return true;
}

// If it's explicitly in the allow list
if (d->capabilities.profileFields->allowed.contains(key)) {
return true;
}

// As long as it's not explicitly disallowed
if (d->capabilities.profileFields->disallowed.contains(key)) {
return false;
}

return true;
Comment on lines +1983 to +1998
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If the capability is missing, assume we are allowed to edit any profile field
if (!d->capabilities.profileFields) {
return true;
}
// If it's explicitly in the allow list
if (d->capabilities.profileFields->allowed.contains(key)) {
return true;
}
// As long as it's not explicitly disallowed
if (d->capabilities.profileFields->disallowed.contains(key)) {
return false;
}
return true;
// If the capability is missing, assume we are allowed to edit any profile field; otherwise,
// it should either be explicitly allowed or NOT explicitly disallowed
return (!d->capabilities.profileFields || d->capabilities.profileFields->allowed.contains(key))
&& !d->capabilities.profileFields->disallowed.contains(key));

}
7 changes: 7 additions & 0 deletions Quotient/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class QUOTIENT_API Connection : public QObject {
Q_PROPERTY(bool encryptionEnabled READ encryptionEnabled WRITE enableEncryption NOTIFY encryptionChanged)
Q_PROPERTY(bool directChatEncryptionEnabled READ directChatEncryptionEnabled WRITE enableDirectChatEncryption NOTIFY directChatsEncryptionChanged)
Q_PROPERTY(QStringList accountDataEventTypes READ accountDataEventTypes NOTIFY accountDataChanged)
Q_PROPERTY(bool canChangeProfileFields READ canChangeProfileFields NOTIFY capabilitiesLoaded)

public:
using UsersToDevicesToContent = QHash<QString, QHash<QString, QJsonObject>>;
Expand Down Expand Up @@ -449,6 +450,12 @@ class QUOTIENT_API Connection : public QObject {
//! \sa loadingCapabilities
bool canChangePassword() const;

//! Indicate if the server allows the user to change their profile fields.
bool canChangeProfileFields() const;

//! Indicate if the server allows this specific profile field.
Q_INVOKABLE bool profileFieldAllowed(const QString& key) const;

//! \brief Check whether encryption is enabled on this connection
//! \sa enableEncryption
bool encryptionEnabled() const;
Expand Down
27 changes: 27 additions & 0 deletions Quotient/csapi/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ class QUOTIENT_API GetCapabilitiesJob : public BaseJob {
QHash<QString, QString> available;
};

//! The profile fields the server supports and if they can be edited.
struct QUOTIENT_API ProfileFieldsCapability {
//! If the user is allowed to change their own profile fields.
bool enabled;

//! A list of allowed profile field keys.
QList<QString> allowed;

//! A list of disallowed profile field keys.
QList<QString> disallowed;
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The contents of csapi/ are generated from API definitions (see CODE_GENERATION.md) - I understand it makes the whole process a bit more tedious but I'd rather wait for matrix-org/matrix-spec#2071 to get merged and then we're going to get those definitions "for free", just by virtue of rebasing the main branch in https://github.com/quotient-im/matrix-spec

//! The custom capabilities the server supports, using the
//! Java package naming convention.
struct QUOTIENT_API Capabilities {
Expand All @@ -62,6 +74,10 @@ class QUOTIENT_API GetCapabilitiesJob : public BaseJob {
//! account.
std::optional<BooleanCapability> getLoginToken{};

//! Capability to indicate if the user can edit profile fields and which ones they can
//! change.
std::optional<ProfileFieldsCapability> profileFields{};

//! Application-dependent keys using the
//! [Common Namespaced Identifier
//! Grammar](/appendices/#common-namespaced-identifier-grammar).
Expand Down Expand Up @@ -96,6 +112,16 @@ struct QUOTIENT_API JsonObjectConverter<GetCapabilitiesJob::RoomVersionsCapabili
}
};

template <>
struct QUOTIENT_API JsonObjectConverter<GetCapabilitiesJob::ProfileFieldsCapability> {
static void fillFrom(const QJsonObject& jo, GetCapabilitiesJob::ProfileFieldsCapability& result)
{
fillFromJson(jo.value("enabled"_L1), result.enabled);
fillFromJson(jo.value("allowed"_L1), result.allowed);
fillFromJson(jo.value("disallowed"_L1), result.disallowed);
}
};

template <>
struct QUOTIENT_API JsonObjectConverter<GetCapabilitiesJob::Capabilities> {
static void fillFrom(QJsonObject jo, GetCapabilitiesJob::Capabilities& result)
Expand All @@ -106,6 +132,7 @@ struct QUOTIENT_API JsonObjectConverter<GetCapabilitiesJob::Capabilities> {
fillFromJson(jo.take("m.set_avatar_url"_L1), result.setAvatarUrl);
fillFromJson(jo.take("m.3pid_changes"_L1), result.thirdPartyIdChanges);
fillFromJson(jo.take("m.get_login_token"_L1), result.getLoginToken);
fillFromJson(jo.take("uk.tcpip.msc4133.profile_fields"_L1), result.profileFields);
fromJson(jo, result.additionalProperties);
}
};
Expand Down
16 changes: 16 additions & 0 deletions Quotient/csapi/profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,19 @@ GetUserProfileJob::GetUserProfileJob(const QString& userId)
: BaseJob(HttpVerb::Get, u"GetUserProfileJob"_s,
makePath("/_matrix/client/v3", "/profile/", userId))
{}

GetProfileFieldJob::GetProfileFieldJob(const QString& userId, const QString& key)
: BaseJob(HttpVerb::Get, u"GetProfileFieldJob"_s,
makePath("/_matrix/client/unstable/uk.tcpip.msc4133", "/profile/", userId, "/", key))
, m_key(key)
{}

SetProfileFieldJob::SetProfileFieldJob(const QString& userId, const QString& key,
const QString& value)
: BaseJob(HttpVerb::Put, u"SetProfileFieldJob"_s,
makePath("/_matrix/client/unstable/uk.tcpip.msc4133", "/profile/", userId, "/", key))
{
QJsonObject _dataJson;
addParam(_dataJson, key, value);
setRequestData({ _dataJson });
}
36 changes: 36 additions & 0 deletions Quotient/csapi/profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,42 @@ class QUOTIENT_API GetAvatarUrlJob : public BaseJob {

inline auto collectResponse(const GetAvatarUrlJob* job) { return job->avatarUrl(); }

//! \brief Get a user's profile field.
//!
//! Get one of the user's profile fields. This API may be used to fetch the user's
//! own profile field or to query the profile field of other users; either locally or
//! on remote homeservers.
class QUOTIENT_API GetProfileFieldJob : public BaseJob {
public:
//! \param userId
//! The user whose profile field to query.
//! \param key
//! The key of the profile field.
explicit GetProfileFieldJob(const QString& userId, const QString& key);

// Result properties

//! The value of the profile field.
QString value() const { return loadFromJson<QString>(m_key); }

private:
QString m_key;
};

//! \brief Sets a user's profile field.
//!
//! Set one of the user's own profile fields. This may fail depending on if the server allows the
//! user to change their own profile field, or if the field isn't allowed.
class QUOTIENT_API SetProfileFieldJob : public BaseJob {
public:
//! \param userId
//! The user whose avatar URL to set.
//!
//! \param avatarUrl
//! The new avatar URL for this user.
explicit SetProfileFieldJob(const QString& userId, const QString& key, const QString& value);
};

//! \brief Get this user's profile information.
//!
//! Get the combined profile information for this user. This API may be used
Expand Down
Loading