<![CDATA[OhMyBrew!]]>https://ohmybrew.com/https://ohmybrew.com/favicon.pngOhMyBrew!https://ohmybrew.com/Ghost 2.10Thu, 14 Nov 2019 20:50:26 GMT60<![CDATA[When "Quick'n'Dirty" Becomes Permanent]]>The Start

You're assigned a backend project to kick-off and setup, great! You know the requirements and goals, so you set off to build the structure and prototype "quick and dirty" code as a proof-of-concept implementation.

Before you know it... you've got the ball rolling on the project and making

]]>
https://ohmybrew.com/quick-and-dirty-becomes-permanent/5dcda7d9934b5756a5cc19c7Thu, 14 Nov 2019 20:37:04 GMTThe StartWhen

You're assigned a backend project to kick-off and setup, great! You know the requirements and goals, so you set off to build the structure and prototype "quick and dirty" code as a proof-of-concept implementation.

Before you know it... you've got the ball rolling on the project and making good headway! Other developers may be introduced to assist, and they pick up right along with you in the development flow. Then, it snowballs.

Eventually, you'll realize your original "quick and dirty" way, is now "the way", and its going to be tough to correct due to the size or timeline of the project now. Whoops!

My personal opinion from being in this situation of beginning large backend projects: Do it right once. Its better to bite the bullet and properly setup the project in a way that's abstract and scalable; even if you have to refactor many times in the early stages, its easier to refactor a couple files/directories compared to dozens.

What to do?

Sit down and plan out your entire structure and with good ol' pen and paper.

What type of project is it? Do you require a database? Will you need caching? Models and Entities? Response handlers? Will you be hitting the database with both reads and writes? Will you have complex queries to a database? Do you need external file storage? Object storage? Do you need views or presenters?

When you sit back and think longer term for the project, it'll help guide your thoughts into compartments which will help you mentally map things out for a better start.

Abstraction & Responsibility

Now, the rest of this article is purely my own opinion from experience. There's usually a good debate on what code should do what, and how much abstraction is needed. Every developer has their own opinion and feelings towards what they view as too much or too little.

In my opinion, back to my previous heading, things should always be compartmentalized and have singular responsibilities. This helps keep code DRY, maintainable, scalable, testable, and even cleaner to look at.

Interfaces

A lot of new developers are put off from interfaces. They don't exactly see the point of them in their projects, even if they are the sole developer working on it.

Interfaces however can be one of the best keys to success in testability and scalability.

An interface in plain words is a set of rules around how a structure needs to behave; wheather that structure is an actual struct, class, method, or so on.

You may think its silly to define an interface for a single class, but thats not the case. It allows you to decouple your dependencies and swap out those dependencies. It allows another developer to know how to define a strcuture to match that interface so there will be no compatibility issues.

Golang is one my favourite languages for this type of work. Its heavy on interfaces, for good reasons like I have listed above. You can swap in your own implementation for anything in Golang simply by following the interface spec. The same is true with many other languages.

For the sake of using a more common language, PHP, lets take a look at how an interface can be useful with a simple silly example.

<?php

// src/Services/BundleDirectory.php

use Some\Namespace\Interfaces\DirectoryStorage as IDirectoryStorage;

class BundleDirectory
{
	protected $storage;

	public function __construct(IDirectoryStorage $storage)
	{
		$this->storage = $storage;
	}

	public function fetch(int $bundleType): array
	{
		$result = // Some // actions // here
		return $this->storage->locate($result);
	}
}

By type-hinting the constructor to an interface and not to a concrete class, we can pass anything in that matches DirectoryStorage interface. This decouples the implementation.

Now, DirectoryStorage interface would define how locate method should be. BundleDirectory doesn't care about the storage lookup... maybe locate pulls from SQLite, or S3, or plain-ol text files. The point is, it just doesn't care, so long as the interface matches and does as it's suppose to.

When you're testing, you can now inject a mock implementation into BundleDirectory and test without the need to hit an actual storage container.

Nice right? Thats just a very basic example of how an interface can be useful.

SRP / CQR

Single Responsibility Principle (SRP) is one of the big topics people go back-and-forth on. The debate is around how single, single should be. Many complaints come around the fact that SRP causes too much abstraction and separation.

My thoughts: meh, go nuts! Your code should be in compartments and have a singular job to do, and to do that job well.

I love following SRP. Similarly, a sub-practice of SRP is CQR, Command Query Responsibility, which states you should have a seperation of reading (Query) and writing (Command) methods.

Tieing this in with interfaces, you can produce code which follows DRY and is clean to look at as well as work with.

Combining both, lets take a look at a file storage cache. In NextCloud, which I use heavily with AWS S3 for a storage backend, it stores the information about the files in the database so it does not have to hit S3 for the information constantly, as well as provide a nice method for metadata.

If we were to build something that followed SRP and CQR, we could create something like this (again using PHP for examples):

<?php

// src/Interfaces/FileQueries.php

use Some/Namespace/Entities/File as FileModel;
use Some/Namespace/Interfaces/Enums/FileTypes;

interface FileQueries
{
    public function getByID(int $id): FileModel;

    public function getAll(): array; // FileModel[]

    public function getByType(string $type = FileTypes::DEFAULT);

    // ....
}

//
// ....
//

// src/Services/Operations/ProcessImageFiles.php

use Some/Namespace/Interfaces/FileQueries as IFileQueries;
use Some/Namesapce/Interfaces/AbstractOperation;

class ProcessImageFiles implements AbstractOperation
{
    protected $query;
    protected $fileType;

    public function __construct(IFileQueries $query, string $fileType)
    {
        $this->query = $query;
        $this->fileType = $fileType;
    }

    public function execute(): array
    {
        $results = [];
        $files = $this->query->getByType($this->fileType);
        foreach ($files as $file) {
            // do something with the files, maybe generate thumbnails for images
            $results[] = // something
        }

        return $results;
    }
}        

In the above, we define a querier, the Q in CQR, which is an interface. We then have an operation which is a single responsibility class doing one job: to query files of a type, do an operation on those files, and return a result.

We can easily swap out the querier for the operation in testing, its clean to look at, resuable, scalable, and so on.

Maybe we swap in a querier which provides a Redis-cached version of the data for example; instead of injecting DatabaseFileQueries we inject RedisFileQueries which still conforms to FileQueries interface.

Similarly, for the C in CQR, we could define FileCommand interface which dictates how to to update, destory, and create a file entity.

Service Classes

While creating many interfaces, operations, commands, queries, etc may seem disjointed... thats the point, because everything should do one thing and do it right!

That being said, you don't have to reference everything singularly just because you defined it with a singular purpose. You can create a service class to glue the operations, commands, and queries together into a group of common methods.

Maybe its a response handler class for the files... taking a request, using that request to form a query, and providing a response. Maybe its a plain old class for the files... having a common place to access the files, transform the data, etc.

This allows you to have decoupled code, that have singular responsibilities, but still commonly accessible if need be. This avoids creating god-like classes, just simply using the classes to join bits of logic together. Again, making it testible, DRY, clean, reusable, and so fourth.

Conclusion

While this was a short article, I just mainly wanted to drive a point home about proper planning for the long run can have some big pay offs when you compartmentalize your code, give it single responsbilities, and decouple it with interfaces. Quick and dirty can become solid and lasting.

