1: -module(graphql_vcard_SUITE).
    2: 
    3: -compile([export_all, nowarn_export_all]).
    4: 
    5: -import(distributed_helper, [require_rpc_nodes/1]).
    6: -import(graphql_helper, [execute_user/3, execute_auth/2, user_to_bin/1]).
    7: 
    8: -include_lib("common_test/include/ct.hrl").
    9: -include_lib("eunit/include/eunit.hrl").
   10: -include_lib("exml/include/exml.hrl").
   11: -include_lib("escalus/include/escalus.hrl").
   12: -include_lib("../../include/mod_roster.hrl").
   13: 
   14: suite() ->
   15:     require_rpc_nodes([mim]) ++ escalus:suite().
   16: 
   17: all() ->
   18:     [{group, user_vcard}, {group, admin_vcard}].
   19: 
   20: groups() ->
   21:     [{user_vcard, [], user_vcard_handler()},
   22:      {admin_vcard, [], admin_vcard_handler()}].
   23: 
   24: user_vcard_handler() ->
   25:     [user_set_vcard,
   26:      user_get_their_vcard,
   27:      user_get_their_vcard_no_vcard,
   28:      user_get_others_vcard,
   29:      user_get_others_vcard_no_user,
   30:      user_get_others_vcard_no_vcard].
   31: 
   32: admin_vcard_handler() ->
   33:     [admin_set_vcard,
   34:      admin_set_vcard_incomplete_fields,
   35:      admin_set_vcard_no_user,
   36:      admin_get_vcard,
   37:      admin_get_vcard_no_vcard,
   38:      admin_get_vcard_no_user].
   39: 
   40: init_per_suite(Config) ->
   41:     case vcard_helper:is_vcard_ldap() of
   42:         true ->
   43:             {skip, ldap_vcard_is_not_supported};
   44:         _ ->
   45:             Config2 = escalus:init_per_suite(Config),
   46:             dynamic_modules:save_modules(domain_helper:host_type(), Config2)
   47:     end.
   48: 
   49: end_per_suite(Config) ->
   50:     dynamic_modules:restore_modules(Config),
   51:     escalus:end_per_suite(Config).
   52: 
   53: init_per_group(admin_vcard, Config) ->
   54:     graphql_helper:init_admin_handler(Config);
   55: init_per_group(user_vcard, Config) ->
   56:     [{schema_endpoint, user} | Config].
   57: 
   58: end_per_group(admin_vcard, _Config) ->
   59:     escalus_fresh:clean();
   60: end_per_group(user_vcard, _Config) ->
   61:     escalus_fresh:clean().
   62: 
   63: init_per_testcase(CaseName, Config) ->
   64:     escalus:init_per_testcase(CaseName, Config).
   65: 
   66: end_per_testcase(CaseName, Config) ->
   67:     escalus:end_per_testcase(CaseName, Config).
   68: 
   69: % User test cases
   70: 
   71: user_set_vcard(Config) ->
   72:     escalus:fresh_story_with_config(Config, [{alice, 1}],
   73:                                     fun user_set_vcard/2).
   74: 
   75: user_set_vcard(Config, Alice) ->
   76:     Vcard = complete_vcard_input(),
   77:     BodySet = set_vcard_body_user(Vcard),
   78:     GraphQlRequestSet = execute_user(BodySet, Alice, Config),
   79:     ParsedResultSet = ok_result(<<"vcard">>, <<"setVcard">>, GraphQlRequestSet),
   80:     ?assertEqual(Vcard, ParsedResultSet),
   81:     QueryGet = user_get_full_vcard_as_result_query(),
   82:     BodyGet = #{query => QueryGet, operationName => <<"Q1">>, variables => #{}},
   83:     GraphQlRequestGet = execute_user(BodyGet, Alice, Config),
   84:     ParsedResultGet = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequestGet),
   85:     ?assertEqual(Vcard, ParsedResultGet).
   86: 
   87: user_get_their_vcard(Config) ->
   88:     escalus:fresh_story_with_config(Config, [{alice, 1}],
   89:                                     fun user_get_their_vcard/2).
   90: 
   91: user_get_their_vcard(Config, Alice) ->
   92:     Client1Fields = [{<<"FN">>, <<"TESTNAME">>}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL">>},
   93:     {<<"HOME">>, []}, {"WORK", []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>},
   94:     {<<"HOME">>, []}]}],
   95:     ExpectedResult = #{<<"formattedName">> => <<"TESTNAME">>,
   96:         <<"email">> => [#{<<"userId">> => <<"TESTEMAIL">>, <<"tags">> => [<<"HOME">>, <<"WORK">>]},
   97:                         #{<<"userId">> => <<"TESTEMAIL2">>, <<"tags">> => [<<"HOME">>]}]},
   98:     escalus_client:send_and_wait(Alice, escalus_stanza:vcard_update(Client1Fields)),
   99:     Body = #{query => user_get_query(), operationName => <<"Q1">>, variables => #{}},
  100:     GraphQlRequest = execute_user(Body, Alice, Config),
  101:     ParsedResult = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequest),
  102:     ?assertEqual(ExpectedResult, ParsedResult).
  103: 
  104: user_get_their_vcard_no_vcard(Config) ->
  105:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  106:                                     fun user_get_their_vcard_no_vcard/2).
  107: 
  108: user_get_their_vcard_no_vcard(Config, Alice) ->
  109:     Body = #{query => user_get_query(), operationName => <<"Q1">>, variables => #{}},
  110:     GraphQlRequest = execute_user(Body, Alice, Config),
  111:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  112:     ?assertEqual(<<"Vcard for user not found">>, ParsedResult).
  113: 
  114: user_get_others_vcard(Config) ->
  115:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  116:                                     fun user_get_others_vcard/3).
  117: 
  118: user_get_others_vcard(Config, Alice, Bob) ->
  119:     Client1Fields = [{<<"FN">>, <<"TESTNAME">>}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL">>},
  120:     {<<"HOME">>, []}, {"WORK", []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>},
  121:     {<<"HOME">>, []}]}],
  122:     ExpectedResult = #{<<"formattedName">> => <<"TESTNAME">>,
  123:         <<"email">> => [#{<<"userId">> => <<"TESTEMAIL">>, <<"tags">> => [<<"HOME">>, <<"WORK">>]},
  124:                         #{<<"userId">> => <<"TESTEMAIL2">>, <<"tags">> => [<<"HOME">>]}]},
  125:     escalus_client:send_and_wait(Bob, escalus_stanza:vcard_update([{<<"VERSION">>, <<"TESTVERSION">>} | Client1Fields])),
  126:     Body = #{query => user_get_query(), operationName => <<"Q1">>,
  127:              variables => #{user => user_to_bin(Bob)}},
  128:     GraphQlRequest = execute_user(Body, Alice, Config),
  129:     ParsedResult = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequest),
  130:     ?assertEqual(ExpectedResult, ParsedResult).
  131: 
  132: user_get_others_vcard_no_vcard(Config) ->
  133:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  134:                                     fun user_get_others_vcard_no_vcard/3).
  135: 
  136: user_get_others_vcard_no_vcard(Config, Alice, Bob) ->
  137:     Body = #{query => user_get_query(), operationName => <<"Q1">>,
  138:              variables => #{user => user_to_bin(Bob)}},
  139:     GraphQlRequest = execute_user(Body, Alice, Config),
  140:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  141:     ?assertEqual(<<"Vcard for user not found">>, ParsedResult).
  142: 
  143: user_get_others_vcard_no_user(Config) ->
  144:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  145:                                     fun user_get_others_vcard_no_user/2).
  146: 
  147: user_get_others_vcard_no_user(Config, Alice) ->
  148:     Body = #{query => user_get_query(), operationName => <<"Q1">>,
  149:              variables => #{user => <<"AAAAA">>}},
  150:     GraphQlRequest = execute_user(Body, Alice, Config),
  151:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  152:     ?assertEqual(<<"User does not exist">>, ParsedResult).
  153: 
  154: %% Admin test cases
  155: 
  156: admin_set_vcard(Config) ->
  157:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  158:                                     fun admin_set_vcard/3).
  159: 
  160: admin_set_vcard(Config, Alice, _Bob) ->
  161:     Vcard = complete_vcard_input(),
  162:     BodySet = set_vcard_body_admin(Vcard, user_to_bin(Alice)),
  163:     GraphQlRequestSet = execute_auth(BodySet, Config),
  164:     ParsedResultSet = ok_result(<<"vcard">>, <<"setVcard">>, GraphQlRequestSet),
  165:     ?assertEqual(Vcard, ParsedResultSet),
  166:     QueryGet = admin_get_full_vcard_as_result_query(),
  167:     VarsGet = #{user => user_to_bin(Alice)},
  168:     BodyGet = #{query => QueryGet, operationName => <<"Q1">>, variables => VarsGet},
  169:     GraphQlRequestGet = execute_auth(BodyGet, Config),
  170:     ParsedResultGet = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequestGet),
  171:     ?assertEqual(Vcard, ParsedResultGet).
  172: 
  173: admin_set_vcard_incomplete_fields(Config) ->
  174:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  175:                                     fun admin_set_vcard_incomplete_fields/3).
  176: 
  177: admin_set_vcard_incomplete_fields(Config, Alice, _Bob) ->
  178:     QuerySet = admin_get_full_vcard_as_result_mutation(),
  179:     VcardInput = address_vcard_input(),
  180:     [VcardAddress] = maps:get(<<"address">> ,VcardInput),
  181:     Vcard = [maps:put(<<"pcode">>, null, VcardAddress)],
  182:     VarsSet = #{user => user_to_bin(Alice), vcard => VcardInput},
  183:     BodySet = #{query => QuerySet, operationName => <<"M1">>, variables => VarsSet},
  184:     GraphQlRequestSet = execute_auth(BodySet, Config),
  185:     ParsedResultSet = ok_result(<<"vcard">>, <<"setVcard">>, GraphQlRequestSet),
  186:     ?assertEqual(Vcard, maps:get(<<"address">>, ParsedResultSet)),
  187:     QueryGet = admin_get_full_vcard_as_result_query(),
  188:     VarsGet = #{user => user_to_bin(Alice)},
  189:     BodyGet = #{query => QueryGet, operationName => <<"Q1">>, variables => VarsGet},
  190:     GraphQlRequestGet = execute_auth(BodyGet, Config),
  191:     ParsedResultGet = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequestGet),
  192:     ?assertEqual(Vcard, maps:get(<<"address">>, ParsedResultGet)).
  193: 
  194: admin_set_vcard_no_user(Config) ->
  195:     Query = admin_get_full_vcard_as_result_mutation(),
  196:     OpName = <<"M1">>,
  197:     Vcard = complete_vcard_input(),
  198:     Vars = #{user => <<"AAAAA">>, vcard => Vcard},
  199:     Body = #{query => Query, operationName => OpName, variables => Vars},
  200:     GraphQlRequest = execute_auth(Body, Config),
  201:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  202:     ?assertEqual(<<"User does not exist">>, ParsedResult).
  203: 
  204: admin_get_vcard(Config) ->
  205:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  206:                                     fun admin_get_vcard/3).
  207: 
  208: admin_get_vcard(Config, Alice, _Bob) ->
  209:     Client1Fields = [{<<"ADR">>, [{<<"POBOX">>, <<"TESTPobox">>}, {<<"EXTADD">>, <<"TESTExtadd">>},
  210:         {<<"STREET">>, <<"TESTStreet">>}, {<<"LOCALITY">>, <<"TESTLocality">>},
  211:         {<<"REGION">>, <<"TESTRegion">>}, {<<"PCODE">>, <<"TESTPCODE">>},
  212:         {<<"CTRY">>, <<"TESTCTRY">>}, {<<"HOME">>, []}, {<<"WORK">>, []}]}],
  213:     ExpectedResult = #{<<"address">> => [#{<<"pobox">> => <<"TESTPobox">>,
  214:         <<"extadd">> => <<"TESTExtadd">>, <<"street">> => <<"TESTStreet">>,
  215:         <<"locality">> => <<"TESTLocality">>, <<"region">> => <<"TESTRegion">>,
  216:         <<"pcode">> => <<"TESTPCODE">>, <<"country">> => <<"TESTCTRY">>,
  217:         <<"tags">> => [<<"HOME">>, <<"WORK">>]}]},
  218:     escalus_client:send_and_wait(Alice, escalus_stanza:vcard_update(Client1Fields)),
  219:     Vars = #{user => user_to_bin(Alice)},
  220:     Body = #{query => admin_get_address_query(), operationName => <<"Q1">>, variables => Vars},
  221:     GraphQlRequest = execute_auth(Body, Config),
  222:     ParsedResult = ok_result(<<"vcard">>, <<"getVcard">>, GraphQlRequest),
  223:     ?assertEqual(ExpectedResult, ParsedResult).
  224: 
  225: admin_get_vcard_no_vcard(Config) ->
  226:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  227:                                     fun admin_get_vcard_no_vcard/2).
  228: 
  229: admin_get_vcard_no_vcard(Config, Alice) ->
  230:     Query = admin_get_address_query(),
  231:     OpName = <<"Q1">>,
  232:     Vars = #{user => user_to_bin(Alice)},
  233:     Body = #{query => Query, operationName => OpName, variables => Vars},
  234:     GraphQlRequest = execute_auth(Body, Config),
  235:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  236:     ?assertEqual(<<"Vcard for user not found">>, ParsedResult).
  237: 
  238: admin_get_vcard_no_user(Config) ->
  239:     Query = admin_get_address_query(),
  240:     OpName = <<"Q1">>,
  241:     Vars = #{user => <<"AAAAA">>},
  242:     Body = #{query => Query, operationName => OpName, variables => Vars},
  243:     GraphQlRequest = execute_auth(Body, Config),
  244:     ParsedResult = error_result(<<"message">>, GraphQlRequest),
  245:     ?assertEqual(<<"User does not exist">>, ParsedResult).
  246: 
  247: %% Helpers
  248: 
  249: ok_result(What1, What2, {{<<"200">>, <<"OK">>}, #{<<"data">> := Data}}) ->
  250:     maps:get(What2, maps:get(What1, Data)).
  251: 
  252: error_result(What, {{<<"200">>, <<"OK">>}, #{<<"errors">> := [Data]}}) ->
  253:     maps:get(What, Data).
  254: 
  255: set_vcard_body_user(Body) ->
  256:     QuerySet = user_get_full_vcard_as_result_mutation(),
  257:     #{query => QuerySet, operationName => <<"M1">>, variables => #{vcard => Body}}.
  258: 
  259: set_vcard_body_admin(Body, User) ->
  260:     QuerySet = admin_get_full_vcard_as_result_mutation(),
  261:     #{query => QuerySet, operationName => <<"M1">>, variables => #{vcard => Body, user => User}}.
  262: 
  263: address_vcard_input() ->
  264:    #{<<"formattedName">> => <<"TestName">>,
  265:      <<"nameComponents">> => #{},
  266:      <<"address">> => [
  267:          #{
  268:              <<"tags">> => [<<"HOME">>, <<"WORK">>],
  269:              <<"pobox">> => <<"poboxTest">>,
  270:              <<"extadd">> => <<"extaddTest">>,
  271:              <<"street">> => <<"TESTSTREET123">>,
  272:              <<"locality">> => <<"LOCALITY123">>,
  273:              <<"region">> => <<"REGION777">>,
  274:              <<"country">> => <<"COUNTRY123">>
  275:          }
  276:      ]}.
  277: 
  278: complete_vcard_input() ->
  279:    #{<<"formattedName">> => <<"TestName">>,
  280:      <<"nameComponents">> => #{
  281:          <<"family">> => <<"familyName">>,
  282:          <<"givenName">> => <<"givenName">>,
  283:          <<"middleName">> => <<"middleName">>,
  284:          <<"prefix">> => <<"prefix">>,
  285:          <<"suffix">> => <<"sufix">>
  286:      },
  287:      <<"nickname">> => [<<"NicknameTest">>, <<"SecondNickname">>],
  288:      <<"photo">> => [
  289:         #{<<"type">> => <<"image/jpeg">>,
  290:           <<"binValue">> => <<"TestBinaries">>},
  291:         #{<<"extValue">> => <<"External Value">>}
  292:     ],
  293:      <<"birthday">> => [<<"birthdayTest">>, <<"SecondBirthday">>],
  294:      <<"address">> => [
  295:          #{
  296:              <<"tags">> => [<<"HOME">>, <<"WORK">>],
  297:              <<"pobox">> => <<"poboxTest">>,
  298:              <<"extadd">> => <<"extaddTest">>,
  299:              <<"street">> => <<"TESTSTREET123">>,
  300:              <<"locality">> => <<"LOCALITY123">>,
  301:              <<"region">> => <<"REGION777">>,
  302:              <<"pcode">> => <<"PcodeTest">>,
  303:              <<"country">> => <<"COUNTRY123">>
  304:          },
  305:          #{
  306:              <<"tags">> => [<<"HOME">>, <<"WORK">>, <<"POSTAL">>],
  307:              <<"pobox">> => <<"poboxTestSecond">>,
  308:              <<"extadd">> => <<"extaddTestSecond">>,
  309:              <<"street">> => <<"TESTSTREET123Second">>,
  310:              <<"locality">> => <<"LOCALITY123Second">>,
  311:              <<"region">> => <<"REGION777TEST">>,
  312:              <<"pcode">> => <<"PcodeTestSECOND">>,
  313:              <<"country">> => <<"COUNTRY123SECOND">>
  314:          }
  315:      ],
  316:      <<"label">> => [
  317:         #{<<"tags">> => [<<"WORK">>, <<"HOME">>], <<"line">> => [<<"LineTest">>, <<"AAA">>]},
  318:         #{<<"tags">> => [<<"POSTAL">>, <<"WORK">>], <<"line">> => [<<"LineTest2">>, <<"AAA">>]}
  319:      ],
  320:      <<"telephone">> => [
  321:          #{<<"tags">> => [<<"HOME">>, <<"BBS">>], <<"number">> => <<"590190190">>},
  322:          #{<<"tags">> => [<<"WORK">>, <<"BBS">>], <<"number">> => <<"590190191">>}
  323:      ],
  324:      <<"email">> => [
  325:          #{<<"tags">> => [<<"PREF">>], <<"userId">> => <<"userIDTEst">>},
  326:          #{<<"tags">> => [<<"PREF">>, <<"HOME">>], <<"userId">> => <<"userIDTEsTETt">>}
  327:      ],
  328:      <<"jabberId">> => [<<"JabberId">>, <<"JabberIDSecind">>],
  329:      <<"mailer">> => [<<"MailerTest">>, <<"MailerSecond">>],
  330:      <<"timeZone">> => [<<"TimeZoneTest">>, <<"TimeZOneSecond">>],
  331:      <<"geo">> => [
  332:          #{<<"lat">> => <<"LatitudeTest">>, <<"lon">> => <<"LongtitudeTest">>},
  333:          #{<<"lat">> => <<"LatitudeTest2">>, <<"lon">> => <<"LongtitudeTest2">>}
  334:      ],
  335:      <<"title">> => [<<"TitleTest">>, <<"SEcondTest">>],
  336:      <<"role">> => [<<"roleTest">>, <<"SecondRole">>],
  337:      <<"logo">> => [
  338:         #{<<"type">> => <<"image/jpeg">>,
  339:           <<"binValue">> => <<"TestBinariesLogo">>},
  340:         #{<<"extValue">> => <<"External Value Logo">>}
  341:      ],
  342:      <<"agent">> => [
  343:          #{<<"vcard">> => agent_vcard_input()},
  344:          #{<<"extValue">> => <<"TESTVALUE">>},
  345:          #{<<"vcard">> => agent_vcard_input()}
  346:      ],
  347:      <<"org">> => [
  348:          #{<<"orgname">> => <<"TESTNAME">>, <<"orgunit">> => [<<"test1">>, <<"TEST2">>]},
  349:          #{<<"orgname">> => <<"TESTNAME123">>, <<"orgunit">> => [<<"test1">>]}
  350:      ],
  351:      <<"categories">> => [
  352:          #{<<"keyword">> => [<<"KeywordTest">>]},
  353:          #{<<"keyword">> => [<<"KeywordTest">>, <<"Keyword2">>]}
  354:      ],
  355:      <<"note">> => [<<"NoteTest">>, <<"NOTE2">>],
  356:      <<"prodId">> => [<<"ProdIdTest">>, <<"PRodTEST2">>],
  357:      <<"rev">> => [<<"revTest">>, <<"RevTest2">>],
  358:      <<"sortString">> => [<<"sortStringTest">>, <<"String2">>],
  359:      <<"sound">> => [
  360:          #{<<"binValue">> => <<"TestBinValue">>},
  361:          #{<<"phonetic">> => <<"PhoneticTest">>},
  362:          #{<<"extValue">> => <<"ExtValueTest">>}
  363:      ],
  364:      <<"uid">> => [<<"UidTest">>, <<"UID2">>],
  365:      <<"url">> => [<<"UrlTest">>, <<"URL2">>],
  366:      <<"desc">> => [<<"DescTest">>, <<"DESC2">>],
  367:      <<"class">> => [
  368:          #{<<"tags">> => [<<"CONFIDENTIAL">>, <<"PRIVATE">>]},
  369:          #{<<"tags">> => [<<"CONFIDENTIAL">>]}
  370:      ],
  371:      <<"key">> => [
  372:          #{<<"type">> => <<"TYPETEST1">>, <<"credential">> => <<"TESTCREDENTIAL1">>},
  373:          #{<<"type">> => <<"TYPETEST2">>, <<"credential">> => <<"TESTCREDENTIAL2">>}
  374:      ]
  375:     }.
  376: 
  377: agent_vcard_input() ->
  378:    #{<<"formattedName">> => <<"TestName">>,
  379:      <<"nameComponents">> => #{
  380:          <<"family">> => <<"familyName">>,
  381:          <<"givenName">> => <<"givenName">>,
  382:          <<"middleName">> => <<"middleName">>,
  383:          <<"prefix">> => <<"prefix">>,
  384:          <<"suffix">> => <<"sufix">>
  385:      },
  386:      <<"nickname">> => [<<"NicknameTest">>, <<"SecondNickname">>],
  387:      <<"photo">> => [
  388:         #{<<"type">> => <<"image/jpeg">>,
  389:           <<"binValue">> => <<"TestBinaries">>},
  390:         #{<<"extValue">> => <<"External Value">>}
  391:     ]}.
  392: 
  393: admin_get_address_query() ->
  394:     <<"query Q1($user: JID!)
  395:        {
  396:            vcard
  397:            {
  398:                getVcard(user: $user)
  399:                {
  400:                    address
  401:                    {
  402:                        tags
  403:                        pobox
  404:                        extadd
  405:                        street
  406:                        locality
  407:                        region
  408:                        pcode
  409:                        country
  410:                    }
  411:                }
  412:            }
  413:        }">>.
  414: 
  415: user_get_query() ->
  416:     <<"query Q1($user: JID)
  417:        {
  418:            vcard
  419:            {
  420:                getVcard(user: $user)
  421:                {
  422:                     formattedName
  423:                     email
  424:                     {
  425:                         userId
  426:                         tags
  427:                     }
  428:                }
  429:            }
  430:        }">>.
  431: 
  432: admin_get_full_vcard_as_result_mutation() ->
  433:     ResultFormat = get_full_vcard_as_result(),
  434:     <<"mutation M1($vcard: VcardInput!, $user: JID!)",
  435:       "{vcard{setVcard(vcard: $vcard, user: $user)", ResultFormat/binary, "}}">>.
  436: 
  437: user_get_full_vcard_as_result_mutation() ->
  438:     ResultFormat = get_full_vcard_as_result(),
  439:     <<"mutation M1($vcard: VcardInput!){vcard{setVcard(vcard: $vcard)",
  440:       ResultFormat/binary, "}}">>.
  441: 
  442: user_get_full_vcard_as_result_query() ->
  443:     ResultFormat = get_full_vcard_as_result(),
  444:     <<"query Q1($user: JID){vcard{getVcard(user: $user)",
  445:       ResultFormat/binary, "}}">>.
  446: 
  447: admin_get_full_vcard_as_result_query() ->
  448:     ResultFormat = get_full_vcard_as_result(),
  449:     <<"query Q1($user: JID!)",
  450:       "{vcard{getVcard(user: $user)", ResultFormat/binary, "}}">>.
  451: 
  452: get_full_vcard_as_result() ->
  453:     <<"{
  454:            formattedName
  455:            nameComponents
  456:            { family givenName middleName prefix suffix }
  457:            nickname
  458:            photo
  459:            {
  460:                ... on ImageData
  461:                { type binValue }
  462:                ... on External
  463:                { extValue }
  464:            }
  465:            birthday
  466:            address
  467:            { tags pobox extadd street locality region pcode country }
  468:            label
  469:            { tags line }
  470:            telephone
  471:            { tags number }
  472:            email
  473:            { tags userId }
  474:            jabberId
  475:            mailer
  476:            timeZone
  477:            geo
  478:            { lat lon }
  479:            title
  480:            role
  481:            logo
  482:            {
  483:                ... on ImageData
  484:                { type binValue }
  485:                ... on External
  486:                { extValue }
  487:            }
  488:            agent
  489:            {
  490:                ... on External
  491:                { extValue }
  492:                ... on AgentVcard
  493:                {
  494:                    vcard
  495:                    {
  496:                        formattedName
  497:                        nameComponents
  498:                        { family givenName middleName prefix suffix }
  499:                        nickname
  500:                        photo
  501:                        {
  502:                            ... on ImageData
  503:                            { type binValue }
  504:                            ... on External
  505:                            { extValue }
  506:                        }
  507:                    }
  508:                }
  509:            }
  510:            org
  511:            { orgname orgunit }
  512:            categories
  513:            { keyword }
  514:            note
  515:            prodId
  516:            rev
  517:            sortString
  518:            sound
  519:            {
  520:                ... on External
  521:                { extValue }
  522:                ... on BinValue
  523:                { binValue }
  524:                ... on Phonetic
  525:                { phonetic }
  526:            }
  527:            uid
  528:            url
  529:            desc
  530:            class
  531:            { tags }
  532:            key
  533:            { type credential }
  534:        }">>.