<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thomas Harris</title>
    <description>The latest articles on DEV Community by Thomas Harris (@lodenh16).</description>
    <link>https://dev.to/lodenh16</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F795870%2F3b3c3550-a78e-412e-a2c3-80efb0c75695.JPG</url>
      <title>DEV Community: Thomas Harris</title>
      <link>https://dev.to/lodenh16</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lodenh16"/>
    <language>en</language>
    <item>
      <title>Acquiring the Auth Code</title>
      <dc:creator>Thomas Harris</dc:creator>
      <pubDate>Wed, 11 May 2022 20:50:10 +0000</pubDate>
      <link>https://dev.to/lodenh16/acquiring-the-auth-code-2b9o</link>
      <guid>https://dev.to/lodenh16/acquiring-the-auth-code-2b9o</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm building this project with &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt; and &lt;a href="https://firebase.google.com/docs/web/setup" rel="noopener noreferrer"&gt;Google Firebase&lt;/a&gt;. If you're following along, follow these getting started guides first, as well as create a &lt;a href="https://developer.spotify.com/dashboard/login" rel="noopener noreferrer"&gt;Spotify Application&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OAuth anyway
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;u&gt;&lt;em&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc6749" rel="noopener noreferrer"&gt;-Internet Engineering Task Force&lt;/a&gt;&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;First, let's go over the basics of the OAuth 2.0 flow because that's what took me the longest to understand.&lt;/p&gt;

&lt;p&gt;There are many different approaches to OAuth called &lt;code&gt;Grant Types&lt;/code&gt;. You can read more about Grant Types &lt;a href="https://oauth.net/2/grant-types/" rel="noopener noreferrer"&gt;here.&lt;/a&gt; I chose the &lt;code&gt;Authorization Code&lt;/code&gt; so users only have to grant access to their Spotify account once.&lt;/p&gt;

&lt;p&gt;Think of it like a bartender trying to serve a patron a drink. Before the bartender serves them, they have to make sure they're old enough to have permission to serve them. They do that by checking the ID issued to the patron by a governing authority. The patron has to prove to the authorities that they are old enough to drink, then present that proof to a bartender to be served. Our User has to prove to Spotify that they are who they say they are and the &lt;code&gt;Auth Code&lt;/code&gt; is proof of that. They then present that proof to our server so we can make API calls on their behalf.&lt;/p&gt;

&lt;p&gt;If that doesn't make any sense, maybe this flow chart will.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs871i5qmu8dur66ypmfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs871i5qmu8dur66ypmfc.png" alt="Graphic Explanation of Authorization Code OAuth grant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, everything revolves around the &lt;code&gt;Auth Code&lt;/code&gt;, a special string the user receives after logging into Spotify. We later use this &lt;code&gt;Auth Code&lt;/code&gt; to verify with Spotify that the User has permitted us to access their account.&lt;/p&gt;

&lt;p&gt;So our first step in getting this &lt;code&gt;Auth Code&lt;/code&gt; is to ask the user to sign in. We do this by generating a special URL that redirects the user to Spotify's website to log in.&lt;/p&gt;
&lt;h2&gt;
  
  
  Crafting the URL
&lt;/h2&gt;

&lt;p&gt;When we prompt the user to log in with Spotify, we have to send them to a specific URL for them to do so. I'm building this project with React so I built a component that does specifically this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as React from "react";
import { useRouter } from "next/router";
import { v4 as uuidv4 } from "uuid";
import * as queryString from "query-string";

const SpotifyLoginButton = () =&amp;gt; {
  const router = useRouter();

  const spotifyQueryParams = {
    response_type: "code",
    client_id: process.env.NEXT_PUBLIC_SPOTIFY_CLIENT_ID,
    scope: "playlist-read-private playlist-modify-private user-read-email",
    redirect_uri: process.env.NEXT_PUBLIC_REDIRECT_URI,
    state: uuidv4(),
  };
  const spotifyOAuthRoute =
    "https://accounts.spotify.com/authorize?" +
    queryString.stringify(spotifyQueryParams);

  const handleClick = (e) =&amp;gt; {
    e.preventDefault();
    router.push(spotifyOAuthRoute);
  };

  return &amp;lt;button onClick={handleClick}&amp;gt;Login with Spotify&amp;lt;/button&amp;gt;;
};