Again, my own opinion on how to work with code, no matter the language.

Cheers.


Photo credit: Nick Abrams

]]>
<![CDATA[Self Hosting Your Cloud]]>Sharing my experience with NextCloud. After months of picking at it here-and-there due to time constraints, I have moved away from my home RaspberryPi setup with USB HDDs, to a full NextCloud solution.

Preamble

I have grabbed a VPS from Amazon and installed Ubuntu 18.04 Server. Then, manually installed

]]>
https://ohmybrew.com/self-hosting-your-cloud/5db64361ae91ba15b2faa02aMon, 28 Oct 2019 02:09:21 GMT

Sharing my experience with NextCloud. After months of picking at it here-and-there due to time constraints, I have moved away from my home RaspberryPi setup with USB HDDs, to a full NextCloud solution.

Preamble

I have grabbed a VPS from Amazon and installed Ubuntu 18.04 Server. Then, manually installed NextCloud (not through snap or Docker) and backed it by NGINX with PHP-FPM.

I wanted to use AWS S3 to store all my files since the cost is effective and endlessly scaleable. Its important to edit NextCloud's config and plug in your AWS S3 settings before installation or NextCloud will default to local filesystem which you can not migrate from.

Once that was done, installation was smooth and simple. The connection to my S3 bucket was fast and painless.

Next, I installed a few NextCloud apps. Namely:

  • Preview Generator - for generating thumbnails. See timer tips here and optimization tips here.
  • Notes - for cross-platform Markdown/TXT notes.
  • Bookmarks - for cross-platform bookmarks.
  • Calendar - for calendar hosting.
  • Contacts - for contacts hosting.
  • Full Text Search - for ElasticSearch enabled searching.
  • Tasks - for cross-platform tasks through CalDav.

PIM

Calendar

Self Hosting Your Cloud
NextCloud Calendar Web Interface

I moved all my contacts and calendar to the setup. It uses standard CalDav/CardDav so it'll work on any system unlike some proprietary solutions, coughgooglecough. I simply needed to hit Settings & Import, import my ics file and pick a calendar target for it.

Contacts

Self Hosting Your Cloud
NextCloud Contacts Web Interface

As with contacts, the same applied; just clicked Settings, imported my vCard file, and everyone was instantly loaded in. Photos, addresses, custom fields and more we're recognized successfully.

Email

For email, I opted to stick with my current provider, MailBox.org as running your own mail server sucks; even when you use something like MailCow, its a pain to manage.


Lastly, for syncing to my phone and desktop... with the new setup, it was easy. With Thunderbird I simply used my CalDav/CardDav addresses for NextCloud. For Android I installed OpenSync (F-Droid), and used my CalDav/CardDav addresses for NextCloud. No issues in both cases for two-way syncs of calendar and contact data.

Tasks

Self Hosting Your Cloud
NextCloud Tasks Web Interface

I extensively use tasks and try to use apps which will sync with a calendar to store the information. This way its easily accessible anywhere even without an app.

NextCloud's Task app filled that solution quite well. You simply pick a calendar to save the tasks to.

On the phone I use Tasks (F-Droid, Tasks.org) which provides an full-featured interface for managing your tasks and also works with CalDav so it can connect to the NextCloud setup.

Bookmarks

Self Hosting Your Cloud
NextCloud Bookmarks Web Interface

Previously I used Buku, which is a great CLI-powered bookmark app aimed to be agnostic to all browsers. I had several custom scripts to manage syncing to Firefox on so-fourth for my bookmarks and grew tired of the manual-ness of it.

I installed Bookmarks for NextCloud on both the server and Android. There is also a Firefox addon which syncs your bookmarks from NextCloud directly into Firefox.

I wrote a script to import from Buku to NextCloud Bookmarks via API connection, and all was fine.

I also have a script watching for new entries, and when a new entry is added, a script is fired off to capture a PDF of the webpage incase it goes down, and saves the PDF to my NextCloud setup.

Self Hosting Your Cloud
NextCloud Bookmarks for Android

RSS

For handling all my RSS, I installed NextCloud's News. Its an app for NextCloud which integrates into the setup just like Tasks, Bookmarks, PIM, etc.

I simply selected my existing OMPL file to import all my feeds.

Self Hosting Your Cloud
NextCloud News Web Interface

It also has clients for Android, iOS, and desktop which syncs to it. I chose NextCloud News on F-Droid for Android, and FeedBurner works well for Linux on the desktop.

Self Hosting Your Cloud
NextCloud News for Android

File Sharing / Pastebin

Self Hosting Your Cloud
Luna homepage after upload

Finally, for sharing quick files, images, videos, or pastes outside of normal NextCloud sharing, I chose a self-hosted setup called Linx.

Linx is a server and client written in Golang. It looks beautiful and provides a ton of features such as an API, pastebin, image/video/file uploads, optional AWS S3 connection, auth protection, and more.

Configuring it to work with an S3 bucket and setup with NGINX was a breeze and in no-time I had a new home for gists and sharing.

Self Hosting Your Cloud
Luna viewing an image upload
Self Hosting Your Cloud
Luna pastebin view

Conclusion

In conclusion, a self-hosted cloud setup is ideal for myself to keep control of my data and host what I need, keeping out of the hands of companies who don't value privacy.

The setup itself would require a few hours start-to-finish for someone who knows comfortable with server setups. If you're not comfortable however, NextCloud has several docs, forums, and resources to guide your way through it.


Photo credit: Christian Seeling

]]>
<![CDATA[i3 & Plasma: A mean match!]]>
i3 & Plasma Marriage - View Full

Introduction

I have been struggling recently to find a good match of the following:

  1. Productivity
  2. Simplistic
  3. Beauty
  4. No hassle

Plasma on its own, much like any other desktop environment such as XFCE or GNOME, does a great job of throwing you into a

]]>
https://ohmybrew.com/i3-plasma-a-mean-match/5d65f9b782d3c966fe569aa6Wed, 28 Aug 2019 04:06:39 GMT
i3 & Plasma Marriage - View Full

Introduction

I have been struggling recently to find a good match of the following:

  1. Productivity
  2. Simplistic
  3. Beauty
  4. No hassle

Plasma on its own, much like any other desktop environment such as XFCE or GNOME, does a great job of throwing you into a full-featured and worry-free setup. Everything from suspending, audio, Bluetooth, and more is handled pretty much out-of-the-box these days.

However, all the major desktop environments are geared towards floating and manually managing windows like you would with Windows or OSX. You end up spending a good chunk of time attached to your mouse... moving, resizing, and managing those windows to do your work. Yes, you could tweak the settings of these desktop environments to semi-simulate what a good window manager can do, but its not the same.

With a configurable window manager, such as i3, sway, bspwm, and others, you're able to solely use your keyboard to manage windows in a way thats efficent, natural, and powerful.

For someone like me, who doesn't use a mouse (I use my Thinkpad dot only) and has back/neck issues... the less I move around (reaching for mice), the better!

So, to hit all points above... a combo of Plasma and i3 works wonders. And the best thing is that it takes no time at all to setup.

Setup

