krz/vox-populi

A Tumblr web client.

clone: git clone https://gitbay.org/krz/vox-populi.git

main: profile/index.php · raw

  1<?php
  2    require __DIR__ . '/../vendor/autoload.php';
  3
  4    session_start();
  5
  6    $consumer_key = getenv('CONSUMER_KEY');
  7    $consumer_secret = getenv('CONSUMER_SECRET');
  8    $client = new Tumblr\API\Client($consumer_key, $consumer_secret);
  9    $requestHandler = $client->getRequestHandler();
 10    $requestHandler->setBaseUrl('https://www.tumblr.com/');
 11
 12    // Check if the user has already authenticated
 13    if(isset($_SESSION['perm_token']) && !empty($_SESSION['perm_token']) && isset($_SESSION['perm_secret']) && !empty($_SESSION['perm_secret'])) {
 14        $token = $_SESSION['perm_token'];
 15        $token_secret = $_SESSION['perm_secret'];
 16    }
 17    // Check if the user was here earlier by checking cookies
 18    else if (isset($_COOKIE['perm_token']) && !empty($_COOKIE['perm_token']) && isset($_COOKIE['perm_secret']) && !empty($_COOKIE['perm_secret'])) {
 19        $token = $_COOKIE['perm_token'];
 20        $token_secret = $_COOKIE['perm_secret'];
 21    }
 22    // Check if this is the user's first visit
 23    else if (!isset($_GET['oauth_verifier'])) {
 24
 25        // Grab the oauth token
 26        $resp = $requestHandler->request('POST', 'oauth/request_token', array());
 27        $out = $result = $resp->body;
 28        $data = array();
 29        parse_str($out, $data);
 30
 31        // Save temporary tokens to session
 32        $_SESSION['tmp_token'] = $data['oauth_token'];
 33        $_SESSION['tmp_secret'] = $data['oauth_token_secret'];
 34
 35        // Redirect user to Tumblr auth page
 36        session_regenerate_id(true);
 37        $header_url = 'https://www.tumblr.com/oauth/authorize?oauth_token=' . $data['oauth_token'];
 38        header('Location: ' . $header_url);
 39        die();
 40
 41    }
 42    // Check if the user was just sent back from the Tumblr authentication site
 43    else {
 44
 45        $verifier = $_GET['oauth_verifier'];
 46
 47        // Use the stored temporary tokens
 48        $client->setToken($_SESSION['tmp_token'], $_SESSION['tmp_secret']);
 49
 50        // Access the permanent tokens
 51        $resp = $requestHandler->request('POST', 'oauth/access_token', array('oauth_verifier' => $verifier));
 52        $out = $result = $resp->body;
 53        $data = array();
 54        parse_str($out, $data);
 55
 56        // Set permanent tokens
 57        $token = $data['oauth_token'];
 58        $token_secret = $data['oauth_token_secret'];;
 59        $_SESSION['perm_token'] = $data['oauth_token'];
 60        $_SESSION['perm_secret'] = $data['oauth_token_secret'];
 61
 62        // Set cookies in case the user comes back later
 63        setcookie("perm_token", $_SESSION['perm_token']);
 64        setcookie("perm_secret", $_SESSION['perm_secret']);
 65
 66        // Redirect user to homepage for a clean URL
 67        session_regenerate_id(true);
 68        $header_url = 'https://example.com/vox-populi/';
 69        header('Location: ' . $header_url);
 70        die();
 71
 72    }
 73
 74    // Authenticate via OAuth
 75    $client = new Tumblr\API\Client(
 76        $consumer_key,
 77        $consumer_secret,
 78        $token,
 79        $token_secret
 80    );
 81
 82    // Set up a function to check if variables are blank later (this function accepts 0, 0.0, and "0" as valid)
 83    function not_blank($value) {
 84        return !empty($value) && isset($value) && $value !== '';
 85    }
 86
 87    // Echo HTML contents
 88    echo '<!doctype html><html lang="en"><head>
 89        <meta charset="utf-8">
 90        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 91        <meta http-equiv="x-ua-compatible" content="ie=edge">
 92        <meta name="robots" content="none">
 93        <link rel="apple-touch-icon" sizes="180x180" href="../assets/favicon/apple-touch-icon.png">
 94        <link rel="icon" type="image/png" sizes="32x32" href="../assets/favicon/favicon-32x32.png">
 95        <link rel="icon" type="image/png" sizes="16x16" href="../assets/favicon/favicon-16x16.png">
 96        <link rel="manifest" href="../assets/favicon/site.webmanifest">
 97        <link rel="stylesheet" href="../assets/css/bootstrap-4.5.2.min.css">
 98        <link rel="stylesheet" href="../assets/css/app.css">
 99        <title>Profile | Vox Populi - A Tumblr Web Client</title>
