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

Mod vcard graphql api #3639

Merged
merged 13 commits into from
May 18, 2022
1 change: 1 addition & 0 deletions big_tests/default.spec
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
{suites, "tests", graphql_roster_SUITE}.
{suites, "tests", graphql_session_SUITE}.
{suites, "tests", graphql_stanza_SUITE}.
{suites, "tests", graphql_vcard_SUITE}.
{suites, "tests", inbox_SUITE}.
{suites, "tests", inbox_extensions_SUITE}.
{suites, "tests", jingle_SUITE}.
Expand Down
1 change: 1 addition & 0 deletions big_tests/dynamic_domains.spec
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
{suites, "tests", graphql_roster_SUITE}.
{suites, "tests", graphql_session_SUITE}.
{suites, "tests", graphql_stanza_SUITE}.
{suites, "tests", graphql_vcard_SUITE}.

{suites, "tests", inbox_SUITE}.

Expand Down
457 changes: 457 additions & 0 deletions big_tests/tests/graphql_vcard_SUITE.erl

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion priv/graphql/schemas/admin/admin_schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ type AdminQuery{
"MUC Light room management"
muc_light: MUCLightAdminQuery
"Roster/Contacts management"
roster: RosterAdminQuery
roster: RosterAdminQuery
"Vcard management"
vcard: VcardAdminQuery
}

"""
Expand All @@ -45,4 +47,6 @@ type AdminMutation @protected{
muc_light: MUCLightAdminMutation
"Roster/Contacts management"
roster: RosterAdminMutation
"Vcard management"
vcard: VcardAdminMutation
}
15 changes: 15 additions & 0 deletions priv/graphql/schemas/admin/vcard.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Allow admin to set user's vcard
"""
type VcardAdminMutation @protected{
"Set a new vcard for a user"
setVcard(user: JID!, vcard: VcardInput!): Vcard
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved
}

"""
Allow admin to get user's vcard
"""
type VcardAdminQuery @protected{
"Get user's vcard"
getVcard(user: JID!): Vcard
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved
}
271 changes: 271 additions & 0 deletions priv/graphql/schemas/global/vcard.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
type Vcard{
"Formatted name from Vcard"
formattedName: String
"Person's name details"
nameComponents: NameComponents
"User's nickname"
nickname: [String]
"User's photo"
photo: [String]
"Birthday date"
birthday: [String]
address: [Address]
label: [Label]
telephone: [Telephone]
email: [Email]
jabberId: [String]
mailer: [String]
timeZone: [String]
"Geographical position"
geo: [GeographicalPosition]
title: [String]
role: [String]
logo: [String]
agent: [String]
Copy link
Contributor

Choose a reason for hiding this comment

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

So theoretically it is possible to have the full vCard in this field :O

<!ELEMENT AGENT (vCard | EXTVAL)>

"Organization"
org: [Organization]
categories: [Keyword]
note: [String]
"Identifier of product that generated the vCard property"
prodId: [String]
"Last revised property. The value must be an ISO 8601 formatted UTC date/time"
rev: [String]
"Sort string property"
sortString: [String]
"Formatted name pronunciation property"
sound: [String]
"Unique identifier property"
uid: [String]
"Directory URL property"
url: [String]
"Free-form descriptive text"
desc: [String]
"Privacy classification property"
class: [Privacy]
"Authentication credential or encryption key property"
key: [Key]
}

type Keyword{
keyword: [String]
}

type NameComponents{
family: String
givenName: String
middleName: String
prefix: String
suffix: String
}

type Address{
"Address tags"
tags: [AddressTags]
"Post office box"
pobox: String
"Extra address data"
extadd: String
street: String
locality: String
region: String
"Postal code"
pcode: String
country: String
}

type Label{
"Label tags"
tags: [AddressTags]
line: [String]
}

type Telephone{
"Telephone tags"
tags: [TelephoneTags]
number: String
}