I followed this guide originally with some tweaks. Since I use OpenSUSE, I did the following for my system (slightly different paths):

# Install i3
sudo zypper in i3

# Create a Plasma + i3 launcher script
$ echo -e '#!/bin/sh\n\nKDEWM=/usr/bin/i3 startkde' > /usr/local/bin/startkde-i3
$ sudo chown root.root /usr/local/bin/startkde-i3
$ sudo chmod 755 /usr/local/bin/startkde-i3

# Create a custom desktop sessions directory
$ sudo cp -a /usr/share/xsessions /usr/local/share/xsessions

# Create a new desktop session file for plasma + i3
$ cp /usr/local/share/xsessions/default.desktop /usr/local/share/xsessions/plasma-i3.desktop
$ sudo sed -i 's|/usr/bin/startkde|/usr/local/bin/startkde-i3|' /usr/local/share/xsessions/plasma-i3.desktop
$ sudo sed -i '/Name.*=/ s/$/-i3/' /usr/local/share/xsessions/plasma-i3.desktop

# Configure sddm (the login screen) to use our new desktop sessions directory
$ echo -e '\n\n[X11]\nSessionDir=/usr/local/share/xsessions' | sudo tee -a /usr/lib/sddm/sddm.conf.d/00-general.conf

Logging out, you'll be presented with an option in SDDM for Plasma-i3.

Tweaking

Several tweaks are needed to ensure an environment that works well for Plasma and i3.

This involves killing off Plasma desktop, telling i3 how to handle certain windows/popups/dialogs, and configuring launchers.

.Xresources is a great way to configure cross-compatible settings for cursors, fonts, colors, and more. Mine simply has just that - colors, cursors, fonts, and some settings for URxvt (terminal).

You can utilize your Xresources to pull in config values into i3.

Here is my i3 config, which has pre-defined settings for handling the different Plasma windows. I have several standard keybindings defined, launchers, and window management. You can go in-depth as you like... you can target certain windows/popups/window-titles and more to do anything you like. You can have certain windows float, certain windows open on a monitor or workspace, certain windows have priorities, certain windows that open next to other certain windows, and so forth; you can go nuts!

Bars

You're able to use any "bar" or panel you like with this setup.. weather it be i3bar, polybar, or plain Plasma panel as I have.

If you decide to use Plasma panels, definately install Virtual Desktop Bar Widget, its a virtual desktop pager which is configurable and simple, and mimics how most other "bars" handle workspaces (its the widget in the screenshot above with "web", "code", "mail", etc).


Give a try. My dot files for i3 and .Xresources has a good starting ground which you can expand upon and enjoy a mouseless experience!

]]>
<![CDATA[Vuex & Data: Keeping It Clean]]>Introduction

Vuex is a state management library, a centralized storage of data for your whole application. Its well documented, beautiful, and easy to use with Vue. The part I want to talk about today is the data portion.

I have increasingly seen cases where the data state of Vuex gets

]]>
https://ohmybrew.com/a-small-vuex-tip/5d31ee515be84050aa1577c0Fri, 19 Jul 2019 16:44:52 GMTIntroductionVuex & Data: Keeping It Clean

Vuex is a state management library, a centralized storage of data for your whole application. Its well documented, beautiful, and easy to use with Vue. The part I want to talk about today is the data portion.

I have increasingly seen cases where the data state of Vuex gets transformed and represents something more than just plain-old data; that's a problem in the long run.

The Problem

A simple example...

Step 1

An external API request is sent out through an action to get a list of books.

Step 2

That book data is then sent to the mutation handler where the developer would map the data to a model class: const bookCollection = books.map(book => new Book(book));.

Step 3

This transformed data gets committed to the state afterwards with state.books = bookCollection;.

All-Together

At first, this seems convenient to the developer, because in any part of their code, they can utilize their models such as: const authorsNotOnSale = state.books.filter(book => !book.isOnSale()).map(book => book.getAuthor()).

But, what happens when you want to serialize that data to JSON? Store it somewhere else outside of Vuex? Such as using a library like vuex-persist?

You'll immidately loose all those nice model functions you've built out and you can not easily restore the state because its more than just data at this point.

The Solution

The proper solution would be to utilize Vuex getters to transform that data into something more usable in your application.

const bookCollection = state => state.books.map(book => new Book(book));

Keep the data clean, lean, and plain. Think of the data this way: can I serialize this? If the answer is no, you may need to dig into why.


Photo credit: Mathew Schwartz

]]>
<![CDATA[FOSS Alternatives for Android]]>These days, privacy and security are out the window. In 2018 and already during 2019, we've seen some of the biggest exploits and privacy invasion to date; everything from people's bank records being leaked due to improper security, to the various scandals of Facebook, and even our home devices such

]]>
https://ohmybrew.com/foss-alternatives-for-android/5cec39c4659a134bdbe1f59dTue, 28 May 2019 13:28:54 GMTThese days, privacy and security are out the window. In 2018 and already during 2019, we've seen some of the biggest exploits and privacy invasion to date; everything from people's bank records being leaked due to improper security, to the various scandals of Facebook, and even our home devices such a basic TV tracking everything you do.

Exodus is a great tool for Android (available on web or F-Droid), allowing you to scan your installed applications and get a full report on what permissions the application asks for and what trackers it has built in.

Below, I'll list some of my choices for alternatives that are free (as in freedom) and protect your privacy.

Lawnchair V2

Source: XDS Developers

This is a Pixel-like launcher that is highly customizable. Although its been in "alpha" stage for quite some time, I've yet to experience any bugs with it and is very stable based on my experience. It is also actively developed, with updates being pushed out weekly.

Exodus - Download

KISS Launcher

Source: APK Fun

Another great launcher which takes a whole new approach is KISS. KISS is a geared to be a very minimal launcher with simply lists your frequent apps on the bottom row and your main screen consists of all your previous/recent apps accessed. Its extremely lightweight, out-of-the-way, and a fresh experience.

Exodus - Download

Fennec / Klar

Source: F-Droid

Fennec is the latest release of "Firefox for Android" with proprietary bits removed. Firefox is rock solid on Android alternative to Chrome. Not only is it more privacy-friendly but it allows for extensions to be installed such as uBlock Origin, HTTPS Everywhere, etc. Firefox Sync also works between devices flawlessly and supports integration with KDE Konnect. Klar, similar to Fennec, is the "Firefox Focus for Android" version with proprietary bits removed.

Download (Fennec) – Download (Klar)

TOR

Source: GHacks

TOR of course, allows for the most privacy. TOR is a network powered by other TOR users. You become anonymous as you're routed through different relay connections before hitting the final destination. The browser itself is a modified Firefox release with a wealth of tools to help your remain anonymous to the "web lords", tracking, and more.

AnySoftKeyboard

Source: F-Droid

GBoard "phones home" to build better suggestions about your typing, but who knows what else it's storing about what you type? I have limited experience with other keyboards, however this one caught my eye and I needed not to look any farther.

AnySoftKeyboard is completely customizable with a wealth of options, gestures (including swipe-to-type), many themes (I find the "Dark ASOP" theme the most GBoard-like), and extensions. Its actively developed and features alternative languages through extensions as well.

Exodus - Download

Markor

Source: F-Droid

