diff --git a/app/Http/Controllers/Api/V1/MicroSoftTeamController.php b/app/Http/Controllers/Api/V1/MicroSoftTeamController.php index 071dadfdc..d179af449 100644 --- a/app/Http/Controllers/Api/V1/MicroSoftTeamController.php +++ b/app/Http/Controllers/Api/V1/MicroSoftTeamController.php @@ -19,6 +19,7 @@ use App\Models\Playlist; use App\Models\Project; use App\Models\Activity; +use App\Jobs\PublishProject; use App\User; use Redirect; @@ -201,11 +202,12 @@ public function createMsTeamClass(MSTeamCreateClassRequest $createClassRequest) $authUser = auth()->user(); $token = $authUser->msteam_access_token; $response = json_decode($this->microsoftTeamRepository->createMsTeamClass($token, $data),true); - + if($response['code'] === 202) { return response([ 'message' => 'Class have been created successfully', - 'classId' => $response['classId'] + 'classId' => $response['classId'], + 'aSyncUrl'=> $response['aSyncURL'], ], 200); } @@ -221,11 +223,11 @@ public function createMsTeamClass(MSTeamCreateClassRequest $createClassRequest) * Publish the project activities as an assignment * * @urlParam Project $project required The Id of a project. Example: 9 - * @bodyParam classId required string Id of the class. Example: Test Class + * @bodyParam classId optional string Id of the class. Example: bebe45d4-d0e6-4085-b418-e98a51db70c3 * * @response 200 { * "message": [ - * "Project has been published successfully." + * "Your request to publish project [project->name] into MS Team has been received and is being processed.
You will be alerted in the notification section in the title bar when complete." * ] * } * @@ -234,40 +236,28 @@ public function createMsTeamClass(MSTeamCreateClassRequest $createClassRequest) * "Project must be shared as we are temporarily publishing the shared link." * ] * } - * - * @response 500 { - * "errors": "MS Team error message", - * "statusCode" : MS team status code - * } - * * @param MSTeamCreateAssignmentRequest $createAssignmentRequest * @param Project $project * @return Response */ public function publishProject(MSTeamCreateAssignmentRequest $createAssignmentRequest, Project $project) { - $createAssignmentRequest->validated(); + $data = $createAssignmentRequest->validated(); if(!$project->shared) { // temporary check will remove it in future return response([ 'errors' => 'Project must be shared as we are temporarily publishing the shared link.', ], 500); } - $authUser = auth()->user(); - $token = $authUser->msteam_access_token; - $classId = $createAssignmentRequest->get('classId'); - - $response = json_decode($this->microsoftTeamRepository->createMSTeamAssignment($token, $classId, $project), true); - - if($response['code'] === 201) { - return response([ - 'message' => 'Project has been published successfully.', - ], 200); - } + $classId = isset($data['classId']) ? $data['classId'] : ''; + // pushed publishing of project in background + PublishProject::dispatch(auth()->user(), $project, $classId)->delay(now()->addSecond()); + return response([ - 'errors' => $response['message'], - 'statusCode' => $response['code'] - ], 500); + 'message' => "Your request to publish project [$project->name] into MS Team has been received and is being processed.
+ You will be alerted in the notification section in the title bar when complete.", + ], 200); + } } diff --git a/app/Http/Requests/V1/MSTeamCreateAssignmentRequest.php b/app/Http/Requests/V1/MSTeamCreateAssignmentRequest.php index 40774e7d2..525a4231d 100644 --- a/app/Http/Requests/V1/MSTeamCreateAssignmentRequest.php +++ b/app/Http/Requests/V1/MSTeamCreateAssignmentRequest.php @@ -24,7 +24,8 @@ public function authorize() public function rules() { return [ - 'classId' => 'required|string|max:255' + 'classId' => 'UUID|max:255', + ]; } } diff --git a/app/Jobs/PublishProject.php b/app/Jobs/PublishProject.php new file mode 100644 index 000000000..bf863a72a --- /dev/null +++ b/app/Jobs/PublishProject.php @@ -0,0 +1,77 @@ +user = $user; + $this->project = $project; + $this->classId = $classId; + $this->aSyncUrl = ''; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle(MicrosoftTeamRepositoryInterface $microsoftTeamRepository) + { + try { + if(empty($this->classId)) { + $response = $microsoftTeamRepository->createMsTeamClass($this->user->msteam_access_token, ['displayName'=>$this->project->name]); + \Log::info($response); + $class = json_decode($response, true); + $this->classId = $class['classId']; + $this->aSyncUrl = $class['aSyncURL']; + } + + $microsoftTeamRepository->createMSTeamAssignment($this->user->msteam_access_token, $this->classId, $this->project, $this->aSyncUrl); + $userName = rtrim($this->user->first_name . ' ' . $this->user->last_name, ' '); + + $this->user->notify(new ProjectPublishNotification($userName, $this->project->name)); + } catch (\Exception $e) { + \Log::error($e->getMessage()); + } + } +} diff --git a/app/Notifications/ProjectPublishNotification.php b/app/Notifications/ProjectPublishNotification.php new file mode 100644 index 000000000..0bada50a1 --- /dev/null +++ b/app/Notifications/ProjectPublishNotification.php @@ -0,0 +1,91 @@ +userName = $userName; + $this->projectName = $projectName; + + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return [ 'database']; + } + + /* + * G*et the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toDatabase($notifiable) + { + $message = "Project [$this->projectName] has been published into Microsoft Team successfully."; + + return [ + 'message' => $message, + 'project' => $this->projectName, + + ]; + } + + + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } + + /** + * Return broadcast message type + * @return string + */ + public function broadcastType() + { + return 'Publish Notification'; + } +} diff --git a/app/Repositories/MicrosoftTeam/MicrosoftTeamRepository.php b/app/Repositories/MicrosoftTeam/MicrosoftTeamRepository.php index 63335f8a3..14c93c81b 100644 --- a/app/Repositories/MicrosoftTeam/MicrosoftTeamRepository.php +++ b/app/Repositories/MicrosoftTeam/MicrosoftTeamRepository.php @@ -102,8 +102,9 @@ public function getLoginUrl($gid) */ public function getClassesList($token) { - - $apiURL = $this->landingUrl . 'education/classes'; + $accountId = $this->getUserDetails($token); + + $apiURL = $this->landingUrl . 'users/' . $accountId . '/joinedTeams'; $headers = [ 'Content-length' => 0, 'Content-type' => 'application/json', @@ -114,6 +115,7 @@ public function getClassesList($token) $statusCode = $response->status(); $responseBody = json_decode($response->getBody(), true); + return $responseBody['value']; } @@ -135,10 +137,11 @@ public function createMsTeamClass($token, $data) $response = Http::withHeaders($headers)->withOptions(["verify"=>false])->post($apiURL, $data); $statusCode = $response->status(); - + \Log::info($statusCode); $returnArr = [ "code" => $statusCode, "classId" => ($statusCode === 202) ? $this->fetchClassIdFromHeader($response->getHeaders()) : Null, + "aSyncURL" => ($statusCode === 202) ? $response->getHeaders()['Location'][0] : Null, ]; return json_encode($returnArr); } @@ -147,30 +150,34 @@ public function createMsTeamClass($token, $data) * @param $token string * @param $classId string * @param $project Project + * @param $aSyncUrl string */ - public function createMSTeamAssignment($token, $classId, $project) + public function createMSTeamAssignment($token, $classId, $project, $aSyncUrl) { + \Log::info('in createMSTeamAssignment'); + if(!empty($aSyncUrl)) { + $this->checkClassAsyncStatus($aSyncUrl, $token); // Check if class fully functional + } + $apiURL = $this->landingUrl . 'education/classes/' . $classId . '/assignments'; - + $assignmentDueDays = config('ms-team-configs.assignment_due_days'); + + $headers = [ + 'Content-length' => 0, + 'Content-type' => 'application/json', + 'Authorization' => 'Bearer ' . $token + ]; + + $postInput['dueDateTime'] =date('c', strtotime(date('Y-m-d'). ' + ' . $assignmentDueDays . ' days')); + $playlists = $project->playlists; foreach ($playlists as $playlist) { $activities = $playlist->activities; foreach($activities as $activity) { - $assignmentDueDays = config('ms-team-configs.assignment_due_days'); - // Logic is in progress - $postInput = [ - 'displayName' => $activity->title, - 'dueDateTime' => date('c', strtotime(date('Y-m-d'). ' + ' . $assignmentDueDays . ' days')), // Need to discuss the due date logic currently hardcoded - ]; + $postInput['displayName'] = $activity->title; - $headers = [ - 'Content-length' => 0, - 'Content-type' => 'application/json', - 'Authorization' => 'Bearer ' . $token - ]; - $response = Http::withHeaders($headers)->withOptions(["verify"=>false]) ->retry(3, 6000)->post($apiURL, $postInput); $responseBody = json_decode($response->getBody(), true); @@ -211,6 +218,34 @@ public function createMSTeamAssignment($token, $classId, $project) return json_encode($returnArr); } + /** + * @param string $aSyncUrl + * @param string $token + */ + private function checkClassAsyncStatus($aSyncUrl, $token) + { + \Log::info('in checkClassAsyncStatus'); + if ($aSyncUrl !== Null) { + $apiURL = $this->landingUrl . $aSyncUrl; + $headers = [ + 'Content-length' => 0, + 'Content-type' => 'application/json', + 'Authorization' => 'Bearer ' . $token + ]; + + $response = Http::withHeaders($headers)->get($apiURL); + if ($response->status() === 200) { + $responseBody = json_decode($response->getBody(), true); + if ($responseBody['status'] === "succeeded") { + return $responseBody['status']; + } else { + sleep(30); + $this->checkClassAsyncStatus($aSyncUrl, $token); + } + } + } + } + /** * @param string $header * @return string @@ -220,4 +255,22 @@ private function fetchClassIdFromHeader($header) // Can implement teamsAsyncOperation if needed return substr($header['Content-Location'][0], 8, 36); } + + /** + * @param string $token + */ + private function getUserDetails($token) + { + $apiURL = $this->landingUrl . '/me'; + $headers = [ + 'Content-length' => 0, + 'Content-type' => 'application/json', + 'Authorization' => 'Bearer ' . $token + ]; + + $response = Http::withHeaders($headers)->get($apiURL); + $responseBody = json_decode($response->getBody(), true); + return $responseBody['id']; + } + } diff --git a/app/Repositories/MicrosoftTeam/MicrosoftTeamRepositoryInterface.php b/app/Repositories/MicrosoftTeam/MicrosoftTeamRepositoryInterface.php index 1136c5061..ef0daa6d6 100644 --- a/app/Repositories/MicrosoftTeam/MicrosoftTeamRepositoryInterface.php +++ b/app/Repositories/MicrosoftTeam/MicrosoftTeamRepositoryInterface.php @@ -39,7 +39,8 @@ public function createMsTeamClass($token, $data); /** * @param $token string * @param $classId string - * @param $activity Activity + * @param $project Project + * @param $aSyncUrl string */ - public function createMSTeamAssignment($token, $classId, $activity); + public function createMSTeamAssignment($token, $classId, $project, $aSyncUrl); }