type Email{
"Email tags"
tags: [EmailTags]
"Email address"
userId: String
}

type GeographicalPosition{
"Geographical latitude"
lat: String
"Geographical longtitude"
lon: String
}

type Organization{
"Organization name"
orgname: String
"Organization unit"
orgunit: [String]
}

type Privacy{
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved
tags: [PrivacyClassificationTags]
}

type Key{
credential: String
}

input VcardInput{
"Formatted name from Vcard"
formattedName: String!
"Person's name details"
nameComponents: NameComponentsInput!
"User's nickname"
nickname: [String]
"User's photo"
photo: [String!]
Copy link
Contributor

Choose a reason for hiding this comment

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

In vcard documentation this field can contain:

  • URL address to photo
  • the photo as a Base64 encoded binary value
<!ELEMENT PHOTO ((TYPE, BINVAL) | EXTVAL)>

Am I right that currently, we produce XML like:

<PHOTO>GIVEN_BINARY_VALUE</PHOTO>

when it should be:

<PHOTO><EXTVAL>GIVEN_BINARY_VAL</EXTVAL></PHOTO>

or

<PHOTO>
   <TYPE>image/jpeg</TYPE>
   <BINVAL>gjdsaoiweghagnasldgfa</BINVAL>
</PHOTO>

"Birthday date"
birthday: [String!]
address: [AddressInput!]
label: [LabelInput!]
telephone: [TelephoneInput!]
email: [EmailInput!]
jabberId: [String!]
mailer: [String!]
timeZone: [String!]
"Geographical position"
geo: [GeographicalPositionInput!]
title: [String!]
role: [String!]
logo: [String!]
Copy link
Contributor

@Premwoik Premwoik May 11, 2022

Choose a reason for hiding this comment

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

<!ELEMENT LOGO ((TYPE, BINVAL) | EXTVAL)>

Maybe it would be possible to do with union like this?

input Vcard{
  logo: [Image!]
  photo: [Image!]
}

union Image = ImageData | External

type ImageData{
   type: String!
   binValue: String!
}

type External{
   extValue: String!

agent: [String!]
"Organization"
org: [OrganizationInput!]
categories: [KeywordInput!]
note: [String!]
"Identifier of product that generated the vCard property"
prodId: [String!]
"Last revised property. The value must be an ISO 8601 formatted UTC date/time"
rev: [String!]
"Sort string property"
sortString: [String!]
"Formatted name pronunciation property"
sound: [String!]
Copy link
Contributor

Choose a reason for hiding this comment

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

<!ELEMENT SOUND (PHONETIC | BINVAL | EXTVAL)>

Same as for the photo field. I think we produce XML like:

<SOUND>quack quack</SOUND>

instead of

<SOUND><PHONETC>quack quack</PHONETIC></SOUND>

"Unique identifier property"
uid: [String!]
"Directory URL property"
url: [String!]
"Free-form descriptive text"
desc: [String!]
"Privacy classification property"
class: [PrivacyInput!]
"Authentication credential or encryption key property"
key: [KeyInput!]
}

input KeywordInput{
keyword: [String!]
}

input NameComponentsInput{
family: String
givenName: String
middleName: String
prefix: String
suffix: String
}

input AddressInput{
"Address tags"
tags: [AddressTags!]
"Post office box"
pobox: String
"Extra address data"
extadd: String
street: String
locality: String
region: String
"Postal code"
pcode: String
country: String
}

input LabelInput{
"Label tags"
tags: [AddressTags!]
line: [String!]!
}

input TelephoneInput{
"Telephone tags"
tags: [TelephoneTags!]
number: String!
}

input EmailInput{
"Email tags"
tags: [EmailTags!]
"Email address"
userId: String!
}

input GeographicalPositionInput{
"Geographical latitude"
lat: String!
"Geographical longtitude"
lon: String!
}

input OrganizationInput{
"Organization name"
orgname: String!
"Organization unit"
orgunit: [String!]
}

input PrivacyInput{
tags: [PrivacyClassificationTags!]
}

input KeyInput{
credential: String!
}

enum PrivacyClassificationTags{
PUBLIC
PRIVATE
CONFIDENTIAL
}

enum AddressTags{
Copy link
Contributor

Choose a reason for hiding this comment

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

NOTE:
In documentation is stated:

 (DOM | INTL)?,

Thus we cannot have these two tags together. I think it is a minor thing, but it's good to know that the user is allowed to add them together through our API.

Second thing is that GraphQL doesn't have the type for a unique list. So it is possible to put a list with a duplication even when vcard documentation requires only one.

HOME
WORK
POSTAL
PARCEL
DOM
PREF
INTL
}

enum TelephoneTags{
HOME
WORK
VOICE
FAX
PAGER
MSG
CELL
VIDEO
BBS
MODEM
ISDN
PCS
PREF
}

enum EmailTags{
HOME
WORK
INTERNET
PREF
X400
}
4 changes: 4 additions & 0 deletions priv/graphql/schemas/user/user_schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type UserQuery{
stanza: StanzaUserQuery
"Roster/Contacts management"
roster: RosterUserQuery
"Vcard management"
vcard: VcardUserQuery
}

"""
Expand All @@ -39,4 +41,6 @@ type UserMutation @protected{
stanza: StanzaUserMutation
"Roster/Contacts management"
roster: RosterUserMutation
"Vcard management"
vcard: VcardUserMutation
}
15 changes: 15 additions & 0 deletions priv/graphql/schemas/user/vcard.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Allow user to set own vcard
"""
type VcardUserMutation @protected{
"Set user's own vcard"
setVcard(vcard: VcardInput!): Vcard
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved
}

"""
Allow user to get user's vcard
"""
type VcardUserQuery @protected{
"Get user's vcard"
getVcard(user: JID): Vcard
}
4 changes: 3 additions & 1 deletion src/graphql/admin/mongoose_graphql_admin_mutation.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ execute(_Ctx, _Obj, <<"session">>, _Args) ->
execute(_Ctx, _Obj, <<"stanza">>, _Args) ->
{ok, stanza};
execute(_Ctx, _Obj, <<"roster">>, _Args) ->
{ok, roster}.
{ok, roster};
execute(_Ctx, _Obj, <<"vcard">>, _Args) ->
{ok, vcard}.
4 changes: 3 additions & 1 deletion src/graphql/admin/mongoose_graphql_admin_query.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ execute(_Ctx, _Obj, <<"stanza">>, _Args) ->
execute(_Ctx, _Obj, <<"roster">>, _Args) ->
{ok, roster};
execute(_Ctx, _Obj, <<"checkAuth">>, _Args) ->
{ok, admin}.
{ok, admin};
execute(_Ctx, _Obj, <<"vcard">>, _Args) ->
{ok, vcard}.
21 changes: 21 additions & 0 deletions src/graphql/admin/mongoose_graphql_vcard_admin_mutation.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-module(mongoose_graphql_vcard_admin_mutation).
-behaviour(mongoose_graphql).

-include("mod_vcard.hrl").

-export([execute/4]).

-import(mongoose_graphql_helper, [make_error/2, format_result/2, null_to_default/2]).
JanuszJakubiec marked this conversation as resolved.
Show resolved Hide resolved

-ignore_xref([execute/4]).

-include("../mongoose_graphql_types.hrl").
-include("mongoose.hrl").
-include("jlib.hrl").

execute(_Ctx, vcard, <<"setVcard">>, #{<<"user">> := CallerJID, <<"vcard">> := VcardInput}) ->
case mod_vcard_api:set_vcard(CallerJID, VcardInput) of
{ok, _} = Vcard -> Vcard;
{ErrorCode, ErrorMessage} ->
make_error({ErrorCode, ErrorMessage}, #{user => CallerJID})
end.
Loading