Markor is a feature-rich markdown editor with support for todo.txt. Nothing is stored in the cloud but because everything is offline it supports any sync client such as OwnCloud, NextCloud, Seafile, Syncthing, or anything else which simply watches a directory.

Markor is great for storing notes, draft blog posts, recipes or anything you can store in markdown or plaintext format.

Exodus - Download

Simple File Manager

Source: F-Droid

Simple File Manager provides an basic interface for managing your files stored locally and on any SD card attached to the phone. It features a quick search, bookmarking, password protection, and more.

Exodus - Download

Syncthing

Source: F-Droid

Syncthing replaces proprietary sync and cloud services with something open, trustworthy and decentralized. Putting you in control of your files and keeping them out of the cloud. You have the ability to add approved devices to share folders on any device with any other device. It has support for iOS, Android, and comes with a handy web-client for easier configuration. As well, it comes with several built-in options for file versioning.

Exodus - Download

Tasks

Source: Google Play

Tasks is a open source fork of the Astrid app. A great material-designed app to keep your self on track. Its full featured with categories, priorities, location-based tasks, voice clips, and more.

Exodus - Download

Bitwarden

Source: Google Play

Bitwarden is a cross-platform password management tool. Its easy to use and can help you store logins for websites, logins for databases, logins for servers, credit cards, notes, and more. It also features built-in TOTP for two-factor authentication. Extension for Firefox is also available.

Exodus - Download

FreeOTP+

Source: Github

FreeOTP is a two-factor authentication (2FA) application for systems  utilizing one-time password protocols (OTP). Tokens can be added easily  by scanning a QR-code or by manually entering in the token  configuration.

FreeOTP implements open standards. This means that  no proprietary server-side component is necessary: use any server-side  component that implements these standards

Exodus - Download

QKSMS

Source: Github

QKSMS is an open source, material designed, SMS/MMS app. It features a customizable interface, with dark mode, scheduled messages, message pinning, searching, media access, and more.

Exodus - Download

OpenHub

Source: Github

An open source GitHub Android client app, faster and concise. It allows you to manage your profile, repositories, issues, and more. The only downside I find is theres no difference inside the app for what is an issue and what is a PR. So if someone submits a PR, you can not view the changes from the app.

Exodus - Download

OpenSync

Source: Google Play

By default, Android does not support CalDAV/CardDAV (probably because Google wants you stuck on their services). This simple app allows you to connect to DAV services such as Mailbox.org, PrivateEmail.com, FastMail.com, and more. You're able to pull in and sync two-way: your contacts, your calendars, your tasks (via calendar), and mail.

Exodus - Download

RedMoon

Source: Phone Arena

RedMoon is a "night shift"-like app which filters out blue light at night. This helps your eyes at night, and prevents the blue light from interfering with production of Melatonin. It features a schedule, or location-based scheduling, with several features for screen color, temperature and more.

Exodus - Download

ScreenCam

Source: Play Store

ScreenCam allows you to record your screen (and voice). It features settings to pause/resume recordings, bit rates, resolutions, audio sources, and more.

Exodus - Download


Of cource, there's more open source apps for calendar, email, etc. Explore and find out what you can replace on your phone with a more open source and privacy-abiding alternatives.

]]>
<![CDATA[Go Is Beauty, In Short]]>I've been coding with Golang in my spare time for the past year. I've released a few side projects such as a simple blockchain implementation, a webhook validator for Shopify, a Python clone of with, and other nick-nacks. Unfourtunately, I haven't had the chance to use it a whole lot

]]>
https://ohmybrew.com/go/5cbd242b4d87ad52707c1017Mon, 22 Apr 2019 02:32:29 GMT

I've been coding with Golang in my spare time for the past year. I've released a few side projects such as a simple blockchain implementation, a webhook validator for Shopify, a Python clone of with, and other nick-nacks. Unfourtunately, I haven't had the chance to use it a whole lot during working hours.

Go is a strange beast. To a new comer, it has an odd syntax for methods, loops, doesn't come with built-in collection methods, its plain-jane control flow, and to top it off.. its not functional and its not object-oriented.

I won't get into depths of Go, but I just wanted to shout out to its beauty in it's strangeness in this post. It allows you to code freely in a logical manner, with the power of interfaces and structs that I've not yet seen in another language I've personally worked with.

I love how it also does not hold you hand. You're free to do what you please and its very bare-bones in a sense which gives you a good base to build from (example: the built in testing package has no assertions). Its also hella fast.. the compile times and plain processing abilities are phenominal.

Theres a lot of built in tools like gofmt which ensures your code is formatted a certain way and the build system, the ability to build targetted binaries for systems (even exes!) quickly.

The community is growing rapidly and many tools are popping up, and many tools are being rewritten to Go. I'm excited to see its future and continue working with it more, hopefully the next few versions will fix some module issues and introduce generics.


Photo credit: strichpunkt

]]>
<![CDATA[De-Servicing Life: Revised]]>A few months ago, I began a journey of mainly de-Googleing, but other services as well. I've made some good and bad choices in terms of alternatives for myself so I have begun revising my choices.

Drive Storage

Provider

Previously, I chose pCloud, mainly due to their Linux support. They

]]>
https://ohmybrew.com/de-servicing-life-revised/5c758423dfc1f8095538cfd5Tue, 26 Feb 2019 20:39:03 GMT

A few months ago, I began a journey of mainly de-Googleing, but other services as well. I've made some good and bad choices in terms of alternatives for myself so I have begun revising my choices.

Drive Storage

Provider

Previously, I chose pCloud, mainly due to their Linux support. They have a Linux client which mounts as a standard drive. Using it for over a month, I had no issues. Its desktop app and Android app work flawlessly. Their pricing is also really fair.

However, through an Exodus scan, I found it used several trackers including Facebook specific ones (even the Facebook SSO SDK). I emailed their support about this privacy concern, twice, and received a complete "robot response" back after a couple weeks of wait. They simply stated they can not remove it and ensured its safe — Goodbye!

I considered jumping to Sync next, which is a truly great Canadian-based service focused on privacy and security of your data. They have great pricing as well, similar to pCloud.

Apps

However, I had an itch and decided to go the self-hosted route. Using my Pi 1 Model B, I attempted to install NextCloud. Yes, I knew of the performance issues with NextCloud on Pi, but I didn't care at the time — I was determined.

In practice though, it was true, the thing is a beast to try and run on a little 700mhz CPU with <1GB RAM board... I had to bail on it. Of course, I could purchase a DigitalOcean server to host NextCloud 1-click, but at this point I was still determined to keep it self-hosted.

I then discovered Syncthing. Syncthing has a large following and its open source, with clients for all the major platforms. It works by syncing folders you choose, to only the devices you choose in a secure way. This means every device you share that folder to, will get a copy of the same data synced. It also offers several revision control options. I haven been using it now for over a month to hold my data (of course with regular backups) and have had no issues, plus everything is self-hosted this way!

Solution: Desktop & Mobile (Syncthing)

Communication

Provider

I'm still with the same private email hosting provider, which handles my mail well, calendar, and contacts; through CalDav and CardDav.

