| @ -0,0 +1,2 @@ | |||||
| local: .env.local | |||||
| prod: .env.prod | |||||
| @ -0,0 +1,7 @@ | |||||
| <?php | |||||
| return [ | |||||
| '*' => [ // Applies to all | |||||
| 'APP_ENV' => 'local', | |||||
| ], | |||||
| ]; | |||||
| @ -0,0 +1,71 @@ | |||||
| <?php | |||||
| namespace App\Http\Controllers; | |||||
| use Google\ApiCore\ApiException; | |||||
| use Google\Photos\Library\V1\PhotosLibraryClient; | |||||
| use Illuminate\Http\Request; | |||||
| class GooglePhotoController extends Controller { | |||||
| public function connect(Request $request) | |||||
| { | |||||
| connectWithGooglePhotos($request, | |||||
| ['https://www.googleapis.com/auth/photoslibrary'], | |||||
| config('app.albums_authentication_redirect_url') | |||||
| ); | |||||
| } | |||||
| public function index() | |||||
| { | |||||
| $credentials = session("credentials"); | |||||
| if ($credentials == null || $credentials == "") { | |||||
| return view("albums/connect"); | |||||
| } | |||||
| $photosLibraryClient = new PhotosLibraryClient(['credentials' => $credentials]); | |||||
| try { | |||||
| // $options['proxy'] = 'http://127.0.0.1:1087'; | |||||
| // $pagedResponse = $photosLibraryClient->listAlbums(); | |||||
| // $options['pageSize'] = 5; | |||||
| $pagedResponse = $photosLibraryClient->listMediaItems(); | |||||
| // echo 111; | |||||
| // var_dump($pagedResponse->iterateAllElements());exit; | |||||
| $iterator = $pagedResponse->iterateAllElements(); | |||||
| $albums = []; | |||||
| $yccImages = []; | |||||
| while (true) { | |||||
| for ($i = 0; $i < 100; $i++) { | |||||
| $album = $iterator->current(); | |||||
| if (strstr($album->getFilename(), "ycc")) { | |||||
| $yccImages[] = $album->getId(); | |||||
| } | |||||
| $iterator->next(); | |||||
| } | |||||
| if (count($yccImages) > 1) { | |||||
| $photosLibraryClient->batchAddMediaItemsToAlbum("AN5jk26M4hJ-wxLPKSzIDyjruMMkWjlDlVkgNaWWk3d3c7TGhm1vKU-YM0JhfgK5CfcfneoIx_8E", $yccImages); | |||||
| echo "add " . count($yccImages) . " images to ycc\n"; | |||||
| $yccImages = []; | |||||
| } | |||||
| break; | |||||
| } | |||||
| //// echo $album->getProductUrl(); | |||||
| // $albums[] = $album; | |||||
| // $iterator->next(); | |||||
| // } | |||||
| // exit; | |||||
| // By using iterateAllElements, pagination is handled for us. | |||||
| return view("albums.index", ['albums' => $pagedResponse->iterateAllElements()]); | |||||
| // echo $templates->render( | |||||
| // 'albums::index', | |||||
| // ['albums' => $pagedResponse->iterateAllElements()]); | |||||
| // echo $templates->render( | |||||
| // 'albums::index', | |||||
| // ['mediaItems' => $albums] | |||||
| // ); | |||||
| // ); | |||||
| } catch (ApiException $e) { | |||||
| // echo $templates->render('error', ['exception' => $e]); | |||||
| view("error"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,66 @@ | |||||
| <?php | |||||
| use Google\Auth\Credentials\UserRefreshCredentials; | |||||
| use Google\Auth\HttpHandler\Guzzle7HttpHandler; | |||||
| use Google\Auth\OAuth2; | |||||
| use GuzzleHttp\Client; | |||||
| function connectWithGooglePhotos($request, array $scopes, $redirectURI) | |||||
| { | |||||
| $clientSecretJson = json_decode( | |||||
| file_get_contents('client_secret_1000190146810-j9mohjt8m4m8j8sj6hupl1bghp6o1pdn.apps.googleusercontent.com.json'), | |||||
| true | |||||
| )['web']; | |||||
| // dump($clientSecretJson);exit; | |||||
| $clientId = $clientSecretJson['client_id']; | |||||
| $clientSecret = $clientSecretJson['client_secret']; | |||||
| $oauth2 = new OAuth2([ | |||||
| 'clientId' => $clientId, | |||||
| 'clientSecret' => $clientSecret, | |||||
| 'authorizationUri' => 'https://accounts.google.com/o/oauth2/v2/auth', | |||||
| // Where to return the user to if they accept your request to access their account. | |||||
| // You must authorize this URI in the Google API Console. | |||||
| 'redirectUri' => $redirectURI, | |||||
| 'tokenCredentialUri' => 'https://www.googleapis.com/oauth2/v4/token', | |||||
| 'scope' => $scopes, | |||||
| 'expiry' => \Google\Auth\OAuth2::DEFAULT_EXPIRY_SECONDS *24 | |||||
| ]); | |||||
| $client = new Client(['proxy' => 'http://127.0.0.1:1087']); | |||||
| $httpHandler = new Guzzle7HttpHandler($client); | |||||
| // The authorization URI will, upon redirecting, return a parameter called code. | |||||
| $code = $request->get('code'); | |||||
| if ($code == null || $code == "") { | |||||
| $authenticationUrl = $oauth2->buildFullAuthorizationUri(['access_type' => 'offline']); | |||||
| // dump($authenticationUrl); | |||||
| // redirect($authenticationUrl); | |||||
| header("Location: " . $authenticationUrl); | |||||
| // redirect()->to($authenticationUrl); | |||||
| } else { | |||||
| dump("code is " . $code); | |||||
| // With the code returned by the OAuth flow, we can retrieve the refresh token. | |||||
| $oauth2->setCode($code); | |||||
| $authToken = $oauth2->fetchAuthToken(); | |||||
| $refreshToken = $authToken['access_token']; | |||||
| // The UserRefreshCredentials will use the refresh token to 'refresh' the credentials when | |||||
| // they expire. | |||||
| $credentials = new UserRefreshCredentials( | |||||
| $scopes, | |||||
| [ | |||||
| 'client_id' => $clientId, | |||||
| 'client_secret' => $clientSecret, | |||||
| 'refresh_token' => $refreshToken | |||||
| ] | |||||
| ); | |||||
| session(['credentials' => $credentials]); | |||||
| // Return the user to the home page. | |||||
| dump("before redirect"); | |||||
| redirect('google/home/index'); | |||||
| // header("Location: index.php"); | |||||
| } | |||||
| } | |||||
| @ -0,0 +1 @@ | |||||
| {"web":{"client_id":"1000190146810-j9mohjt8m4m8j8sj6hupl1bghp6o1pdn.apps.googleusercontent.com","project_id":"photo1-1584853697553","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"oSPGIFy-Z_z92IG9iT03Dhor","redirect_uris":["http://localhost:8080/oauth2callback","http://localhost:1234/albums/connect.php","http://localhost:1234/filters/connect.php","https://ins.app/google/photo/connect"]}} | |||||
| @ -0,0 +1 @@ | |||||
| {"web":{"client_id":"1000190146810-j9mohjt8m4m8j8sj6hupl1bghp6o1pdn.apps.googleusercontent.com","project_id":"photo1-1584853697553","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"oSPGIFy-Z_z92IG9iT03Dhor","redirect_uris":["http://localhost:8080/oauth2callback","http://localhost:1234/albums/connect.php","http://localhost:1234/filters/connect.php","https://ins.app/google/photo/connect"]}} | |||||
| @ -0,0 +1 @@ | |||||
| {"web":{"client_id":"1000190146810-j9mohjt8m4m8j8sj6hupl1bghp6o1pdn.apps.googleusercontent.com","project_id":"photo1-1584853697553","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"oSPGIFy-Z_z92IG9iT03Dhor","redirect_uris":["http://localhost:8080/oauth2callback","http://localhost:1234/albums/connect.php","http://localhost:1234/filters/connect.php","https://ins.app/google/photo/connect","http://localhost:1234/google/photo/connect"]}} | |||||
| @ -0,0 +1,4 @@ | |||||
| { | |||||
| "/js/app.js": "/js/app.js", | |||||
| "/css/app.css": "/css/app.css" | |||||
| } | |||||
| @ -1,33 +1,16 @@ | |||||
| /** | /** | ||||
| * First we will load all of this project's JavaScript dependencies which | * First we will load all of this project's JavaScript dependencies which | ||||
| * includes Vue and other libraries. It is a great starting point when | |||||
| * building robust, powerful web applications using Vue and Laravel. | |||||
| * includes React and other helpers. It's a great starting point while | |||||
| * building robust, powerful web applications using React + Laravel. | |||||
| */ | */ | ||||
| require('./bootstrap'); | require('./bootstrap'); | ||||
| window.Vue = require('vue'); | |||||
| /** | |||||
| * The following block of code may be used to automatically register your | |||||
| * Vue components. It will recursively scan this directory for the Vue | |||||
| * components and automatically register them with their "basename". | |||||
| * | |||||
| * Eg. ./components/ExampleComponent.vue -> <example-component></example-component> | |||||
| */ | |||||
| // const files = require.context('./', true, /\.vue$/i) | |||||
| // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)) | |||||
| Vue.component('example-component', require('./components/ExampleComponent.vue').default); | |||||
| /** | /** | ||||
| * Next, we will create a fresh Vue application instance and attach it to | |||||
| * Next, we will create a fresh React component instance and attach it to | |||||
| * the page. Then, you may begin adding components to this application | * the page. Then, you may begin adding components to this application | ||||
| * or customize the JavaScript scaffolding to fit your unique needs. | * or customize the JavaScript scaffolding to fit your unique needs. | ||||
| */ | */ | ||||
| const app = new Vue({ | |||||
| el: '#app' | |||||
| }); | |||||
| require('./components/Example'); | |||||
| @ -0,0 +1,26 @@ | |||||
| import React, { Component } from 'react'; | |||||
| import ReactDOM from 'react-dom'; | |||||
| export default class Example extends Component { | |||||
| render() { | |||||
| return ( | |||||
| <div className="container"> | |||||
| <div className="row justify-content-center"> | |||||
| <div className="col-md-8"> | |||||
| <div className="card"> | |||||
| <div className="card-header">Example Component</div> | |||||
| <div className="card-body"> | |||||
| I'm an example component! | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| if (document.getElementById('example')) { | |||||
| ReactDOM.render(<Example />, document.getElementById('example')); | |||||
| } | |||||
| @ -1,23 +0,0 @@ | |||||
| <template> | |||||
| <div class="container"> | |||||
| <div class="row justify-content-center"> | |||||
| <div class="col-md-8"> | |||||
| <div class="card card-default"> | |||||
| <div class="card-header">Example Component</div> | |||||
| <div class="card-body"> | |||||
| I'm an example component. | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| mounted() { | |||||
| console.log('Component mounted.') | |||||
| } | |||||
| } | |||||
| </script> | |||||
| @ -0,0 +1,36 @@ | |||||
| <?php | |||||
| /** | |||||
| * Copyright 2018 Google LLC | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * https://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| */ | |||||
| //$this->layout('template', ['title' => 'Connect with Google Photos']) | |||||
| ?> | |||||
| <div id="intro"> | |||||
| <h4>Google Photos Library API sample</h4> | |||||
| <img src="http://www.baidu.com" alt=""> | |||||
| <h2>Title</h2> | |||||
| <p>This sample will cover</p> | |||||
| <ul> | |||||
| <li>Connecting to a Google Photos Library</li> | |||||
| <li>Requesting scopes from a Google Photos user</li> | |||||
| <li>Read the entire library</li> | |||||
| <li>Apply filters to a library</li> | |||||
| </ul> | |||||
| <a class="connect-btn" href="/google/photo/connect"> | |||||
| <img src="../common/google_photos_logo.png"> | |||||
| Connect to Google Photos | |||||
| </a> | |||||
| </div> | |||||
| @ -0,0 +1,62 @@ | |||||
| <?php | |||||
| /** | |||||
| * Copyright 2018 Google LLC | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * https://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License. | |||||
| */ | |||||
| //$this->layout('template', ['title' => 'Photos Library API PHP Sample', 'additionalStylesheets' => ['views/style.css']]) | |||||
| <dialog class="mdl-dialog"> | |||||
| <h4 class="mdl-dialog__title">Create a new album</h4> | |||||
| <form action="album.php"> | |||||
| <div class="mdl-dialog__content"> | |||||
| <div class="mdl-textfield mdl-js-textfield"> | |||||
| <input type="text" class="mdl-textfield__input" name="create" id="create"/> | |||||
| <label for="create" class="mdl-textfield__label">Title</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="mdl-dialog__actions"> | |||||
| <button class="mdl-button">Create</button> | |||||
| <a class="mdl-button close">Cancel</a> | |||||
| </div> | |||||
| </form> | |||||
| </dialog> | |||||
| <div class="mdl-grid"> | |||||
| <div class="mdl-cell mdl-cell--12-col description"> | |||||
| <h3>This is your Google Photos library</h3> | |||||
| <p>You've used the <span class="code">photoslibrary</span> scope to view the albums in the | |||||
| user's library.</p> | |||||
| <p>Use the create action to add a new album.</p> | |||||
| <button id='create-btn' class="mdl-button mdl-button--raised mdl-button--colored">Create</button> | |||||
| </div> | |||||
| <?php $this->insert('album_grid', ['albums' => $albums, 'photoLink' => 'album.php']);?> | |||||
| <!-- --><?php //$this->insert('image_grid', ['mediaItems' => $mediaItems]); ?> | |||||
| </div> | |||||
| <script> | |||||
| var dialog = document.querySelector('dialog'); | |||||
| var showModalButton = document.querySelector('#create-btn'); | |||||
| showModalButton.addEventListener('click', function() { | |||||
| dialog.showModal(); | |||||
| }); | |||||
| dialog.querySelector('.close').addEventListener('click', function() { | |||||
| dialog.close(); | |||||
| }); | |||||
| </script> | |||||