100        <style>
101            @font-face {
102                font-family: "IBM Plex Sans";
103                src: url("../assets/fonts/IBMPlexSans-Regular.eot");
104                src: url("../assets/fonts/IBMPlexSans-Regular.woff2") format("woff2"),
105                    url("../assets/fonts/IBMPlexSans-Regular.woff") format("woff"),
106                    url("../assets/fonts/IBMPlexSans-Regular.ttf") format("truetype");
107            }
108
109            @font-face {
110                font-family: "IBM Plex Sans";
111                src: url("../assets/fonts/IBMPlexSans-Bold.eot");
112                src: url("../assets/fonts/IBMPlexSans-Bold.woff2") format("woff2"),
113                    url("../assets/fonts/IBMPlexSans-Bold.woff") format("woff"),
114                    url("../assets/fonts/IBMPlexSans-Bold.ttf") format("truetype");
115                font-weight: bold;
116            }
117
118            @font-face {
119                font-family: "IBM Plex Mono";
120                src: url("../assets/fonts/IBMPlexMono-Regular.eot");
121                src: url("../assets/fonts/IBMPlexMono-Regular.woff2") format("woff2"),
122                    url("../assets/fonts/IBMPlexMono-Regular.woff") format("woff"),
123                    url("../assets/fonts/IBMPlexMono-Regular.ttf") format("truetype");
124            }
125
126            @font-face {
127                font-family: "IBM Plex Mono";
128                src: url("../assets/fonts/IBMPlexMono-Bold.eot");
129                src: url("../assets/fonts/IBMPlexMono-Bold.woff2") format("woff2"),
130                    url("../assets/fonts/IBMPlexMono-Bold.woff") format("woff"),
131                    url("../assets/fonts/IBMPlexMono-Bold.ttf") format("truetype");
132                font-weight: bold;
133            }
134        </style>
135    </head>
136
137    <body>
138        <div class="banner fixed-top" role="contentinfo">
139            <p class="m-0 mr-2">Black Lives Matter.</p>
140            <a href="https://developer.ibm.com/callforcode/racial-justice/" target="_blank" rel="noopener">Support the Call for Code®</a>
141        </div>
142        <nav class="navbar navbar-expand-lg navbar-dark fixed-top">
143            <li class="nav-item d-block d-md-none">
144                <a id="sidebarButton" class="nav-link" href="javascript:void(0)"><svg id="icon-side-menu"
145                        xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 32 32" aria-hidden="true">
146                        <path
147                            d="M14 4H18V8H14zM4 4H8V8H4zM24 4H28V8H24zM14 14H18V18H14zM4 14H8V18H4zM24 14H28V18H24zM14 24H18V28H14zM4 24H8V28H4zM24 24H28V28H24z">
148                        </path>
149                    </svg></a>
150            </li>
151            <a class="navbar-brand" href="../dashboard/">Vox Populi</a>
152
153            <ul class="navbar-nav mr-0 ml-auto flex-row">
154                <li class="nav-item">
155                    <a id="search-button" class="nav-link" href="javascript:void(0)"><svg id="icon-search"
156                            xmlns="http://www.w3.org/2000/svg" description="Open search" width="20" height="20"
157                            viewBox="0 0 32 32" aria-hidden="true">
158                            <path d="M30,28.59,22.45,21A11,11,0,1,0,21,22.45L28.59,30ZM5,14a9,9,0,1,1,9,9A9,9,0,0,1,5,14Z">
159                            </path>
160                        </svg></a>
161                </li>
162            </ul>
163            <form id="search-form" class="form-inline h-100 d-none flex-fill" method="get"
164                action="../search.php">
165                <input class="form-control h-100 ml-auto" type="search" placeholder="Search" aria-label="Search"
166                    name="query">
167                <a id="search-close-button" class="nav-link" href="javascript:void(0)">
168                    <svg id="icon-search" xmlns="http://www.w3.org/2000/svg" description="Clear search" width="20"
169                        height="20" viewBox="0 0 32 32" aria-hidden="true">
170                        <path
171                            d="M24 9.4L22.6 8 16 14.6 9.4 8 8 9.4 14.6 16 8 22.6 9.4 24 16 17.4 22.6 24 24 22.6 17.4 16 24 9.4z">
172                        </path>
173                    </svg>
174                </a>
175            </form>
176        </nav>
177
178        <div class="container-fluid">
179            <div class="row">
180                <div id="sidebar" class="sidebar d-none d-md-block col-md-3 col-lg-2 p-0">
181                    <div class="sidebar-box p-0">
182                        <div>
183                            <ul class="actions">
184                                <li><p>Account</p></li>
185                                <hr class="sidebar-divider">
186                                <li><a href="../dashboard/">Dashboard</a></li>
187                                <li><a href="../profile/">Profile</a></li>
188                                <li><a href="../logout.php">Logout</a></li>
189                            </ul>
190                            <ul class="categories">
191                                <li><p>Filter</p></li>
192                                <hr class="sidebar-divider">
193                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == '') ? 'active' : ""); echo '" href="./">All Posts</a></li>
194                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'answer') ? 'active' : ""); echo '" href="./?type=answer">Answer</a></li>
195                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'audio') ? 'active' : ""); echo '" href="./?type=audio">Audio</a></li>
196                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'chat') ? 'active' : ""); echo '" href="./?type=chat">Chat</a></li>
197                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'link') ? 'active' : ""); echo '" href="./?type=link">Link</a></li>
198                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'photo') ? 'active' : ""); echo '" href="./?type=photo">Photo</a></li>
199                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'quote') ? 'active' : ""); echo '" href="./?type=quote">Quote</a></li>
200                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'text') ? 'active' : ""); echo '" href="./?type=text">Text</a></li>
201                                <li><a class="'; echo ((isset($_GET['type']) && $_GET['type'] == 'video') ? 'active' : ""); echo '" href="./?type=video">Video</a></li>
202                            </ul>
203                        </div>
204                        <div>
205                            <hr class="sidebar-divider">
206                            <ul class="meta">
207                                <li>
208                                    <a href="#" target="_blank">Source Code <svg
209                                            id="icon-external-link" xmlns="http://www.w3.org/2000/svg" width="16"
210                                            height="16" viewBox="0 0 16 16" aria-hidden="true">
211                                            <path
212                                                d="M13,14H3c-0.6,0-1-0.4-1-1V3c0-0.6,0.4-1,1-1h5v1H3v10h10V8h1v5C14,13.6,13.6,14,13,14z">
213                                            </path>
214                                            <path d="M10 1L10 2 13.3 2 9 6.3 9.7 7 14 2.7 14 6 15 6 15 1z"></path>
215                                        </svg>
216                                    </a>
217                                </li>
218                                <li>
219                                    <a href="https://example.com" target="_blank">&copy; 0000</a>
220                                </li>
221                            </ul>
222                        </div>
223                    </div>
224                </div>
225                <div id="main" class="main col-xs-12 col-md-9 col-lg-10 ml-auto">
226                    <span class="homepage--dots"></span>';
227
228            // Get the user's blog name for welcome message
229            if ($client->getUserInfo()) {
230                $client->getUserInfo();
231            } else {
232                // Echo rate-limit error message
233                $rate_error = '<div id="rate-limit-exceeded" class="alert alert-danger my-5"><b>[429] Error</b>: Tumblr rate limit exceeded. Please visit again tomorrow.</div>';
234                echo $rate_error;
235                die();
236            }
237            foreach ($client->getUserInfo()->user->blogs as $blog) {
238                // Add header to show information about the blog
239                $blog_name = $blog->name;
240                $blog_description = $blog->description;
241                $blog_avatar = $blog->avatar[0]->url;
242                $blog_header_image = $blog->theme->header_image;
243                $blog_total_posts = $blog->total_posts;
244
245                echo '<div class="card blog-header">
246                        <img class="img-fluid blog-header-image" src="' . $blog_header_image . '">
247                        <div class="m-3">
248                            <div class="d-flex flex-row align-items-center">
249                                <img class="img-fluid mr-3 blog-avatar" height="64" width="64" src="' . $blog_avatar . '">
250                                <h1 class="m-0 blog-title">' . $blog_name . '</h1>
251                            </div>
252                            <hr>
253                            <p class="m-0 lead blog-description">' . $blog_description . '</p>
254                        </div>
255                      </div>';
256            }
257
258            // Create function to allow a client to get 20 posts per page
259            function get_blog_posts($client, $blog_identifier, $post_start, $limit, $post_type) {
260                if ($post_type != NULL) {
261                    $blog_posts = $client->getBlogPosts($blog_identifier, array('limit' => $limit, 'offset' => $post_start, 'reblog_info' => true, 'type' => $post_type));
262                } else {
263                    $blog_posts = $client->getBlogPosts($blog_identifier, array('limit' => $limit, 'offset' => $post_start, 'reblog_info' => true));
264                }
265
266                // Add posts to blog stream
267                $card_columns = '<div class="card-columns py-3">';
268                // print_r($blog_posts);
269                foreach ($blog_posts->posts as $post) {
270                    $card_columns .= '<div class="card" data-type="' . $post->type . '" data-id="' . $post->id_string . '">';
271                    $card_columns .= '<div class="card-header d-flex justify-content-between"><div class="card-header-blog"><a href="' . $post->blog->url . '" target="_blank"><img class="avatar" src="' . $client->getBlogAvatar($post->blog_name, 32) . '"></a>';
272                    $card_columns .= '<a href="' . $post->blog->url . '">' . $post->blog_name . '</a>';
273                    if (not_blank($post->reblogged_from_name)) {
274                        $card_columns .= '<i data-feather="repeat"></i><a href="' . $post->reblogged_from_url . '">' . $post->reblogged_from_name . '</a>';
275                        if (!$post->reblogged_from_following) {
276                            $card_columns .= '<a href="javascript:void(0);" onclick="follow(\'' . $post->reblogged_from_name . '\', ' . $post->reblogged_from_uuid . ');" data-follow-id="' . $post->reblogged_from_uuid . '"><span class="badge badge-secondary ml-2">Follow</span></a>';
277                        }
278                    }
279                    $card_columns .= '</div>';
280
281                    // Add 'follow user' button if not following blog
282                    if ($post->followed) {
283                        $card_columns .= '</div>';
284                    } else {
285                        $card_columns .= '<a href="javascript:void(0);" onclick="follow(\'' . $post->blog_name . '\', ' . $post->blog->uuid . ');" title="Follow" data-id="' . $post->blog->uuid . '"><i data-feather="user-plus"></i></a></div>';
286                    }
287
288                    // Add root blog (original poster)
289                    if ($post->reblogged_root_following) {
290                        $card_columns .= '<div class="card-header d-flex justify-content-between"><div class="card-header-blog">';
291                        $card_columns .= '<a href="' . $post->reblogged_root_url . '" target="_blank"><img class="avatar" src="' . $client->getBlogAvatar($post->reblogged_root_name, 32) . '"></a>';
292                        $card_columns .= '<a href="' . $post->reblogged_root_url . '">' . $post->reblogged_root_name . '</a></div>';
293                        $card_columns .= '</div>';
294                    } else {
295                        $card_columns .= '<div class="card-header d-flex justify-content-between"><div class="card-header-blog">';
296                        $card_columns .= '<a href="' . $post->reblogged_root_url . '" target="_blank"><img class="avatar" src="' . $client->getBlogAvatar($post->reblogged_root_name, 32) . '"></a>';
297                        $card_columns .= '<a href="' . $post->reblogged_root_url . '">' . $post->reblogged_root_name . '</a></div>';
298                        if (strpos($post->reblogged_root_name, 'deactivated') == false) {
299                            $card_columns .= '<a href="javascript:void(0);" onclick="follow(\'' . $post->reblogged_root_name . '\');" title="Follow" data-id="' . $post->reblogged_root_uuid . '"><i data-feather="user-plus"></i></a>';
300                        }
301                        $card_columns .= '</div>';
302                    }
303
304                    if ($post->type == 'photo') {
305                        $card_columns .= '<a href="' . $post->photos[0]->original_size->url . '"><img src="' . $post->photos[0]->original_size->url . '" class="card-img" alt="..."></a>';
306                    }
307                    if ($post->type == 'video') {
308                        $card_columns .= '<video controls poster="'.$post->thumbnail_url.'" class="card-img"><source src="'.$post->video_url.'"></source></video>';
309                    }
310                    $card_columns .= '<div class="card-body">';
311                    if ($post->type == 'photo') {
312                        if (not_blank($post->caption)) {
313                            $card_columns .= '<p class="card-text post-caption">' . $post->caption . '</p>';
314                        }
315                    }
316                    if ($post->type == 'text') {
317                        if (not_blank($post->title)) {
318                            $card_columns .= '<h5 class="card-title post-title">' . $post->title . '</h5>';
319                        }
320                        if (not_blank($post->body)) {
321                            $card_columns .= '<p class="card-text post-body">' . $post->body . '</p>';
322                        }
323                    }
324                    if ($post->type == 'answer') {
325                        $card_columns .= '<p class="card-text"><b>' . $post->asking_name . '</b>: ' . $post->question . '</p>';
326                        $card_columns .= '<hr>';
327                        $card_columns .= $post->answer;
328                    }
329                    if ($post->type == 'quote') {
330                        $card_columns .= '<blockquote class="card-text post-quote">' . $post->summary;
331                        $card_columns .= '<br><br><cite>' . $post->reblog->comment . '</cite></blockquote>';
332                    }
333                    if ($post->type == 'chat') {
334                        for ($i = 0; $i <= count($post->dialogue); $i++) {
335                            $card_columns .= '<blockquote class="card-text post-chat-' . $i . '">' . (not_blank($post->dialogue[$i]->name) ? ('<b>' . $post->dialogue[$i]->name . '</b>: ') : "") . $post->dialogue[$i]->phrase . '</blockquote>';
336                        }
337                    }
338                    // $card_columns .= '<a href="' . $post->post_url . '" class="card-link">Visit Post &rarr;</a>';
339                    $card_columns .= '<div class="card-footer d-flex justify-content-between align-items-center p-0"><div class="note-count">' . number_format($post->note_count, 0) . ' notes</div>';
340                    $card_columns .= '<div class="post-icons"><a href="' . $post->post_url . '" target="_blank" title="View on Tumblr"><i data-feather="external-link"></i></a>';
341                    $card_columns .= '<a href="#" title="Share"><i data-feather="send"></i></a>';
342                    $card_columns .= '<a href="#" title="Comment"><i data-feather="message-square"></i></a>';
343                    $card_columns .= '<a href="#" title="Reblog"><i data-feather="repeat"></i></a>';
344
345                    if ($post->liked != true) {
346                        // Like this post
347                        $card_columns .= '<a href="javascript:void(0);" onclick="like(\'' . urlencode($post->id) . '\', \'' . urlencode($post->reblog_key) . '\');" title="Like" data-like-id="' . $post->id . '"><i data-feather="heart"></i></a></div></div>';
348                    } else {
349                        // Unlike this post
350                        $card_columns .= '<a href="javascript:void(0);" onclick="unlike(\'' . urlencode($post->id) . '\', \'' . urlencode($post->reblog_key) . '\');" title="Unlike" data-unlike-id="' . $post->id . '"><i data-feather="heart"></i></a></div></div>';
351                    }
352
353                    $card_columns .= '</div></div>';
354                }
355                $card_columns .= '</div>';
356                return $card_columns;
357            }
358
359            // Create a loop to call as many blog posts as you want (results are returned in sets of 20 per API rules)
360            // Can specify post type: text, chat, link, photo, audio, video, NULL
361            if (isset($_GET['type'])) {
362                $post_type = $_GET['type'];
363            } else {
364                $post_type = NULL;
365            }
366            if (isset($_GET['page'])) {
367                $page = $_GET['page'];
368            } else {
369                $page = 1;
370            }
371            $post_start = (($page - 1) * 20) + 1;
372            $limit = 20;
373            $blog_identifier = $blog_name . '.tumblr.com';
374            echo get_blog_posts($client, $blog_identifier, $post_start, $limit, $post_type);
375
376            // Echo HTML page navigation
377            // Embedded PHP tags here are calculating page numbers for URL parameters
378            echo '<nav aria-label="Page navigation">
379            <ul class="pagination justify-content-center">
380                <li class="page-item '; echo ($page <= 1 ? "disabled" : ""); echo'">
381                    <a class="page-link" href="./?page='; echo ($page-1); echo (isset($_GET['type']) ? "&type=" . $_GET['type'] : ""); echo '" aria-label="Previous">
382                        <span aria-hidden="true">&laquo;</span>
383                    </a>
384                </li>
385                <li class="page-item '; echo ($page <= 1 ? "disabled" : "");  echo '"><a class="page-link"
386                        href="./?page='; echo ($page-1); echo (isset($_GET['type']) ? "&type=" . $_GET['type'] : ""); echo '">'; echo ($page-1); echo '</a></li>
387                <li class="page-item active"><a class="page-link" href="#">'; echo $page; echo '</a></li>
388                <li class="page-item"><a class="page-link"
389                        href="./?page='; echo ($page+1); echo (isset($_GET['type']) ? "&type=" . $_GET['type'] : ""); echo '">'; echo ($page+1); echo '</a></li>
390                <li class="page-item">
391                    <a class="page-link" href="./?page='; echo ($page+1); echo (isset($_GET['type']) ? "&type=" . $_GET['type'] : ""); echo'" aria-label="Next">
392                        <span aria-hidden="true">&raquo;</span>
393                    </a>
394                </li>
395            </ul>
396        </nav>
397    </div>
398
399    </div>
400    </div>
401    <button class="btn-to-top" type="button" aria-label="Back to Top">
402        <svg id="icon-to-top" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 32 32"
403            aria-hidden="true">
404            <path d="M16 14L6 24 7.4 25.4 16 16.8 24.6 25.4 26 24zM4 8H28V10H4z"></path>
405        </svg>
406    </button>
407
408    <!-- JavaScript -->
409    <script src="../assets/js/feather-icons.4.2.8.min.js"></script>
410    <script src="../assets/js/jquery-3.5.1.min.js"></script>
411    <script src="../assets/js/bootstrap.bundle.min.js"></script>
412    <script src="../assets/js/app.js"></script>
413</body></html>';
414?>