The only downside is no automated Birthdays & Events calendar like other services generate based on your contacts. Luckily, I found this app, "Contact Events & Birthdays FREE". It will list our any events in your contacts... for birthdays, it'll say how far away the birthday is, plus the person's age, it will also list out any anniversaries. Further, it will notify you ahead of time. It has a solid privacy policy, and sniffing the requests it doesn't seem to have anything out of the ordinary.

Solution: Remained the same

Apps

On mobile, I tried a lot of options but some failed to work well with my work email (gSuite), or some plain didn't work. K9, which I do like because its open source, hasn't been updated in ages, the UI makes it hard to read and navigate. MailDroid was a good one as well, however I had trouble with it loading and parsing attachments, its notifications didn't seem to come in correctly as well. Nine, while praised, is $25; it works well but I am not sure I will commit to it yet.

So for now, I'm stuck with stock gMail app still.

On the desktop, I've moved over to Evolution which seems to work for my personal and work quite well. A few bugs here and there but I can get around them.

Solution: Mobile (None) — Desktop (Evolution)

Office Suite

I have fully moved off of using Google to manage my documents. I now use LibreOffice and simple Markdown documents where I can with Typora.

With Syncthing running, I can edit documents on my computer and it will sync to my devices. For Markdown, I use Typora on the desktop and on Android I use an app called Markor.

The only thing I can not find is an open source office suite for Android. Previous I tried PolarisOffice but it's riddled with ads and trackers.

For todo lists, I moved away finally from Todoist. I regular use todo list but I don't need anything heavy. I settled on a simple todo.txt file synced with Syncthing. I am able to edit this on desktop and mobile through Markor (which has todo.txt support built in).

Solution: Mobile (Markor, but no Office Suite yet) — Desktop ( LibreOffice + Typora)

Backups

I am still self-hosting... I regularly run bash scripts monthly to gather all the data I need, compress it, and sync it (through Syncthing) to an external drive as well as my Pi. With multiple copies and drives, I feel safe in this regard.

Solution: Remained the same

Photos

Sadly, no update here. Still stuck on Google Photos. I am investigating building my own solution using face_recognition library for Python. With some initial code I have some good success, the problem is finding the time to code the thing.

Solution: None

Misc

Other than that, I run blocking on all my desktop and mobile browsers. I have also setup Blokada on my Android. Blokada is open source, available on F-Droid and works by creating a local VPN on your device to run requests through. It will block tracking domains, ad domains, and more, instantly. I no longer see ads on any webpage or app I use, its successfully blocked over 10,000 of these requests for me so far in a month!

For RSS feeds, I have dropped Feedly. I now use a synced OPML list for desktop and devices. On desktop I use QuiteRSS which is fully featured and a Thunderbird-like interface to it for managing articles. On mobile, I am using Fylm, which is available on F-Droid and open source. The only downside is not having synced what was alread read or not read, but its fairly easy for me to find the point of where I left off.

I'm slowly trying to move over everything else remaining to open source apps if possible and am almost complete in my journey to de-service myself... cheers!


Photo credit: Mael BALLAND

]]>
<![CDATA[2018 Self Reflection]]>Its a couple months into 2019 already! I sat down and thought about all I've done in 2018 in regards to my digital landscape. On initial spark of this, I didn't think of much therefore, I didn't do much; but, I was wrong!

Software

Open Source

During last year I

]]>
https://ohmybrew.com/2018-self-reflection/5c5b28d39864c66c144f7ad5Wed, 06 Feb 2019 19:09:24 GMTIts a couple months into 2019 already! I sat down and thought about all I've done in 2018 in regards to my digital landscape. On initial spark of this, I didn't think of much therefore, I didn't do much; but, I was wrong!

Software

Open Source

During last year I really hunkered down and focused on my open source projects.

A few silly ones like movie-barcode, CloudApp-Bash, or With and some more important ones, which have gained some popularity, such as Laravel Shopify and Basic Shopify API.

Focusing on my open source work has not only allowed me to refine my existing public code (which some of it has aged), keep self-improving, but also help others who've faced similar issues.

In regards to Laravel Shopify in particular, I hinged on learning the core of Laravel, and coming from a previous Symfony background, this was not hard - just different. Laravel feels more like Rails for PHP, which I do love Rails so I instantly fell in love. Laravel was missing a decent Shopify boilerplate package at the time so I created the package from the ground-up to follow similar practices to how Rails' version, shopify_app gem does.

It has since gained a lot of popularity with many helpful contributors both in pull requests and general questions people post in the issue section. This, in-conjunction with Basic Shopify API package, have allowed many companies (based on their personal thank you emails to me) to create Laravel-powered Shopify apps fairly quickly, letting them focus on their apps code and not the setup.

Open source ecosystems are always great to be involved with. I'm glad I've had the late nights this year to give back to it.

Operating

Its been a hectic year bouncing between operating systems. As a long time Linux user, I broke the streak in 2014 when I purchased my Macbook. However, last year my Macbook finally hit the grave and I purchased a Thinkpad T580 to replace it (with some great specs too!), leading me to use Windows for a few months, but now I'm back on Linux!

Thankfully for software like Vagrant, Docker, WSL, VSCode, and more, my productivity hasn't been impacted between these transitions since mostly everything I write these days is either fairly portable or easily setup on another system.

I've opted for PopOS on my T580 given its great support for dual graphics cards and customizations. I even have a recent post outlining some steps I took to optimize the T580 for daily-driver usage.

Code

Besides moving away from Ruby/Rails and focusing back to PHP/Laravel/Symfony, I've also taken a great focus on modern Javascript/Node and Typescript.

I've absolutely fallen in love with Typescript. Not only is it backed by Microsoft, but its integration with VSCode (through Intellisense and TSLint) has been great. It really allows you to write code you can trust by ensuring values in, out and across, are correct and properly formed.

From a pure web-perspective... a good Typescript setup with Babel/Browserify and some polyfills, can allow you to write modern Javascript that transpiles down to something that's able to work even on older browsers. Keeping a nice, clean, modern source code.

I currently have a large Typescript library assisting an enterprise company processing over 15 million hits a month successfully.

Blog

Not much to say here, but I moved away from Jekyll and moved to Ghost, simply to have a nice interface for writing posts and something I could further customize.

I also opted to develop a modified theme which had colors that were pleasing to the eyes, and easily readable. I based my colors on my favourite editor theme, from RainGlow called UserScape (High Contrast).

Its still powered by Github Pages through a custom script I have which uses Buster to turn my Ghost installation locally into a pure HTML website, which gets uploaded directly to Github.

Digital Fingerprint

Essentially this involved de-Googling as much as I could. Google used to be a great company to my eyes - creating leading-edge software with first-class Android integration.

But the last couple years, they've turned into a pile of shit. No other way to put it. Discontinuing many services and apps and creating a bunch of useless ones, not only showing instability or trust in investing into their ecosystem, but it shows lack of direction. This, on top of their constant privacy issues has driven me away.

It took quite a bit of time to move away from what I could move away from...

Email & Browsing

I've opted to go full-time with Firefox and Thunderbird on the desktop to manage my browsing and e-mail/calendar access. Both solutions are highly customizable, community-backed, and open source. Firefox also has great Android apps such as Firefox itself and Firefox Focus.

