data_user.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "data/data_user.h"
  8. #include "api/api_credits.h"
  9. #include "api/api_sensitive_content.h"
  10. #include "api/api_statistics.h"
  11. #include "storage/localstorage.h"
  12. #include "storage/storage_account.h"
  13. #include "storage/storage_user_photos.h"
  14. #include "main/main_session.h"
  15. #include "data/business/data_business_common.h"
  16. #include "data/business/data_business_info.h"
  17. #include "data/components/credits.h"
  18. #include "data/data_session.h"
  19. #include "data/data_changes.h"
  20. #include "data/data_peer_bot_command.h"
  21. #include "data/data_photo.h"
  22. #include "data/data_stories.h"
  23. #include "data/data_wall_paper.h"
  24. #include "data/notify/data_notify_settings.h"
  25. #include "history/history.h"
  26. #include "api/api_peer_photo.h"
  27. #include "apiwrap.h"
  28. #include "lang/lang_keys.h"
  29. #include "styles/style_chat.h"
  30. namespace {
  31. // User with hidden last seen stays online in UI for such amount of seconds.
  32. constexpr auto kSetOnlineAfterActivity = TimeId(30);
  33. using UpdateFlag = Data::PeerUpdate::Flag;
  34. bool ApplyBotVerifierSettings(
  35. not_null<BotInfo*> info,
  36. const MTPBotVerifierSettings *settings) {
  37. if (!settings) {
  38. const auto taken = base::take(info->verifierSettings);
  39. return taken != nullptr;
  40. }
  41. const auto &data = settings->data();
  42. const auto parsed = BotVerifierSettings{
  43. .iconId = DocumentId(data.vicon().v),
  44. .company = qs(data.vcompany()),
  45. .customDescription = qs(data.vcustom_description().value_or_empty()),
  46. .canModifyDescription = data.is_can_modify_custom_description(),
  47. };
  48. if (!info->verifierSettings) {
  49. info->verifierSettings = std::make_unique<BotVerifierSettings>(
  50. parsed);
  51. return true;
  52. } else if (*info->verifierSettings != parsed) {
  53. *info->verifierSettings = parsed;
  54. return true;
  55. }
  56. return false;
  57. }
  58. } // namespace
  59. BotInfo::BotInfo() = default;
  60. Data::LastseenStatus LastseenFromMTP(
  61. const MTPUserStatus &status,
  62. Data::LastseenStatus currentStatus) {
  63. return status.match([](const MTPDuserStatusEmpty &data) {
  64. return Data::LastseenStatus::LongAgo();
  65. }, [&](const MTPDuserStatusRecently &data) {
  66. return currentStatus.isLocalOnlineValue()
  67. ? Data::LastseenStatus::OnlineTill(
  68. currentStatus.onlineTill(),
  69. true,
  70. data.is_by_me())
  71. : Data::LastseenStatus::Recently(data.is_by_me());
  72. }, [](const MTPDuserStatusLastWeek &data) {
  73. return Data::LastseenStatus::WithinWeek(data.is_by_me());
  74. }, [](const MTPDuserStatusLastMonth &data) {
  75. return Data::LastseenStatus::WithinMonth(data.is_by_me());
  76. }, [](const MTPDuserStatusOnline& data) {
  77. return Data::LastseenStatus::OnlineTill(data.vexpires().v);
  78. }, [](const MTPDuserStatusOffline &data) {
  79. return Data::LastseenStatus::OnlineTill(data.vwas_online().v);
  80. });
  81. }
  82. UserData::UserData(not_null<Data::Session*> owner, PeerId id)
  83. : PeerData(owner, id)
  84. , _flags((id == owner->session().userPeerId()) ? Flag::Self : Flag(0)) {
  85. }
  86. UserData::~UserData() = default;
  87. bool UserData::canShareThisContact() const {
  88. return canShareThisContactFast()
  89. || !owner().findContactPhone(peerToUser(id)).isEmpty();
  90. }
  91. void UserData::setIsContact(bool is) {
  92. const auto status = is
  93. ? ContactStatus::Contact
  94. : ContactStatus::NotContact;
  95. if (_contactStatus != status) {
  96. _contactStatus = status;
  97. session().changes().peerUpdated(this, UpdateFlag::IsContact);
  98. }
  99. }
  100. Data::LastseenStatus UserData::lastseen() const {
  101. return _lastseen;
  102. }
  103. bool UserData::updateLastseen(Data::LastseenStatus value) {
  104. if (_lastseen == value) {
  105. return false;
  106. }
  107. _lastseen = value;
  108. owner().maybeStopWatchForOffline(this);
  109. return true;
  110. }
  111. // see Serialize::readPeer as well
  112. void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
  113. photo.match([&](const MTPDuserProfilePhoto &data) {
  114. if (data.is_personal()) {
  115. addFlags(UserDataFlag::PersonalPhoto);
  116. } else {
  117. removeFlags(UserDataFlag::PersonalPhoto);
  118. }
  119. updateUserpic(
  120. data.vphoto_id().v,
  121. data.vdc_id().v,
  122. data.is_has_video());
  123. }, [&](const MTPDuserProfilePhotoEmpty &) {
  124. removeFlags(UserDataFlag::PersonalPhoto);
  125. clearUserpic();
  126. });
  127. }
  128. auto UserData::unavailableReasons() const
  129. -> const std::vector<Data::UnavailableReason> & {
  130. return _unavailableReasons;
  131. }
  132. void UserData::setUnavailableReasonsList(
  133. std::vector<Data::UnavailableReason> &&reasons) {
  134. _unavailableReasons = std::move(reasons);
  135. }
  136. void UserData::setCommonChatsCount(int count) {
  137. if (_commonChatsCount != count) {
  138. _commonChatsCount = count;
  139. session().changes().peerUpdated(this, UpdateFlag::CommonChats);
  140. }
  141. }
  142. int UserData::peerGiftsCount() const {
  143. return _peerGiftsCount;
  144. }
  145. void UserData::setPeerGiftsCount(int count) {
  146. if (_peerGiftsCount != count) {
  147. _peerGiftsCount = count;
  148. session().changes().peerUpdated(this, UpdateFlag::PeerGifts);
  149. }
  150. }
  151. bool UserData::hasPrivateForwardName() const {
  152. return !_privateForwardName.isEmpty();
  153. }
  154. QString UserData::privateForwardName() const {
  155. return _privateForwardName;
  156. }
  157. void UserData::setPrivateForwardName(const QString &name) {
  158. _privateForwardName = name;
  159. }
  160. bool UserData::hasActiveStories() const {
  161. return flags() & Flag::HasActiveStories;
  162. }
  163. bool UserData::hasUnreadStories() const {
  164. return flags() & Flag::HasUnreadStories;
  165. }
  166. void UserData::setStoriesState(StoriesState state) {
  167. Expects(state != StoriesState::Unknown);
  168. const auto was = flags();
  169. switch (state) {
  170. case StoriesState::None:
  171. _flags.remove(Flag::HasActiveStories | Flag::HasUnreadStories);
  172. break;
  173. case StoriesState::HasRead:
  174. _flags.set(
  175. (flags() & ~Flag::HasUnreadStories) | Flag::HasActiveStories);
  176. break;
  177. case StoriesState::HasUnread:
  178. _flags.add(Flag::HasActiveStories | Flag::HasUnreadStories);
  179. break;
  180. }
  181. if (flags() != was) {
  182. if (const auto history = owner().historyLoaded(this)) {
  183. history->updateChatListEntryPostponed();
  184. }
  185. session().changes().peerUpdated(this, UpdateFlag::StoriesState);
  186. }
  187. }
  188. const Data::BusinessDetails &UserData::businessDetails() const {
  189. static const auto empty = Data::BusinessDetails();
  190. return _businessDetails ? *_businessDetails : empty;
  191. }
  192. void UserData::setBusinessDetails(Data::BusinessDetails details) {
  193. details.hours = details.hours.normalized();
  194. if ((!details && !_businessDetails)
  195. || (details && _businessDetails && details == *_businessDetails)) {
  196. return;
  197. }
  198. _businessDetails = details
  199. ? std::make_unique<Data::BusinessDetails>(std::move(details))
  200. : nullptr;
  201. session().changes().peerUpdated(this, UpdateFlag::BusinessDetails);
  202. }
  203. void UserData::setStarRefProgram(StarRefProgram program) {
  204. const auto info = botInfo.get();
  205. if (info && info->starRefProgram != program) {
  206. info->starRefProgram = program;
  207. session().changes().peerUpdated(
  208. this,
  209. Data::PeerUpdate::Flag::StarRefProgram);
  210. }
  211. }
  212. ChannelId UserData::personalChannelId() const {
  213. return _personalChannelId;
  214. }
  215. MsgId UserData::personalChannelMessageId() const {
  216. return _personalChannelMessageId;
  217. }
  218. void UserData::setPersonalChannel(ChannelId channelId, MsgId messageId) {
  219. if (_personalChannelId != channelId
  220. || _personalChannelMessageId != messageId) {
  221. _personalChannelId = channelId;
  222. _personalChannelMessageId = messageId;
  223. session().changes().peerUpdated(this, UpdateFlag::PersonalChannel);
  224. }
  225. }
  226. void UserData::setName(
  227. const QString &newFirstName,
  228. const QString &newLastName,
  229. const QString &newPhoneName,
  230. const QString &newUsername) {
  231. bool changeName = !newFirstName.isEmpty() || !newLastName.isEmpty();
  232. QString newFullName;
  233. if (changeName && newFirstName.trimmed().isEmpty()) {
  234. firstName = newLastName;
  235. lastName = QString();
  236. newFullName = firstName;
  237. } else {
  238. if (changeName) {
  239. firstName = newFirstName;
  240. lastName = newLastName;
  241. }
  242. newFullName = lastName.isEmpty()
  243. ? firstName
  244. : tr::lng_full_name(
  245. tr::now,
  246. lt_first_name,
  247. firstName,
  248. lt_last_name,
  249. lastName);
  250. }
  251. updateNameDelayed(newFullName, newPhoneName, newUsername);
  252. }
  253. void UserData::setUsernames(const Data::Usernames &newUsernames) {
  254. const auto wasUsername = username();
  255. const auto wasUsernames = usernames();
  256. _username.setUsernames(newUsernames);
  257. const auto nowUsername = username();
  258. const auto nowUsernames = usernames();
  259. session().changes().peerUpdated(
  260. this,
  261. UpdateFlag()
  262. | ((wasUsername != nowUsername)
  263. ? UpdateFlag::Username
  264. : UpdateFlag())
  265. | (!ranges::equal(wasUsernames, nowUsernames)
  266. ? UpdateFlag::Usernames
  267. : UpdateFlag()));
  268. }
  269. void UserData::setUsername(const QString &username) {
  270. _username.setUsername(username);
  271. }
  272. void UserData::setPhone(const QString &newPhone) {
  273. if (_phone != newPhone) {
  274. _phone = newPhone;
  275. }
  276. }
  277. void UserData::setBotInfoVersion(int version) {
  278. if (version < 0) {
  279. // We don't support bots becoming non-bots.
  280. if (botInfo) {
  281. botInfo->version = -1;
  282. }
  283. } else if (!botInfo) {
  284. botInfo = std::make_unique<BotInfo>();
  285. botInfo->version = version;
  286. owner().userIsBotChanged(this);
  287. } else if (botInfo->version < version) {
  288. if (!botInfo->commands.empty()) {
  289. botInfo->commands.clear();
  290. owner().botCommandsChanged(this);
  291. }
  292. botInfo->description.clear();
  293. botInfo->version = version;
  294. botInfo->inited = false;
  295. }
  296. }
  297. void UserData::setBotInfo(const MTPBotInfo &info) {
  298. switch (info.type()) {
  299. case mtpc_botInfo: {
  300. const auto &d = info.c_botInfo();
  301. if (!isBot()) {
  302. return;
  303. } else if (d.vuser_id() && peerFromUser(*d.vuser_id()) != id) {
  304. return;
  305. }
  306. const auto description = qs(d.vdescription().value_or_empty());
  307. if (botInfo->description != description) {
  308. botInfo->description = description;
  309. ++botInfo->descriptionVersion;
  310. }
  311. if (const auto photo = d.vdescription_photo()) {
  312. const auto parsed = owner().processPhoto(*photo);
  313. if (botInfo->photo != parsed) {
  314. botInfo->photo = parsed;
  315. ++botInfo->descriptionVersion;
  316. }
  317. } else if (botInfo->photo) {
  318. botInfo->photo = nullptr;
  319. ++botInfo->descriptionVersion;
  320. }
  321. if (const auto document = d.vdescription_document()) {
  322. const auto parsed = owner().processDocument(*document);
  323. if (botInfo->document != parsed) {
  324. botInfo->document = parsed;
  325. ++botInfo->descriptionVersion;
  326. }
  327. } else if (botInfo->document) {
  328. botInfo->document = nullptr;
  329. ++botInfo->descriptionVersion;
  330. }
  331. auto commands = d.vcommands()
  332. ? ranges::views::all(
  333. d.vcommands()->v
  334. ) | ranges::views::transform(
  335. Data::BotCommandFromTL
  336. ) | ranges::to_vector
  337. : std::vector<Data::BotCommand>();
  338. const auto changedCommands = !ranges::equal(
  339. botInfo->commands,
  340. commands);
  341. botInfo->commands = std::move(commands);
  342. const auto changedButton = Data::ApplyBotMenuButton(
  343. botInfo.get(),
  344. d.vmenu_button());
  345. botInfo->inited = true;
  346. const auto privacy = qs(d.vprivacy_policy_url().value_or_empty());
  347. const auto privacyChanged = (botInfo->privacyPolicyUrl != privacy);
  348. botInfo->privacyPolicyUrl = privacy;
  349. if (const auto settings = d.vapp_settings()) {
  350. const auto &data = settings->data();
  351. botInfo->botAppColorTitleDay = Ui::MaybeColorFromSerialized(
  352. data.vheader_color()).value_or(QColor(0, 0, 0, 0));
  353. botInfo->botAppColorTitleNight = Ui::MaybeColorFromSerialized(
  354. data.vheader_dark_color()).value_or(QColor(0, 0, 0, 0));
  355. botInfo->botAppColorBodyDay = Ui::MaybeColorFromSerialized(
  356. data.vbackground_color()).value_or(QColor(0, 0, 0, 0));
  357. botInfo->botAppColorBodyNight = Ui::MaybeColorFromSerialized(
  358. data.vbackground_dark_color()).value_or(QColor(0, 0, 0, 0));
  359. } else {
  360. botInfo->botAppColorTitleDay
  361. = botInfo->botAppColorTitleNight
  362. = botInfo->botAppColorBodyDay
  363. = botInfo->botAppColorBodyNight
  364. = QColor(0, 0, 0, 0);
  365. }
  366. const auto changedVerifierSettings = ApplyBotVerifierSettings(
  367. botInfo.get(),
  368. d.vverifier_settings());
  369. if (changedCommands
  370. || changedButton
  371. || privacyChanged
  372. || changedVerifierSettings) {
  373. owner().botCommandsChanged(this);
  374. }
  375. } break;
  376. }
  377. }
  378. void UserData::setNameOrPhone(const QString &newNameOrPhone) {
  379. nameOrPhone = newNameOrPhone;
  380. }
  381. void UserData::madeAction(TimeId when) {
  382. if (isBot() || isServiceUser() || when <= 0) {
  383. return;
  384. }
  385. const auto till = lastseen().onlineTill();
  386. if (till < when + 1
  387. && updateLastseen(
  388. Data::LastseenStatus::OnlineTill(
  389. when + kSetOnlineAfterActivity,
  390. !till || lastseen().isLocalOnlineValue(),
  391. lastseen().isHiddenByMe()))) {
  392. session().changes().peerUpdated(this, UpdateFlag::OnlineStatus);
  393. }
  394. }
  395. void UserData::setAccessHash(uint64 accessHash) {
  396. if (accessHash == kInaccessibleAccessHashOld) {
  397. _accessHash = 0;
  398. _flags.add(Flag::Deleted);
  399. invalidateEmptyUserpic();
  400. } else {
  401. _accessHash = accessHash;
  402. }
  403. }
  404. void UserData::setFlags(UserDataFlags which) {
  405. if ((which & UserDataFlag::Deleted)
  406. != (flags() & UserDataFlag::Deleted)) {
  407. invalidateEmptyUserpic();
  408. }
  409. _flags.set((flags() & UserDataFlag::Self)
  410. | (which & ~UserDataFlag::Self));
  411. }
  412. void UserData::addFlags(UserDataFlags which) {
  413. setFlags(flags() | which);
  414. }
  415. void UserData::removeFlags(UserDataFlags which) {
  416. setFlags(flags() & ~which);
  417. }
  418. bool UserData::isVerified() const {
  419. return flags() & UserDataFlag::Verified;
  420. }
  421. bool UserData::isScam() const {
  422. return flags() & UserDataFlag::Scam;
  423. }
  424. bool UserData::isFake() const {
  425. return flags() & UserDataFlag::Fake;
  426. }
  427. bool UserData::isPremium() const {
  428. return flags() & UserDataFlag::Premium;
  429. }
  430. bool UserData::isBotInlineGeo() const {
  431. return flags() & UserDataFlag::BotInlineGeo;
  432. }
  433. bool UserData::isBot() const {
  434. return botInfo != nullptr;
  435. }
  436. bool UserData::isSupport() const {
  437. return flags() & UserDataFlag::Support;
  438. }
  439. bool UserData::isInaccessible() const {
  440. return flags() & UserDataFlag::Deleted;
  441. }
  442. bool UserData::applyMinPhoto() const {
  443. return !(flags() & UserDataFlag::DiscardMinPhoto);
  444. }
  445. bool UserData::hasPersonalPhoto() const {
  446. return (flags() & UserDataFlag::PersonalPhoto);
  447. }
  448. bool UserData::hasStoriesHidden() const {
  449. return (flags() & UserDataFlag::StoriesHidden);
  450. }
  451. bool UserData::hasRequirePremiumToWrite() const {
  452. return (flags() & UserDataFlag::HasRequirePremiumToWrite);
  453. }
  454. bool UserData::hasStarsPerMessage() const {
  455. return (flags() & UserDataFlag::HasStarsPerMessage);
  456. }
  457. bool UserData::requiresPremiumToWrite() const {
  458. return !isSelf() && (flags() & UserDataFlag::RequiresPremiumToWrite);
  459. }
  460. bool UserData::messageMoneyRestrictionsKnown() const {
  461. return (flags() & UserDataFlag::MessageMoneyRestrictionsKnown);
  462. }
  463. bool UserData::canSendIgnoreMoneyRestrictions() const {
  464. return !isInaccessible() && !isRepliesChat() && !isVerifyCodes();
  465. }
  466. bool UserData::readDatesPrivate() const {
  467. return (flags() & UserDataFlag::ReadDatesPrivate);
  468. }
  469. int UserData::starsPerMessage() const {
  470. return _starsPerMessage;
  471. }
  472. void UserData::setStarsPerMessage(int stars) {
  473. if (_starsPerMessage != stars) {
  474. _starsPerMessage = stars;
  475. session().changes().peerUpdated(this, UpdateFlag::StarsPerMessage);
  476. }
  477. checkTrustedPayForMessage();
  478. }
  479. bool UserData::canAddContact() const {
  480. return canShareThisContact() && !isContact();
  481. }
  482. bool UserData::canShareThisContactFast() const {
  483. return !_phone.isEmpty();
  484. }
  485. QString UserData::username() const {
  486. return _username.username();
  487. }
  488. QString UserData::editableUsername() const {
  489. return _username.editableUsername();
  490. }
  491. const std::vector<QString> &UserData::usernames() const {
  492. return _username.usernames();
  493. }
  494. bool UserData::isUsernameEditable(QString username) const {
  495. return _username.isEditable(username);
  496. }
  497. void UserData::setBotVerifyDetails(Ui::BotVerifyDetails details) {
  498. if (!details) {
  499. if (_botVerifyDetails) {
  500. _botVerifyDetails = nullptr;
  501. session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
  502. }
  503. } else if (!_botVerifyDetails) {
  504. _botVerifyDetails = std::make_unique<Ui::BotVerifyDetails>(details);
  505. session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
  506. } else if (*_botVerifyDetails != details) {
  507. *_botVerifyDetails = details;
  508. session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
  509. }
  510. }
  511. void UserData::setBotVerifyDetailsIcon(DocumentId iconId) {
  512. if (!iconId) {
  513. setBotVerifyDetails({});
  514. } else {
  515. auto info = _botVerifyDetails
  516. ? *_botVerifyDetails
  517. : Ui::BotVerifyDetails();
  518. info.iconId = iconId;
  519. setBotVerifyDetails(info);
  520. }
  521. }
  522. const QString &UserData::phone() const {
  523. return _phone;
  524. }
  525. UserData::ContactStatus UserData::contactStatus() const {
  526. return _contactStatus;
  527. }
  528. bool UserData::isContact() const {
  529. return (contactStatus() == ContactStatus::Contact);
  530. }
  531. UserData::CallsStatus UserData::callsStatus() const {
  532. return _callsStatus;
  533. }
  534. int UserData::commonChatsCount() const {
  535. return _commonChatsCount;
  536. }
  537. void UserData::setCallsStatus(CallsStatus callsStatus) {
  538. if (callsStatus != _callsStatus) {
  539. _callsStatus = callsStatus;
  540. session().changes().peerUpdated(this, UpdateFlag::HasCalls);
  541. }
  542. }
  543. Data::Birthday UserData::birthday() const {
  544. return _birthday;
  545. }
  546. void UserData::setBirthday(Data::Birthday value) {
  547. if (_birthday != value) {
  548. _birthday = value;
  549. session().changes().peerUpdated(this, UpdateFlag::Birthday);
  550. if (isSelf()) {
  551. session().api().sensitiveContent().reload(true);
  552. }
  553. }
  554. }
  555. void UserData::setBirthday(const tl::conditional<MTPBirthday> &value) {
  556. if (!value) {
  557. setBirthday(Data::Birthday());
  558. } else {
  559. const auto &data = value->data();
  560. setBirthday(Data::Birthday(
  561. data.vday().v,
  562. data.vmonth().v,
  563. data.vyear().value_or_empty()));
  564. }
  565. }
  566. bool UserData::hasCalls() const {
  567. return (callsStatus() != CallsStatus::Disabled)
  568. && (callsStatus() != CallsStatus::Unknown);
  569. }
  570. namespace Data {
  571. void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
  572. const auto profilePhoto = update.vprofile_photo()
  573. ? user->owner().processPhoto(*update.vprofile_photo()).get()
  574. : nullptr;
  575. const auto personalPhoto = update.vpersonal_photo()
  576. ? user->owner().processPhoto(*update.vpersonal_photo()).get()
  577. : nullptr;
  578. if (personalPhoto && profilePhoto) {
  579. user->session().api().peerPhoto().registerNonPersonalPhoto(
  580. user,
  581. profilePhoto);
  582. } else {
  583. user->session().api().peerPhoto().unregisterNonPersonalPhoto(user);
  584. }
  585. if (const auto photo = update.vfallback_photo()) {
  586. const auto data = user->owner().processPhoto(*photo);
  587. if (!data->isNull()) { // Sometimes there is photoEmpty :shrug:
  588. user->session().storage().add(Storage::UserPhotosSetBack(
  589. peerToUser(user->id),
  590. data->id
  591. ));
  592. }
  593. }
  594. user->setBarSettings(update.vsettings());
  595. user->owner().notifySettings().apply(user, update.vnotify_settings());
  596. user->setMessagesTTL(update.vttl_period().value_or_empty());
  597. if (const auto info = update.vbot_info()) {
  598. user->setBotInfo(*info);
  599. } else {
  600. user->setBotInfoVersion(-1);
  601. }
  602. if (const auto info = user->botInfo.get()) {
  603. info->canManageEmojiStatus = update.is_bot_can_manage_emoji_status();
  604. user->setStarRefProgram(
  605. Data::ParseStarRefProgram(update.vstarref_program()));
  606. }
  607. if (const auto pinned = update.vpinned_msg_id()) {
  608. SetTopPinnedMessageId(user, pinned->v);
  609. }
  610. user->setStarsPerMessage(
  611. update.vsend_paid_messages_stars().value_or_empty());
  612. using Flag = UserDataFlag;
  613. const auto mask = Flag::Blocked
  614. | Flag::HasPhoneCalls
  615. | Flag::PhoneCallsPrivate
  616. | Flag::CanPinMessages
  617. | Flag::VoiceMessagesForbidden
  618. | Flag::ReadDatesPrivate
  619. | Flag::MessageMoneyRestrictionsKnown
  620. | Flag::RequiresPremiumToWrite;
  621. user->setFlags((user->flags() & ~mask)
  622. | (update.is_phone_calls_private()
  623. ? Flag::PhoneCallsPrivate
  624. : Flag())
  625. | (update.is_phone_calls_available() ? Flag::HasPhoneCalls : Flag())
  626. | (update.is_can_pin_message() ? Flag::CanPinMessages : Flag())
  627. | (update.is_blocked() ? Flag::Blocked : Flag())
  628. | (update.is_voice_messages_forbidden()
  629. ? Flag::VoiceMessagesForbidden
  630. : Flag())
  631. | (update.is_read_dates_private() ? Flag::ReadDatesPrivate : Flag())
  632. | Flag::MessageMoneyRestrictionsKnown
  633. | (update.is_contact_require_premium()
  634. ? Flag::RequiresPremiumToWrite
  635. : Flag()));
  636. user->setIsBlocked(update.is_blocked());
  637. user->setCallsStatus(update.is_phone_calls_private()
  638. ? UserData::CallsStatus::Private
  639. : update.is_phone_calls_available()
  640. ? UserData::CallsStatus::Enabled
  641. : UserData::CallsStatus::Disabled);
  642. user->setAbout(qs(update.vabout().value_or_empty()));
  643. user->setCommonChatsCount(update.vcommon_chats_count().v);
  644. user->setPeerGiftsCount(update.vstargifts_count().value_or_empty());
  645. user->checkFolder(update.vfolder_id().value_or_empty());
  646. user->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));
  647. user->setTranslationDisabled(update.is_translations_disabled());
  648. user->setPrivateForwardName(
  649. update.vprivate_forward_name().value_or_empty());
  650. if (const auto info = user->botInfo.get()) {
  651. const auto group = update.vbot_group_admin_rights()
  652. ? ChatAdminRightsInfo(*update.vbot_group_admin_rights()).flags
  653. : ChatAdminRights();
  654. const auto channel = update.vbot_broadcast_admin_rights()
  655. ? ChatAdminRightsInfo(
  656. *update.vbot_broadcast_admin_rights()).flags
  657. : ChatAdminRights();
  658. if (info->groupAdminRights != group
  659. || info->channelAdminRights != channel) {
  660. info->groupAdminRights = group;
  661. info->channelAdminRights = channel;
  662. user->session().changes().peerUpdated(
  663. user,
  664. Data::PeerUpdate::Flag::Rights);
  665. }
  666. if (info->canEditInformation) {
  667. const auto id = user->id;
  668. const auto weak = base::make_weak(&user->session());
  669. const auto creditsLoadLifetime
  670. = std::make_shared<rpl::lifetime>();
  671. const auto creditsLoad
  672. = creditsLoadLifetime->make_state<Api::CreditsStatus>(user);
  673. creditsLoad->request({}, [=](Data::CreditsStatusSlice slice) {
  674. if (const auto strong = weak.get()) {
  675. strong->credits().apply(id, slice.balance);
  676. creditsLoadLifetime->destroy();
  677. }
  678. });
  679. const auto currencyLoadLifetime
  680. = std::make_shared<rpl::lifetime>();
  681. const auto currencyLoad
  682. = currencyLoadLifetime->make_state<Api::EarnStatistics>(user);
  683. currencyLoad->request(
  684. ) | rpl::start_with_error_done([=](const QString &error) {
  685. currencyLoadLifetime->destroy();
  686. }, [=] {
  687. if (const auto strong = weak.get()) {
  688. strong->credits().applyCurrency(
  689. id,
  690. currencyLoad->data().currentBalance);
  691. currencyLoadLifetime->destroy();
  692. }
  693. }, *currencyLoadLifetime);
  694. }
  695. }
  696. if (const auto paper = update.vwallpaper()) {
  697. user->setWallPaper(
  698. Data::WallPaper::Create(&user->session(), *paper),
  699. update.is_wallpaper_overridden());
  700. } else {
  701. user->setWallPaper({});
  702. }
  703. user->setBusinessDetails(FromMTP(
  704. &user->owner(),
  705. update.vbusiness_work_hours(),
  706. update.vbusiness_location(),
  707. update.vbusiness_intro()));
  708. user->setBirthday(update.vbirthday());
  709. user->setPersonalChannel(
  710. update.vpersonal_channel_id().value_or_empty(),
  711. update.vpersonal_channel_message().value_or_empty());
  712. if (user->isSelf()) {
  713. user->owner().businessInfo().applyAwaySettings(
  714. FromMTP(&user->owner(), update.vbusiness_away_message()));
  715. user->owner().businessInfo().applyGreetingSettings(
  716. FromMTP(&user->owner(), update.vbusiness_greeting_message()));
  717. }
  718. user->setBotVerifyDetails(
  719. ParseBotVerifyDetails(update.vbot_verification()));
  720. user->owner().stories().apply(user, update.vstories());
  721. user->fullUpdated();
  722. }
  723. StarRefProgram ParseStarRefProgram(const MTPStarRefProgram *program) {
  724. if (!program) {
  725. return {};
  726. }
  727. auto result = StarRefProgram();
  728. const auto &data = program->data();
  729. result.commission = data.vcommission_permille().v;
  730. result.durationMonths = data.vduration_months().value_or_empty();
  731. result.revenuePerUser = data.vdaily_revenue_per_user()
  732. ? Data::FromTL(*data.vdaily_revenue_per_user())
  733. : StarsAmount();
  734. result.endDate = data.vend_date().value_or_empty();
  735. return result;
  736. }
  737. Ui::BotVerifyDetails ParseBotVerifyDetails(const MTPBotVerification *info) {
  738. if (!info) {
  739. return {};
  740. }
  741. const auto &data = info->data();
  742. const auto description = qs(data.vdescription());
  743. const auto flags = TextParseLinks;
  744. return {
  745. .botId = UserId(data.vbot_id().v),
  746. .iconId = DocumentId(data.vicon().v),
  747. .description = TextUtilities::ParseEntities(description, flags),
  748. };
  749. }
  750. } // namespace Data