write-tweet.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { Component } from "@angular/core";
  2. import {
  3. IonicPage,
  4. NavController,
  5. NavParams,
  6. LoadingController,
  7. AlertController
  8. } from "ionic-angular";
  9. import { FormBuilder, Validators, FormGroup } from "@angular/forms";
  10. import { TwitterApiProvider } from "../../providers/twitter-api/twitter-api";
  11. import { Storage } from "@ionic/storage";
  12. import { P2pStorageIpfsProvider } from "../../providers/p2p-storage-ipfs/p2p-storage-ipfs";
  13. import { P2pDatabaseGunProvider } from "../../providers/p2p-database-gun/p2p-database-gun";
  14. import twittertext from "twitter-text";
  15. import { CryptoProvider } from "../../providers/crypto/crypto";
  16. @IonicPage()
  17. @Component({
  18. selector: "page-write-tweet",
  19. templateUrl: "write-tweet.html"
  20. })
  21. export class WriteTweetPage {
  22. tweet: FormGroup;
  23. retweetId: string;
  24. replyToStatusId: string;
  25. retweet;
  26. replyTweet;
  27. constructor(
  28. public navCtrl: NavController,
  29. public navParams: NavParams,
  30. private formBuilder: FormBuilder,
  31. private twitter: TwitterApiProvider,
  32. private loadingCtrl: LoadingController,
  33. private storage: Storage,
  34. private ipfs: P2pStorageIpfsProvider,
  35. private gun: P2pDatabaseGunProvider,
  36. private cryptoUtils: CryptoProvider,
  37. private alertCtrl: AlertController
  38. ) {
  39. this.retweetId = this.navParams.get("tweetId");
  40. this.replyToStatusId = this.navParams.get("replyToStatus");
  41. this.tweet = this.formBuilder.group({
  42. text: ["", Validators.maxLength(140)],
  43. p2p: [false]
  44. });
  45. }
  46. async ionViewDidLoad() {
  47. if (this.retweetId) {
  48. this.retweet = await this.twitter.fetchTweet(this.retweetId);
  49. }
  50. if (this.replyToStatusId) {
  51. this.replyTweet = await this.twitter.fetchTweet(this.replyToStatusId);
  52. }
  53. }
  54. get tweetCharProgress() {
  55. let progress = 1 - this.tweet.value["text"].length / 140;
  56. let radius = 8;
  57. let circumference = Math.PI * radius * 2;
  58. return progress * circumference;
  59. }
  60. async submitTweet() {
  61. const loading = this.loadingCtrl.create();
  62. loading.present();
  63. if (this.tweet.value.p2p) {
  64. if (
  65. (await this.cryptoUtils.isPrivateKeySet()) &&
  66. (await this.cryptoUtils.isPublicKeyPublished())
  67. ) {
  68. await this.tweetPrivate();
  69. } else {
  70. const alert = this.alertCtrl.create({
  71. title: "Oooops...",
  72. message:
  73. "Please verify that you have set a private and public key in the settings and that your latest public key was published."
  74. });
  75. loading.dismiss();
  76. alert.present();
  77. return;
  78. }
  79. } else {
  80. await this.twitter.tweet(
  81. this.tweet.value["text"],
  82. this.retweet,
  83. this.replyToStatusId
  84. );
  85. }
  86. loading.dismiss();
  87. this.navCtrl.pop();
  88. }
  89. private async tweetPrivate() {
  90. const tweet = await this.buildPrivateTweet();
  91. const privateKey = await this.storage.get("privateKey");
  92. const encryptedTweet = this.cryptoUtils.encrypt(
  93. JSON.stringify(tweet),
  94. privateKey
  95. );
  96. const res = await this.ipfs.storeTweet(encryptedTweet);
  97. this.gun.storeLastTweetHashForUser(
  98. tweet.user_id,
  99. res["Hash"],
  100. tweet.created_at
  101. );
  102. this.gun.publishHashtags(tweet.entities.hashtags);
  103. }
  104. private async buildPrivateTweet() {
  105. const status = this.tweet.value["text"].trim();
  106. const entities = await this.getEntities(status);
  107. return {
  108. full_text: status,
  109. user_id: await this.storage.get("userId"),
  110. created_at: Date.now(),
  111. private_tweet: true,
  112. display_text_range: [0, status.length],
  113. entities: entities
  114. };
  115. }
  116. private async getEntities(status: string) {
  117. return {
  118. hashtags: twittertext.extractHashtagsWithIndices(status),
  119. urls: twittertext.extractUrlsWithIndices(status),
  120. user_mentions: await this.getMentions(status)
  121. };
  122. }
  123. private async getMentions(status: string) {
  124. // extract mentions
  125. const entities = twittertext.extractMentionsWithIndices(status);
  126. // add user_id
  127. const entitiesWithPromises = entities.map(async mention => {
  128. try {
  129. const user = await this.twitter.fetchUserFromScreenName(
  130. mention.screenName
  131. );
  132. mention["id_str"] = user[0]["id_str"];
  133. mention["screen_name"] = mention.screenName;
  134. delete mention.screenName;
  135. } catch (err) {
  136. console.error(
  137. "There is no user signed up to twitter with username: " +
  138. mention.screenName
  139. );
  140. }
  141. return mention;
  142. });
  143. // filter for valid users and return
  144. return (await Promise.all(entitiesWithPromises)).filter(el =>
  145. el.hasOwnProperty("id_str")
  146. );
  147. }
  148. }