I've also moved away from Gmail and the whole Gsuite of products. Gmail itself plain sucks.... from its obscure standards (such as labels and own "IMAP" implementation), to its ever-changing feature-set, it became a disaster and forced you to stick with their product (Google's goal anyways...).

I have moved on to private services such as MailBox.org which gives you a full e-mail/calendar/contact setup for $15 a year.

Services like MailBox.org, PrivateEmail.com, FastMail.com, are all great because they're well... private! Also secure and are based on existing standards such as CalDav, CardDav, and IMAP, allowing you to easily use many popular software on the desktop and mobile to access your digital content (by the way, Android doesn't support *Dav out of the box... I guess another way for Google to keep you locked in).

Drive

This one was hard. It took me months to find a suitable service. I have a lot of documents which Google (creepily) scans via OCR allowing it to be very searchable. They also offered a nice chunk of free space, 15GB last I used it.

I researched and tried many... from Dropbox, which disappointed in price and syncing abilities to a strong second place runner-up of Sync.com, which I liked, but didn't provide Linux integration.

I settled on pCloud, which has a great set of security features, flawless syncing across all my devices, including Linux, and a great web interface. It also has a hard to beat pricing system, allowing you to pay a one-time life-time fee for their service, or a low monthly cost. It also comes with 10GB (unlockable) space for free to try out as long as you like.

The only feature I miss so far is the OCR that Drive provided, but I'll manage without it for now.

Document Suite

I've moved to use LibreOffice on the desktop, which has given me no issues editing any type of document so far, even Doc and Excel files.

For mobile, I've wen't with Polaris Office for Android. I have not used it much as I do not normally edit docs on-the-go, but the few times I did, it managed the job fine.

Other Services

I've yet to break off from anything else. Some people have had success moving away from Google Maps and Youtube, but its not my direct interest right now. Currently I am happy having my core information moved away!


In the end, I've been move productive than I thought originally. I've accomplished a lot, changed a lot, and hope to continue growing. Cheers!

]]>
<![CDATA[Thunderbird with GSuite & Exchange]]>Its true desktop clients are on the decline in favour of easily accessible web clients (such as GMail, Outlook.com). However, if you've ever used a complete native desktop client before such as the star of it all, Outlook, then you know nothing on the web can come close.

Besides

]]>
https://ohmybrew.com/thunderbird-with-gsuite-exchange/5c34feecd6c9242dfe62ac2aTue, 08 Jan 2019 20:20:24 GMTIts true desktop clients are on the decline in favour of easily accessible web clients (such as GMail, Outlook.com). However, if you've ever used a complete native desktop client before such as the star of it all, Outlook, then you know nothing on the web can come close.

Besides the obvious dependability/extendability of endless settings you can tailor to your liking, desktop clients come with the added benefit of offline and powerful instant search. If you travel occasionally like myself, doing work while up in the air is much easier when you have your entire mailbox, address book, and schedule in front of you.

Why Thunderbird

Well, I'm on Linux to start, but its also a great well-tested application suite backed by Mozilla. It features a large helpful community, a wealth of addons, and its open source. I considered using Evolution but it didn't quite meet to my standards of needs.  Other clients such as the popular Geary, are simply too basic to work with when you're dealing with business activities.

Setup for GSuite

Mail

Google implements their own standards when it comes to a lot of things, IMAP is one of them. Instead of folders, Google chose to implement "labels" which translates poorly on my clients.

Luckily Thunderbird handles this well. Simply add your Google account to Thunderbird as normal and configure the account settings to your liking.

Calendar

You'll need two addons for this to work.

  1. "Ligtning" - The integrated calendar & scheduling addon for Thunderbird
  2. "Provider for Google Calendar" - Allows bidirectional access to Google Calendar.

Once both are installed, simply click the menu icon for Thunderbird > "New Message >" > Calendar.., to open the calendar dialog. From here, select "From network...", then "Google Calendar". You should now be able to enter your Google account information and your calendars will sync.

Contacts

For contacts, you'll need to install "gContactSync". Once installed, click the menu icon for Thunderbird, go to Addons > gContactSync. Enter your Google account information, choose the lists you wish to sync, and hit save.

This addon does support contact photos as well.

Setup for Exchange / Outlook

Mail

Thunderbird supports this out of the box, if your using Outlook.com you may need to generate an app password for your account to connect. Enter your account information and your mail will begin to sync.

Calendar & Contacts

For this to work, you'll need the following addons:

  1. "TbSync" - Sync contacts, tasks, and calendars for Exchange
  2. "Provider for Exchange" - Adds sync support for Exchange accounts for TbSync
  3. "Ligtning" - The integrated calendar & scheduling addon for Thunderbird

Once installed, click the menu icon for Thunderbird, go to Addons > TbSync > Account Actions > Add a new account. Enter your account information and a dialog will appear allowing you to select which contact lists to sync and which calendars to sync. Once chosen, click "Synchronize this account".

Done! Now your contacts and calendars will appear once syncing is complete.

One note, the contact images do not seem to work though (for me)...

Screenshots or it didn't happen!

Fine!

Example of GSuite & Exchange Mail + Events List
Address book with GSuite & Exchange
]]>
<![CDATA[Thinkpad T580 on Linux]]>Lenovo is known for creating configurable machines that are great for both business and consumers, which are easily extendable or fixable by the average user thanks to their documentation and sane build.

They're also one of the very few vendors, if not the only, to claim Linux compatibility ("out of

]]>
https://ohmybrew.com/thinkpad-t580-on-linux/5c34f408d6c9242dfe62abb6Tue, 08 Jan 2019 19:44:11 GMTLenovo is known for creating configurable machines that are great for both business and consumers, which are easily extendable or fixable by the average user thanks to their documentation and sane build.

They're also one of the very few vendors, if not the only, to claim Linux compatibility ("out of the box" working) for many models.

My Machine

  • Lenovo ThinkPad T580 (2018)
  • 32GB RAM
  • 500GB SSD
  • 15.6" UHD matte screen
  • Intel i7-8650U CPU @ 1.90GHZ x 8
  • Intel UHD 620 (Kabylake) / Nvidia MX150
  • Fingerprint reader
  • Lenovo USB-C Dock

Distro Choice

History

I've been around the block when it comes to Linux, used it for over a decade, with 2003 being my first self installation experience. It was a tough experience at that, head diving into non-GUI command line installations, partitioning, and many pages of installation manuals to read over.

I've tried everything from FreeBSD, Debian, Fedora, DSL, Redhat, OpenSUSE, Gentoo, Ubuntu, Slackware, Mandriva, Arch, and more. Hell, I even tried out Linux from Scratch for fun!

All that distro-hopping gained me a lot of experience, and by experience I mean the type of experience you gain when your system crashes for some random reason, becomes unusable, random annoyances you have/want to solve. Many of these distros I stuck with and used for years happily.

However, the last few years (if you can tell from my posts), I've been in the land of Mac and Windows... simply because at the time, I needed things to "just work" and being as mobile as I was, I couldn't afford my machine failing on me during a presentation or on-site job. I didn't even trust the ol' Debian route out of that fear.

Change

Not to knock Mac or Windows, they're fine systems and you can get the job done on both through many of the tools available these days such as Vagrant, Docker, or even Microsoft's new WSL; but it just doesn't feel like home. You don't feel the control or the fullness open source software can bring you.