export default SpotifyLoginButton;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay special attention to the &lt;code&gt;spotifyQueryParams&lt;/code&gt;. These values are how we generate the special URL. You can learn more &lt;a href="https://developer.spotify.com/documentation/general/guides/authorization/code-flow/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but I'll go over what each value means.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;response_type:&lt;/code&gt; indicates we want an Auth Code returned to the user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;client_id:&lt;/code&gt; is the ID of our &lt;a href="https://developer.spotify.com/dashboard/" rel="noopener noreferrer"&gt;Spotify Application&lt;/a&gt;, this is required for Spotify to register our server before accessing their API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;scope:&lt;/code&gt; indicates the specific permissions we need the user to grant us, &lt;a href="https://developer.spotify.com/documentation/general/guides/authorization/scopes/" rel="noopener noreferrer"&gt;read more&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;redirect_uri:&lt;/code&gt; is the URL Spotify send the user back to with the Auth Code. This value must be set in the settings of your Spotify Application, I'm using local host now for development&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;state:&lt;/code&gt; this helps prevent attacks like cross-site request forgery&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After setting those values our User is ready to log in! I'm using &lt;a href="https://www.npmjs.com/package/query-string" rel="noopener noreferrer"&gt;query-string&lt;/a&gt; to stringify the URL. Notice the URL starts with &lt;code&gt;https://accounts.spotify.com/authorize?&lt;/code&gt;. The next part of the process happens on Spotify's servers, our site never sees the user's username or password. Our site only sees the &lt;code&gt;Auth Code&lt;/code&gt; for now.&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;useRouter()&lt;/code&gt; to push the user to our login URL. I used a Button and function instead of an Anchor element because I wanted the user to know they're taking an action, not just following a link. Next, the user will see a screen like this,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoziv3jdpctg16ah8dmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoziv3jdpctg16ah8dmg.png" alt="The Spotify login page prompting the user to grant us permissions on their account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the User agrees to grant us permission, they'll be returned to the &lt;code&gt;redirect_uri&lt;/code&gt; we specified with their Auth Code in the URL. Finally, we have the fabled Auth Code!&lt;/p&gt;

&lt;p&gt;Now, what do we do with it? In my next post, I'll be detailing what we do with the &lt;code&gt;auth code&lt;/code&gt; and the part it plays in our project.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>firebase</category>
      <category>spotify</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I turned GitHub into my own Billboard</title>
      <dc:creator>Thomas Harris</dc:creator>
      <pubDate>Tue, 18 Jan 2022 03:43:10 +0000</pubDate>
      <link>https://dev.to/lodenh16/i-turned-github-into-my-own-billboard-3m10</link>
      <guid>https://dev.to/lodenh16/i-turned-github-into-my-own-billboard-3m10</guid>
      <description>&lt;p&gt;The day I made my GitHub account, I immediately realized the possibilities of the Commit Heatmap being a colorful grid. I wanted to show some personality, like a smiley face or a friendly greeting, welcoming potential employers to my page. Unfortunately, Git had other ideas, and soon my Heatmap looked more like toxic sludge than a welcome mat.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FcHSliSO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgcylm2ue4p3fnk16szi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FcHSliSO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgcylm2ue4p3fnk16szi.png" alt="my messy commit history" width="421" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No matter, I have the power of Inspect Element! I'll just manually adjust each cell. After about 10 minutes into this plan, I had restarted 3 times without completing a single letter. It was clear human input is not reliable enough to complete this task. Good thing I know JavaScript and have several hours to burn!&lt;/p&gt;

&lt;p&gt;The first step on this project was to redefine the alphabet. The GitHub commit history is just a grid, so I needed an alphabet that can fit in a grid. Credit to @hgcummings on GitHub for &lt;a href="https://github.com/hgcummings/pixel-fonts"&gt;this library&lt;/a&gt;. It's exactly what I needed, so I copied and pasted the object into my project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qI77FBoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02dokedoylmznixleoig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qI77FBoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02dokedoylmznixleoig.png" alt="hgcumming's font structure" width="133" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I was trying to manually change each cell, I got well acquainted with the commit history HTML. The grid is made of 52 groups with 7 &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&gt; elements each. Each cell has a &lt;code&gt;"data-level"&lt;/code&gt; attribute between 0 and 4, this determines what shade of green the cell is.&lt;/p&gt;

&lt;p&gt;Immediately I noticed a problem. The commit history is grouped vertically, by weeks. But, my font object is sorted horizontally. If I carried on from here my message would come out sideways! I spent a few minutes thinking about how to proceed, how could I reorganize the arrays into the structure I needed? In the end, I decided it was best to just rewrite the data by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W64Z8Xtb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izuocns31g4yetbfcitw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W64Z8Xtb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izuocns31g4yetbfcitw.png" alt="my font data structure" width="572" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it certainly would be possible to write a sorting algorithm, I think this choice saved me time in the long run. It also gave me the minor performance boost of shipping and running less code. I also noticed many letters of the alphabet have straight vertical lines (26 lines to be exact). Instead of writing &lt;code&gt;[1,1,1,1,1]&lt;/code&gt; several times, I opted to define it as a variable to be reused. This saved me a small amount of time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let message = prompt("What do you want to say?", "")

message
 .toUpperCase()
 .split("")
 .map((character) =&amp;gt; Letters[character])

//this prompts the user for an input
//then turns that input into an array of pixels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I finally had all the pieces I needed. All that's left to do is plug the user's input into the commit history's grid. This task is easier said than done. The commit history is an array of arrays of cells, and the user message is an array of arrays of pixels. It seems simple in theory, but connecting the right cell with the right pixel is a bit complicated.&lt;/p&gt;

&lt;p&gt;My first idea was to access each cell by its &lt;code&gt;"data-date"&lt;/code&gt; attribute. This solution is probably the simplest, but ultimately flawed. The commit history changes each week when a new row is added, eventually, the cell I was accessing would no longer exist. Making the text scroll would be incredibly complicated, computing which cell is where in the grid and how many days are between adjacent cells. This solution quickly was abandoned.&lt;/p&gt;

