You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

actions.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // @flow
  2. import type { Dispatch } from 'redux';
  3. import { getShareInfoText } from '../invite';
  4. import {
  5. SET_GOOGLE_API_PROFILE,
  6. SET_GOOGLE_API_STATE
  7. } from './actionTypes';
  8. import { GOOGLE_API_STATES } from './constants';
  9. import googleApi from './googleApi';
  10. /**
  11. * Retrieves the current calendar events.
  12. *
  13. * @param {number} fetchStartDays - The number of days to go back when fetching.
  14. * @param {number} fetchEndDays - The number of days to fetch.
  15. * @returns {function(Dispatch<any>): Promise<CalendarEntries>}
  16. */
  17. export function getCalendarEntries(
  18. fetchStartDays: ?number, fetchEndDays: ?number) {
  19. return () =>
  20. googleApi.get()
  21. .then(() =>
  22. googleApi._getCalendarEntries(fetchStartDays, fetchEndDays));
  23. }
  24. /**
  25. * Loads Google API.
  26. *
  27. * @param {string} clientId - The client ID to be used with the API library.
  28. * @returns {Function}
  29. */
  30. export function loadGoogleAPI(clientId: string) {
  31. return (dispatch: Dispatch<any>, getState: Function) =>
  32. googleApi.get()
  33. .then(() => {
  34. if (getState()['features/google-api'].googleAPIState
  35. === GOOGLE_API_STATES.NEEDS_LOADING) {
  36. return googleApi.initializeClient(clientId);
  37. }
  38. return Promise.resolve();
  39. })
  40. .then(() => dispatch(setGoogleAPIState(GOOGLE_API_STATES.LOADED)))
  41. .then(() => googleApi.isSignedIn())
  42. .then(isSignedIn => {
  43. if (isSignedIn) {
  44. dispatch(setGoogleAPIState(GOOGLE_API_STATES.SIGNED_IN));
  45. }
  46. });
  47. }
  48. /**
  49. * Executes a request for a list of all YouTube broadcasts associated with
  50. * user currently signed in to the Google API Client Library.
  51. *
  52. * @returns {function(): (Promise<*>|Promise<any[] | never>)}
  53. */
  54. export function requestAvailableYouTubeBroadcasts() {
  55. return () =>
  56. googleApi.requestAvailableYouTubeBroadcasts()
  57. .then(response => {
  58. // Takes in a list of broadcasts from the YouTube API,
  59. // removes dupes, removes broadcasts that cannot get a stream key,
  60. // and parses the broadcasts into flat objects.
  61. const broadcasts = response.result.items;
  62. const parsedBroadcasts = {};
  63. for (let i = 0; i < broadcasts.length; i++) {
  64. const broadcast = broadcasts[i];
  65. const boundStreamID = broadcast.contentDetails.boundStreamId;
  66. if (boundStreamID && !parsedBroadcasts[boundStreamID]) {
  67. parsedBroadcasts[boundStreamID] = {
  68. boundStreamID,
  69. id: broadcast.id,
  70. status: broadcast.status.lifeCycleStatus,
  71. title: broadcast.snippet.title
  72. };
  73. }
  74. }
  75. return Object.values(parsedBroadcasts);
  76. });
  77. }
  78. /**
  79. * Fetches the stream key for a YouTube broadcast and updates the internal
  80. * state to display the associated stream key as being entered.
  81. *
  82. * @param {string} boundStreamID - The bound stream ID associated with the
  83. * broadcast from which to get the stream key.
  84. * @returns {function(): (Promise<*>|Promise<{
  85. * streamKey: (*|string),
  86. * selectedBoundStreamID: *} | never>)}
  87. */
  88. export function requestLiveStreamsForYouTubeBroadcast(boundStreamID: string) {
  89. return () =>
  90. googleApi.requestLiveStreamsForYouTubeBroadcast(boundStreamID)
  91. .then(response => {
  92. const broadcasts = response.result.items;
  93. const streamName = broadcasts
  94. && broadcasts[0]
  95. && broadcasts[0].cdn.ingestionInfo.streamName;
  96. const streamKey = streamName || '';
  97. return {
  98. streamKey,
  99. selectedBoundStreamID: boundStreamID
  100. };
  101. });
  102. }
  103. /**
  104. * Sets the current Google API state.
  105. *
  106. * @param {number} googleAPIState - The state to be set.
  107. * @param {Object} googleResponse - The last response from Google.
  108. * @returns {{
  109. * type: SET_GOOGLE_API_STATE,
  110. * googleAPIState: number
  111. * }}
  112. */
  113. export function setGoogleAPIState(
  114. googleAPIState: number, googleResponse: ?Object) {
  115. return {
  116. type: SET_GOOGLE_API_STATE,
  117. googleAPIState,
  118. googleResponse
  119. };
  120. }
  121. /**
  122. * Forces the Google web client application to prompt for a sign in, such as
  123. * when changing account, and will then fetch available YouTube broadcasts.
  124. *
  125. * @returns {function(): (Promise<*>|Promise<{
  126. * streamKey: (*|string),
  127. * selectedBoundStreamID: *} | never>)}
  128. */
  129. export function showAccountSelection() {
  130. return () =>
  131. googleApi.showAccountSelection();
  132. }
  133. /**
  134. * Prompts the participant to sign in to the Google API Client Library.
  135. *
  136. * @returns {function(Dispatch<any>): Promise<string | never>}
  137. */
  138. export function signIn() {
  139. return (dispatch: Dispatch<any>) => googleApi.get()
  140. .then(() => googleApi.signInIfNotSignedIn())
  141. .then(() => dispatch({
  142. type: SET_GOOGLE_API_STATE,
  143. googleAPIState: GOOGLE_API_STATES.SIGNED_IN
  144. }));
  145. }
  146. /**
  147. * Logs out the user.
  148. *
  149. * @returns {function(Dispatch<any>): Promise<string | never>}
  150. */
  151. export function signOut() {
  152. return (dispatch: Dispatch<any>) =>
  153. googleApi.get()
  154. .then(() => googleApi.signOut())
  155. .then(() => {
  156. dispatch({
  157. type: SET_GOOGLE_API_STATE,
  158. googleAPIState: GOOGLE_API_STATES.LOADED
  159. });
  160. dispatch({
  161. type: SET_GOOGLE_API_PROFILE,
  162. profileEmail: ''
  163. });
  164. });
  165. }
  166. /**
  167. * Updates the profile data that is currently used.
  168. *
  169. * @returns {function(Dispatch<any>): Promise<string | never>}
  170. */
  171. export function updateProfile() {
  172. return (dispatch: Dispatch<any>) => googleApi.get()
  173. .then(() => googleApi.signInIfNotSignedIn())
  174. .then(() => dispatch({
  175. type: SET_GOOGLE_API_STATE,
  176. googleAPIState: GOOGLE_API_STATES.SIGNED_IN
  177. }))
  178. .then(() => googleApi.getCurrentUserProfile())
  179. .then(profile => {
  180. dispatch({
  181. type: SET_GOOGLE_API_PROFILE,
  182. profileEmail: profile.getEmail()
  183. });
  184. return profile.getEmail();
  185. });
  186. }
  187. /**
  188. * Updates the calendar event and adds a location and text.
  189. *
  190. * @param {string} id - The event id to update.
  191. * @param {string} calendarId - The calendar id to use.
  192. * @param {string} location - The location to add to the event.
  193. * @returns {function(Dispatch<any>): Promise<string | never>}
  194. */
  195. export function updateCalendarEvent(
  196. id: string, calendarId: string, location: string) {
  197. return (dispatch: Dispatch<any>, getState: Function) =>
  198. getShareInfoText(getState(), location)
  199. .then(text =>
  200. googleApi._updateCalendarEntry(id, calendarId, location, text));
  201. }