With my new T580, I decided to change that and get back on Linux - bite the bullet and make the system work but also trustworthy.

Thought a lot of research, trial and error, I ended up choosing Pop!_OS. Its a distro based upon Ubuntu with many patches to assist in things like multi-DPI, Intel/Nvidia graphics switching, custom beautiful theming/icons, and sane defaults. Its the distro they pack into their own System76 machines.

Installation

Installation was pretty simple, Pop's installer is well made, easy to follow and clean.

Before beginning installation, I did the following:

  • Wrote Pop to a USB stick
  • Disabled Secure Boot in the BIOs
  • Disabled Window's paging
  • Disabled Window's restore point
  • Shrunk Windows partition (through Windows Disk Management) to bare minimum

Next:

  • Created a EXT4 partition from the unallocated space
  • Set Pop to use the new partition for the boot
  • Set Pop to use the existing EFI partition

Pop then installed the system successfully and created a default boot entry.

Everything upon boot worked. Screens, WIFI, Bluetooth, etc.

Tweaks

To make the most out of the ThinkPads, you should install the following.

TLP

TLP is a power saving utility with special additions for Thinkpads. Such as battery thresholds, statistics, charging plans, recalibration and more.

sudo apt install tlp

With this, you should also install the kernel modules for thresholds to work.

sudo apt install tp-smapi-dms

sudo modprobe tp-smapi

For more information visit the TLP webpage.

Audio

With the newer ThinkPads, Lenovo ships them with Dolby Digital assistant for Windows to really make the built-in speakers sound beefy. On Pop (any others), the speaker will sound average... even lame.

To help with this, we can install PulseEffects. This is a complete tool for managing the audio output, allowing you to adjust and save/load presets to your liking.

sudo apt install pulseeffects

Once installed I recommend you check out this repository on Github for some great ready-made presets. I personally recommend Perfect EQ.

Now, your speakers, and even other audio devices will sound great!

Wayland

If you have an Intel graphics card like me, then you're able to use Wayland.

sudo nano /etc/gdm3/custom.conf

Find WaylandEnable=false and commend it out: #WaylandEndable=false. Then, sudo systemctl restart gdm.service.

You should now be logged out and a visible cog icon should show next to "Login". Click it and select "Pop (Wayland)".

The only downfall is Firefox (and Chrome), as well as Thunderbird, do not support the scaling properly yet. I've heard the nightly edition of Firefox does solve these issues however.

Given those scaling issues, I personally remain on the default Xorg for now. Which is totally fine! Pop has a great daemon running to detect when you plug in mixed DPI screens to the laptop. It will automatically adjust the resolutions to match so you won't have scaling issues.

Nvidia

As of writing, you can install the nvidia-410 driver which works fine for the MX150.

Running sudo powertop and switching to the tunables tab, you should see a "BAD" status for the Nvidia power management. Simply click enter, to check it from bad to good. Using the recommended changes, my power usage for Nvidia (7-9W) closely matches Intel (6-8W of usage).

A Month Later

Its now been a month and I've experience no issues besides the rare issue of the desktop freezing sometimes when I plug in my USB-C dock.

Overall, Pop is a great polished distro with a lot of care put into its end-to-end process from installation to the end-user experience with the polished custom themeing. Give it a try!

]]>
<![CDATA[Apply, Verify, and Validate Shopify Discount Codes]]>Shopify doesn't have an API to verify discount, however I have found a little work-around.

By making an AJAX call to /discount/(code), Shopify will set a cookie telling the checkout to auto-apply a discount on visit to the checkout page.

Next, making an AJAX call to /checkout, we're able

]]>
https://ohmybrew.com/apply-verify-and-validate-shopify-discount-codes/5bc93b19b15546125023bdfbFri, 19 Oct 2018 02:14:59 GMTShopify doesn't have an API to verify discount, however I have found a little work-around.

By making an AJAX call to /discount/(code), Shopify will set a cookie telling the checkout to auto-apply a discount on visit to the checkout page.

Next, making an AJAX call to /checkout, we're able to parse the HTML and determine if the discount code worked!

Here's an example of it in action:

promo-verify

For source code of this script, please see this repository.

]]>
<![CDATA[Moved to Ghost]]>

Background

I originally created my blog with Jekyll for the past few years. Jekyll is an amazing static-site generator created with Ruby; it gives you full control over the templates, markdown, and more.

However, I recently found Ghost. Ghost is a paid publishing platform which also offers their platform as

]]>
https://ohmybrew.com/moved-to-ghost/5a8dbdff3f9db9150b632d47Wed, 21 Feb 2018 19:10:45 GMT

Background

Moved to Ghost

I originally created my blog with Jekyll for the past few years. Jekyll is an amazing static-site generator created with Ruby; it gives you full control over the templates, markdown, and more.

However, I recently found Ghost. Ghost is a paid publishing platform which also offers their platform as open-source on Github.

What I like about Ghost is it's beautiful administration panel that lets me just focus on writing (in Markdown). It comes with a lot of features and plugins; like integration with Unsplash, featured image support, basic Markdown tools, meta modifications, excerpts, spell checking, tag tracking, live previews, etc.

I took the plunge and decided to move.

Moving

First, I wrote a quick script to convert the Markdown files into a Ghost-compatible JSON file for import.

Essentially taking the YAML frontmatter that Jekyll uses, moving it into a JSON file, and uploading it into Ghost's administration panel.

For images, I simply dropped them right into the content/images of the Ghost installation.

Static Generation

So one problem, Ghost is writtin in NodeJS and is meant to be run on a server. It is not a static generator like Jekyll.

Using a tools, like Buster, we can overcome this problem fairly easy.

Buster

You can install Buster; a simple static-generator for Ghost which crawls the Ghost installation using wget and produces a static structure ready to upload to Github pages or other static hosting providers.

Its a simple as using your terminal to move into the Ghost installation, and typing pip install buster, followed by buster setup.

Buster Clean-Up

Buster produces raw files... no fixing for domain names, HTTPs, and all files and anchor tags are preserved to use ".html" at the end.

I modified a script from StefanScherer/ghost-buster-docker to fix the domain names, move all http to https, clean up .html from links, and more. You can view the Gist here.

Save it to your Ghost installation was buster.sh and be sure to give the file the correct permissions to run. Also, change my domain name for your domain name.

Next, create a folder inside your Ghost installation:
mkdir static; mkdir copy

  • static is where Buster will generate the files.
  • copy is where you wish to place files to be copied over after Buster has ran (README.md, CNAME, etc).

Now, start Ghost up with npm start. Once started, run ./buster.sh --deploy.

The script will clear out the static folder, run the static generation, fix all the links within the HTML and sitemaps, clean up any cruft, copy the files over from copy, and push the result to Github.

Thats it! Ghost > Static Generation > Github Pages. I'm really enjoying Ghost thus far, and I hope you too will check it out.


Cover image credit: Toa Heftiba

]]>
<![CDATA[Laravel Shopify Billing]]>

Version 2.0.0 was just released which features the baked-in ability to turn your Shopify app into a billable app with some simple configuration additions.