&lt;p&gt;To solve this, I had to think of programming in the most basic terms. What I like to think all programming is at its core is Data Manipulation. HTML is just data, and JavaScript is just a way to manipulate data. With this mindset, I could make a plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LZyzLNFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9yjkhhyudemkgnf0ahym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LZyzLNFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9yjkhhyudemkgnf0ahym.png" alt="a visualization of the commit history's data structure compared to the pixelated message's data structure" width="880" height="1091"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visualizing the data like this helps me to conceptualize how to connect it. In this format you can clearly see how each grid cell has a corresponding pixel value derived from the user message. After understanding the data structure, all that's left is writing the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const writeToBillboard = (message, rowIndex) =&amp;gt; 
  clearBoard();
  let currentWeek = rowIndex;
  message
    .toUpperCase()
    .split("")
    .map((character) =&amp;gt; Letters[character])
    .map((pixelLetter, index) =&amp;gt; {
      pixelLetter.map((pixelLine, index) =&amp;gt; {
        let week = weeks[currentWeek];
        pixelLine.map((pixel, index) =&amp;gt; {
          if (currentWeek &amp;gt;= 0 &amp;amp;&amp;amp; currentWeek &amp;lt; 53) {
            if (Array.from(week.children)[index + 1]) {
              Array.from(week.children)[index + 1].setAttribute(
                "data-level",
                pixel ? "4" : "0"
              );
            }
          }
        });
        //move to next row
        currentWeek += 1;
      });
      //skip a line after a letter is complete
      currentWeek += 1;
    });
};{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we convert the user input string into an array of pixels. Next, we access each pixel letter, then each pixel line. Then we define the &lt;code&gt;week&lt;/code&gt; as the current row of cells we're accessing. After that, we access each cell, and we're ready to overwrite the data! We do a couple of checks to make sure we're on a row that exists and a cell that exists (otherwise it throws about 30 errors per second), then we set the cell's &lt;code&gt;data-level&lt;/code&gt; attribute to a 4 or 0, depending on the pixel's value. Finally! We've put a message on our commit history!&lt;/p&gt;

&lt;p&gt;The hard part is over, but it's not quite ready to push yet. We still need to make it scroll. This is simpler than it sounds. With &lt;code&gt;setInterval()&lt;/code&gt; we can call &lt;code&gt;writeToBillboard()&lt;/code&gt; every 100ms, and increment the &lt;code&gt;rowIndex&lt;/code&gt; down one each time. This writes the message one row to the left ten times per second, giving the illusion of a moving image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const scrollWrite = () =&amp;gt; 
  let rowIndex = 53;
  let interval = setInterval(() =&amp;gt; {
      writeToBillboard(message, rowIndex)
    //check if rowIndex has extended far enough for all
    //characters
    rowIndex &amp;lt; 0 - message.split("").length * 4
      ? //if true: reset
        (rowIndex = 53)
      : //if false: keep going
        (rowIndex -= 1);
  }, 100);
};{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define &lt;code&gt;rowIndex&lt;/code&gt; as 53 to start at the row furthest to the right. We call &lt;code&gt;writeToBillboard()&lt;/code&gt;, passing in the message and &lt;code&gt;rowIndex&lt;/code&gt; as arguments. After the message is written, we check if all characters have passed the left side of the grid. Each character takes 4 rows to write, including the gap between characters. So by subtracting the number of characters multiplied by 4, we know what &lt;code&gt;rowIndex&lt;/code&gt; will be far enough to have passed all characters. If &lt;code&gt;rowindex&lt;/code&gt; has passed this number, we reset &lt;code&gt;rowIndex&lt;/code&gt; to 53, if not we subtract one so the message moves a little bit to the left.&lt;/p&gt;

&lt;p&gt;The final step in the process is to turn our code into a Chrome Extension. Chrome extensions require a &lt;code&gt;manifest.json&lt;/code&gt; to define the properties of the code and let Chrome know what to do with it. We have to name the extension, version it, and give it a description. In &lt;code&gt;"content_scripts"&lt;/code&gt;, we tell the extension to run content.js when on any github.com page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "manifest_version": 3,


  "name": "GitHub Billboard",
  "version": "1.0.0",
  "description": "Turn your GitHub commits into a marquee billboard",
  "icons": {
    "32": "icon32.png",
    "128": "icon128.png"
  },


  "content_scripts": [
    {
      "js": ["content.js"],
      "matches": ["https://github.com/*"]
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, we're ready to push our code, you can check it out &lt;a href="https://github.com/LodenH16/GitHub-Billboard"&gt;here&lt;/a&gt;. This project was a lot of fun to work on and I was amazed at the power and simplicity of Chrome Extensions. I was impressed by how quickly I was able to get up and running with a custom extension. I'll be making more in the future!&lt;/p&gt;

</description>
      <category>github</category>
      <category>chromeextension</category>
      <category>javascript</category>
      <category>100daysofcode</category>
    </item>
  </channel>
</rss>