It has support for the two methods Shopify supports, single and recurring charges. You have the ability to set the plan name, price, trial

]]>
https://ohmybrew.com/laravel-shopify-billing/5a8ca2fd415b127824f260edFri, 26 Jan 2018 15:52:56 GMTLaravel Shopify Billing

Version 2.0.0 was just released which features the baked-in ability to turn your Shopify app into a billable app with some simple configuration additions.

It has support for the two methods Shopify supports, single and recurring charges. You have the ability to set the plan name, price, trial days, and more.

You also have to ability to easily upgrade or downgrade a shop's plan, enable them as a grandfather (skip billing), and more.

For full information see the release notes, upgrading doc, and the wiki page for creating a billable app.

Other minor updates include integration with StyleCI to keep coding standards within PSR1 and PSR2.

]]>
<![CDATA[Setting Up Lumen + Redis]]>

This is more of an extension of my previous post "Setting Up Lumen + Mail". I wanted to take it a step furthur and show the basic setup for getting Redis to work, so you can queue not only mail, but jobs.

First, run composer require illuminate/redis:5.

]]>
https://ohmybrew.com/setting-up-lumen-and-redis/5a8ca2fd415b127824f260e8Sun, 19 Nov 2017 11:43:01 GMTSetting Up Lumen + Redis

This is more of an extension of my previous post "Setting Up Lumen + Mail". I wanted to take it a step furthur and show the basic setup for getting Redis to work, so you can queue not only mail, but jobs.

First, run composer require illuminate/redis:5.5 to grab the Redis components.

Next, open app/Providers/AppServiceProvider.php and add the following to the register method:

<?php
// ...

// Configs
$this->app->configure('database');

// Enable queues
$this->app->make('queue');

Next, create config/database.php and add the following:

<?php

return [
  'redis' => [
    'client' => 'predis',
    'default' => [
      'host' => env('REDIS_HOST', '127.0.0.1'),
      'password' => env('REDIS_PASSWORD', null),
      'port' => env('REDIS_PORT', 6379),
      'database' => 0
    ]
  ]
];

Don't forget to setup all your environment variables for Redis, as well, to enable Redis for job processing and cache, set the following environment variables:

CACHE_DRIVER=redis
QUEUE_DRIVER=redis

That's it! You can now queue mail or process jobs.


Cover image credit: Jingyi Wang

]]>
<![CDATA[Setting Up Lumen + Mailer]]>

What is Lumen?

Lumen is a micro-framework built by Laravel. Its geared towards small services like APIs, job handling, or very small projects. Laravel is all-inclusive, where as Lumen is bare-bones but still featured.

Setting Up Mailing

Recently I ported a small app from Sinatra to Lumen for trial with

]]>
https://ohmybrew.com/setting-up-lumen-and-mail/5a8ca2fd415b127824f260e1Sun, 19 Nov 2017 11:04:33 GMT

What is Lumen?

Setting Up Lumen + Mailer

Lumen is a micro-framework built by Laravel. Its geared towards small services like APIs, job handling, or very small projects. Laravel is all-inclusive, where as Lumen is bare-bones but still featured.

Setting Up Mailing

Recently I ported a small app from Sinatra to Lumen for trial with a client. Its a job processing app for Shopify, where it would take data from a web hook, process it with a worker, and send back some data later. It needed to be fast, as like other webhook-focused app, it has to keep up with the high demand.

One issue I ran into was mailing, its not enabled by default in Lumen, and there are many posts throughout Google of people attempting to set it up. There is also many outdated ways which only worked for old version of Lumen.

Through trial and error, I managed to find a working setup I thought I would share.

Setup

First, run composer require illuminate/mail:5.5 to grab the mailing component.

Next, open bootstrap/app.php, find $app->register(App\Providers\AppServiceProvider::class); and uncomment it, if not already.

After this is done, open the app provider in app/Providers/.

At the bottom of the register method, paste in the following:

<?php
// ...

// Init mailer
$this->app->singleton(
    'mailer',
    function ($app) {
        return $app->loadComponent('mail', 'Illuminate\Mail\MailServiceProvider', 'mailer');
    }
);

// Aliases
$this->app->alias('mailer', \Illuminate\Contracts\Mail\Mailer::class);

To make mailing queue-able and able to be processed in the background, simply add:

<?php
// ...

// Enable queues
$this->app->make('queue');  

And see my Lumen Redis tutorial to setup Redis for processing.

Next, setup the basic config config/mail.php:

<?php

return [
    'driver' => env('MAIL_DRIVER'),
    'host' => env('MAIL_HOST'),
    'port' => env('MAIL_PORT'),
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS'),
        'name' => env('MAIL_FROM_NAME'),
    ],
    'encryption' => env('MAIL_ENCRYPTION'),
    'username' => env('MAIL_USERNAME'),
    'password' => env('MAIL_PASSWORD'),
    'markdown' => [
        'theme' => 'default',
        'paths' => [
            resource_path('views/vendor/mail'),
        ],
    ],
];

That's it, you're done the setup! Don't forget to setup your environment variables for production.

Creating a Mailer

Now that we're setup, you can create a mailer in app/Mail/, heres an example to go by (app/Mail/Winnings):

<?php namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class Winnings extends Mailable
{
    use Queueable, SerializesModels;

    /** @var string the address to send the email */
    protected $to_address;

    /** @var float the winnings they won */
    protected $winnings;

    /**
     * Create a new message instance.
     *
     * @param string $to_address the address to send the email
     * @param float $winnings   the winnings they won
     * 
     * @return void
     */
    public function __construct($to_address, $winnings)
    {
        $this->to_address = $to_address;
        $this->winnings = $winnings;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this
            ->to($this->to_address)
            ->subject('Your winnings!')
            ->view('emails.winnings')
            ->with(
                [
                    'winnings' => $this->winnings
                ]
            );
    }
}

Now, create a view, resources/views/emails/winnings.blade.php for simply HTML-only,:

{% raw %}<strong>You won {{ $winnings }}</strong>!{% endraw %}

Sending Mail

Now that we have it setup, and a mailable created, we can send. In your job, controller, or where ever you need it:

<?php
use App\Mail\Winnings as WinningsMail;

// ...
// $to_email = 'john@doe.com'; $winnings = 130.00;

Mail::send(
    new WinningsMail(
        $to_email,
        $winnings
    )
);

If you're queuing mail, replace send with queue. You can also see Laravel's mail documentation for more information on sending.

Testing

Of course, we need to test (tests/WinningsMailTest.php):

<?php

use App\Mail\Winnings;
use Illuminate\Support\Facades\Mail;

class WinningsMailTest extends TestCase
{
    public function testItWorks()
    {
        Mail::fake();

        Mail::send(
            (new Winnings('john@doe.com', 15.00))->build()
        );

        Mail::assertSent(Winnings::class, function ($mail) {
            return $mail->hasTo('john@doe.com') &&
                   $mail->subject === 'Your winnings!' &&
                   $mail->viewData['winnings'] === 15.00;
        });
    }
}

Running the tests should pass if everything is setup correctly. For more information on testing mailables, see Laravel's documentation on faking.

I hope this was a quick and useful setup for anyone having issues. Good luck!


Cover image credit: Mikael Kristenson

]]>