Thursday, 31 August 2017

Meet the millennials who mine - Not gold but Cryptocurrency

Bitcoins saw explosive growth in India after Prime Minister Narendra Modi recalled high-denomination banknotes in November.

How to Regain Access to Your Plex Server When You’re Locked Out

For the most part, the Plex Media Server experience is pretty flawless. You install the server software, you point your Plex clients at it, and start watching your movies. But sometimes, you’ll go to log into your server only to be mysteriously shut out. Let’s dig into some arcane settings and get you back to media nirvana.

Python Software Foundation


Python in Nigeria


In 2015, the PSF sponsored the first Python event in Nigeria - the Codesses Workshop in Lagos. In 2016, the number of events increased to 13, and there have been 28 events funded so far in 2017! What has happened in the last 2 ½ years to create such a demand for learning Python in this part of the world?


Aisha Bello
I spoke with Aisha Bello about this. She serves as vice-chair for the Python Nigeria community. She has helped co-organize and support a number of Django Girls workshops in Namibia and Nigeria, and also co-organizes PyLadies Nigeria. Aisha is enthusiastic about the  Python community, with a strong desire and passion for social change, women’s tech education and empowerment in Africa. She currently works as an Associate Systems Engineer for Cisco Systems.




Chukwudi Nwachukwu
Sharing his thoughts as well, is Chukwudi Nwachukwu, PSF Board Director, and Team Lead Integrations, TechAdvance. He is also a volunteer member of the PSF Grants Work Group, helping to review requests from Africa and all over the world. He has also been invited to speak at PyCon NG in September. When I asked why he’s passionate about Python, he said, “Python is easy on the brain and I thank Guido [van Rossum]for such a concept.”



Python + Community


20170407_161417.jpg
Smart Girls Project
According to Aisha, Python is popular in Nigeria because it’s one of the easiest ways to learn programming. Knowing how to code opens up many career options. The advantages of open source software are becoming more well-known in this region, and have allowed the community to grow because they’re not tied to any one vendor. She notes: “What we have is community. It means a lot to people that there is a common place or forum where they’re not afraid to share their struggles and ideas with people with like minds. We took the Python language and community and made it our own.”


33338630346_0664e570ca_o.jpg
Django Girls Lagos
Chukwudi believes that “the recent urge for more women to be in the workforce of Nigeria through IT has been a huge factor in the growth of Python programming. The Federal Government of Nigeria has also keyed into this drive by choosing Flask as a framework of choice to be taught in their Npower programme.” In addition, Django Girls events nationwide, startup companies incorporating Python as part of their stack, and IT companies training people to code in Python, have all made Python a leading programming language in Nigeria.

Funding for Events


Aisha and Chukwudi agree that getting funding for events in Nigeria is challenging. Often, it’s startups that come forward to help sponsor events. Aisha believes that “By creating more awareness and putting ourselves more out there, we’re hopeful things will change. Organizations like Github, the PSF, and the Django Software Foundation believe in us, and sponsor our events even when no one else will.”


Fortunately, the Django Girls Foundation offers help through their Organizer’s Manual and a template for how to run a workshop: the Coaching Manual. These documents provide a framework to help groups get started. Having a professional-looking proposal goes a long way toward convincing organizations to support these events.


Positive Outcomes


Many of the participants of these workshops have gone into IT careers, received internships, become mentors, organized workshops, and are actively involved in helping out the community.  Outreach to girls in primary and high schools is working too. Girls are learning to program in Python, and most importantly, they’re learning how to use the tools to continue in their journey toward a career.


One very real example is what Abocoders did in collaboration with DjangoGirls in Lagos. Girls who had been displaced from their homes due to Bokoharam in the North were able to learn about computers and programming. In addition, they each got a refurbished computer to use during and after the workshop.


#GirlCodersRock came out of one of the events. An attendee of a Django Girls event in Nigeria is now an intern at TechAdvance, where Chukwudi works. She’s now coding Python full time. There are many Python-related jobs being advertised right now in Nigeria - Google Nigeria and Upperlink are hiring, and Alljobs.ng has 40+ listings. It looks like the trend will continue.


Chukwudi has seen a large increase in members both on slack channels and mailing lists. The community is very excited about the first PyCon Nigeria, September 15-16, 2017, in Lagos. It’s the largest gathering for the Python community in Nigeria, and is organised by members of the Python Users Nigeria Group, a nonprofit organisation dedicated to advancing and promoting the use of the Python programming language in the country.


25272297040_37be1b624d_o.jpg
Django Girls Lagos
Chukwudi suggested that I speak with a woman he mentors, Hamdalah Adetunji, about her road to a career in programming. She explained: “It is all a step towards growth and progress, but I hope one day in the near future, I get to do more than wish I wasn't the only female on the team. I hope to mentor women to give back the amazing support I have received all through my journey, and also let them know they can be anything they want to be as long as they are focused and determined."

Anker’s Eufy Genie vs. Amazon Echo Dot: Are the Savings Worth It?

The Echo Dot is a great device, but Anker’s Eufy Genie ($35) aims to dethrone it with the same Alexa-based system and a $15 cheaper price tag (even more when it’s on sale). But is it worth saving a few bucks to get a third-party Echo device in the first place?

Wednesday, 30 August 2017

Dataquest: Python Cheat Sheet for Data Science: Intermediate

The printable version of this cheat sheet

The tough thing about learning data is remembering all the syntax. While at Dataquest we advocate getting used to consulting the Python documentation, sometimes it’s nice to have a handy reference, so we’ve put together this cheat sheet to help you out!

This cheat sheet is the companion to our Python Basics Data Science Cheat Sheet

If you’re interested in learning Python, we have a free Python Programming: Beginner course which can start you on your data science journey.

Key Basics, Printing and Getting Help

This cheat sheet assumes you are familiar with the content of our Python Basics Cheat Sheet

s A Python string variable
i A Python integer variable
f A Python float variable
l A Python list variable
d A Python dictionary variable

Lists

l.pop(3) Returns the fourth item from l and deletes...

How to Search Your Amazon Order History

You order so much stuff from Amazon, it’s tough to keep track of it all. If you need to go back through your history to find something you’ve ordered before, you can scroll through pages and pages of items you’ve bought, but that’s tedious. Instead, use the order search history.

Riyadh-headquartered Saudi Rotorcraft Support Company (SRSC) partners with Ramco Systems to provide national MRO Software Support across Saudi Arabia

Saudi Rotorcraft Support Company is a joint venture company formed under agreement with Alsalam Aerospace Industries, Boeing and Saudia Aerospace Engineering IndustriesAs a technology partner, Ramco will install cutting-edge maintenance and engineering software to help SRSC support mission-critical capabilities for Saudi Arabia’s military and commercial helicoptersRiyadh, Saudi Arabia/Singapore – August 2017 – Ramco Systems, the global aviation software provider on Cloud and Mobile, today announced that it has signed a prestigious 5-year agreement with Saudi... Source: RealWire

The Cheapest Ways To Stream College Football (Without Cable)

We’ve shown you the cheapest ways to stream (almost) every NFL game this season. Now we’re back to do the same service for college ball…with one really big caveat.

Continuum Analytics Blog: Anaconda: A Coming of Age Story

Earlier this week, Continuum Analytics was officially renamed  Anaconda. This change is exciting, and equally as exciting is the journey, from our humble beginnings to today—a community of 4.5 million Anaconda users worldwide. No one tells our story better than Continuum co-founders, Travis Oliphant and Peter Wang. Read on for their thoughts and feelings on …
Read more →

Matthew Rocklin: Dask Release 0.15.2

This work is supported by Anaconda Inc. and the Data Driven Discovery Initiative from the Moore Foundation.

I’m pleased to announce the release of Dask version 0.15.2. This release contains stability enhancements and bug fixes. This blogpost outlines notable changes since the 0.15.0 release on June 11th.

You can conda install Dask:

conda install dask

or pip install from PyPI

pip install dask[complete] --upgrade

Conda packages are available both on the defaults and conda-forge channels.

Full changelogs are available here:

Some notable changes follow.

New dask-core and dask conda packages

On conda there are now three relevant Dask packages:

  1. dask-core: Package that includes only the core Dask package. This has no dependencies other than the standard library. This is primarily intended for down-stream libraries that depend on certain parts of Dask.
  2. distributed: Dask’s distributed scheduler, depends on Tornado, cloudpickle, and other libraries.
  3. dask: Metapackage that includes dask-core, distributed, and all relevant libraries like NumPy, Pandas, Bokeh, etc.. This is intended for users to install

This organization is designed to both allow downstream libraries to only depend on the parts of Dask that they need while also making the default behavior for users all-inclusive.

Downstream libraries may want to change conda dependencies from dask to dask-core. They will then need to be careful to include the necessary libraries (like numpy or cloudpickle) based on their user community.

Improved Deployment

Due to increased deployment on Docker or other systems with complex networking rules dask-worker processes now include separate --contact-address and --listen-address keywords that can be used to specify addresses that they advertise and addresses on which they listen. This is especially helpful when the perspective of ones network can shift dramatically.

dask-worker scheduler-address:8786 \
            --contact-address 192.168.0.100:9000  # contact me at 192.168.0.100:9000
            --listen-address 172.142.0.100:9000  # I listen on this host

Additionally other services like the HTTP and Bokeh servers now respect the hosts provided by --listen-address or --host keywords and will not be visible outside of the specified network.

Avoid memory, file descriptor, and process leaks

There were a few occasions where Dask would leak resources in complex situations. Many of these have now been cleaned up. We’re grateful to all those who were able to provide very detailed case studies that demonstrated these issues and even more grateful to those who participated in resolving them.

There is undoubtedly more work to do here and we look forward to future collaboration.

Array and DataFrame APIs

As usual, Dask array and dataframe have a new set of functions that fill out their API relative to NumPy and Pandas.

See the full APIs for further reference:

Deprecations

Officially deprecated dask.distributed.Executor, users should use dask.distributed.Client instead. Previously this was set to an alias.

Removed Bag.concat, users should use Bag.flatten instead.

Removed magic tuple unpacking in Bag.map like bag.map(lambda x, y: x + y). Users should unpack manually instead.

Julia

Developers from the Invenia have been building Julia workers and clients that operate with the Dask.distributed scheduler. They have been helpful in raising issues necessary to ensure cross-language support.

Acknowledgements

The following people contributed to the dask/dask repository since the 0.15.0 release on June 11th

  • Bogdan
  • Elliott Sales de Andrade
  • Bruce Merry
  • Erik Welch
  • Fabian Keller
  • James Bourbeau
  • Jeff Reback
  • Jim Crist
  • John A Kirkham
  • Luke Canavan
  • Mark Dunne
  • Martin Durant
  • Matthew Rocklin
  • Olivier Grisel
  • Søren Fuglede Jørgensen
  • Stephan Hoyer
  • Tom Augspurger
  • Yu Feng

The following people contributed to the dask/distributed repository since the 1.17.1 release on June 14th:

  • Antoine Pitrou
  • Dan Brown
  • Elliott Sales de Andrade
  • Eric Davies
  • Erik Welch
  • Evan Welch
  • John A Kirkham
  • Jim Crist
  • James Bourbeau
  • Jeremiah Lowin
  • Julius Neuffer
  • Martin Durant
  • Matthew Rocklin
  • Paul Anton Letnes
  • Peter Waller
  • Sohaib Iftikhar
  • Tom Augspurger

Additionally we’re happy to announce that John Kirkham (@jakirkham) has accepted commit rights to the Dask organization and become a core contributor. John has been active through the Dask project, and particularly active in Dask.array.

How to Enable or Disable Notification Dots in Android 8.0 Oreo

Google brought a handful of changes in Android Oreo, both big and small. Among the smaller, yet welcome additions to the operating system is something the company calls Notification Dots. Essentially, these are small markers on home screen icons that let you know when an app has a notification.

Amulet Hotkey Delivers Unique Virtual GPU for Dell EMC PowerEdge servers

DXG-P6 GPU solution brings NVIDIA Virtual GPU Solutions and Tesla P6 GPU Accelerator to Dell EMC PowerEdge 14G and 13G M-series blade servers. New York, August 30, 2017 – Amulet Hotkey Inc., a leader in design, manufacturing and system integration for remote physical and virtual workstation solutions, today announced the availability of a new high-performance virtual graphics card for Dell EMC M-series blade servers.The DXG-P6 virtual graphics card brings the latest NVIDIA® Tesla® P6 GPU... Source: RealWire

3 open source Python GUI frameworks

Open source Python GUI frameworks

There comes a time in the journey of most any programmer when they are ready to branch out past the basic examples and start to build a graphical interface to their program.

In Python, the steps to get started with GUI programming are not terribly complex, but they do require the user to begin making some choices. By its nature as a general purpose programming language with interpreters available across every common operating system, Python has to be fairly agnostic as to the choices it presents for creating graphical user interfaces.


read more

What’s the Difference Between a Facebook Profile, Page, and Group?

Facebook is used by a lot of different people for a lot of different things, so it’s only natural that Facebook would have different sets of features for each of them. There are three main ways you can use Facebook: with a regular Profile, as a Page, or as a Group admin. Let’s look at what each is for.

App Subscriptions Are a Good Thing

I get attached to the apps I use. I do all my photo editing in Photoshop and Lightroom, I use Airmail for email, I listen to music with Spotify, I read feeds with Inoreader and Reeder, I Tweet using Tweetbot, and most importantly, for writing I use Ulysses.

Industry 4.0: How to manage the change and prepare leaders

The manufacturing and engineering industries are on the cusp of a fourth industrial revolution that will see artificial intelligence transforming every aspect of our operations. Manufacturers and engineering firms need to start preparing now, to pro-actively manage change and keep ahead of the curve.Festo has produced an extensive White Paper – All Change for Industry 4.0 – to enable leaders and managers to effectively plan-ahead. This White Paper provides the knowledge leaders need to overcome... Source: RealWire

Opportunities for blockchain in healthcare and pharma

The medical and pharma industry holds a significant amount of crucial and personal information including health records and financial information

8 best practices for robotic process automation

Today robotic process automation (RPA) is the technology of choice to streamline business operations and reduce costs.

GDPR: What Does it Mean for Businesses?

By Ian Kilpatrick, EVP Cyber Security for Nuvias GroupOn May 25, 2018, the General Data Protection Regulation (GDPR) will come into force, and will be a game-changer in how organisations store, secure and manage personal data.GDPR will affect the whole of the EU Zone, which currently spans 28 member countries and half a billion citizens. Its goal is to unify data protection across the European Union, but because GDPR applies to individuals within the EU... Source: RealWire

8 open source Android apps for education

8 open source Android apps for education

With a new school year beginning in many areas, now is a great time for parents, students, and educators to try out apps that can help with the learning experience. The following eight apps can turn an Android phone or tablet into a tool to help a student learn and study. They are all open source and all of them are available from the F-Droid repository, so you easily add these apps to any phone that is configured to allow apps from external repositories.


read more

How to create reproducible build environments with Rebuild

How to simplify software development with Rebuild

Building modern software in a predictable and repeatable way isn't easy. The overwhelming number of software dependencies and the need to isolate conflicting components presents numerous challenges in managing build environments.

Although there are many tools aimed at mitigating this challenge, there are two approaches most of them take: either they rely on package managers to preserve and replicate package sets, or they use virtual or physical machines with preconfigured environments.


read more

Mentoring: Your path to immortality

Mentoring: Your path to immortality

Have you ever wondered why some open source projects have better luck than others when it comes to attracting and retaining enthusiastic contributors? Here are a few ways open source projects can improve their chances of getting—and keeping—the kinds of contributors who help make projects succeed.


read more

Google, Apple face off over augmented reality technology

Alphabet Inc's Google on Wednesday unveiled tools to make augmented reality apps for mobile devices using the Android operating system, setting up its latest showdown with Apple Inc's iPhone over next-generation smartphone feature

RTI activist says Aadhaar contract gave foreign firms access to un-encrypted data

Contracts signed with foreign firms by the UIDAI show that they got “full access” to classified data including fingerprints, iris scan info, and personal information like date of birth, address and mobile number of the applicants. They were also allowed to store the data for seven years.

Can electric scooter maker Okinawa sell a Japanese dream to petrol-obsessed Indians?

The biggest challenge for Jeetender Sharma -lack of awareness about electric scooters among Indians -is turning out to be his biggest business opportunity.

States act on Aadhaar, link it to local schemes

This follows a meeting chaired by Prime Minister Narendra Modi in June on expanding the Aadhaar-(DBT) project after which cabinet secretary PK Sinha wrote to all state chief secretaries.

Weekly Python Chat: Virtual Environments in Python

What's a virtual environment? Do you really need them? Is there any way to make them easier to use?

If you're using Python, you probably should be using virtual environments. In this chat we'll discuss what virtual environments are and how to use them.

How Do You Define a PowerShell Function That Requires Elevation?

PowerShell can be extremely useful for a lot of everyday tasks as is, but if you need to tweak some functions with a bit of safety in mind, then how do you define a function so that it requires elevation? Today’s SuperUser Q&A post has the answer to a curious reader’s question.

How to Set Up the Kwikset Kevo Fob to Unlock Your Door Without Your Phone

Under normal circumstances, the Kwikset Kevo relies on your phone in order to know whether it should unlock your door. However, if you’d rather use a dedicated key fob for that (or as a backup when you forget your phone), here’s how to set up the Kwikset Kevo Fob to give your phone a break.

Tuesday, 29 August 2017

Tomasz Früboes: Multiprocessing – understand your exception

If you are reading this post, most likely you’re still working with python 2.7 series for some reason. In such case, one of the small annoyances you risk running into is nearly complete lack of information what’s happening when the multiprocessing module is used and an uncaught exception is thrown in the child process. In… Continue reading

DataCamp: Python Seaborn Cheat Sheet For Statistical Data Visualization

You most probably will know by now that data storytelling, accomplished by data visualization, amongst other things, is an essential skill for every data scientist: after you have turned the raw data into understanding, insights and knowledge, you also need to communicate these findings effectively to your audience. 

For most beginners, the first Python data visualization library that they use is, naturally, Matplotlib. It is a Python 2D plotting library that enables users to make publication-quality figures. It is quite an extensive library where a cheat sheet will definitely come in handy when you're learning, but when you manage to use this library effectively, you'll also be able to get insights and work better with other packages, such as Pandas, that intend to build more plotting integration with Matplotlib as time goes on. 

Another package that you'll be able to tackle is Seaborn, the statistical data visualization library of Python. 

DataCamp has created a Seaborn cheat sheet for those who are ready to get started with this data visualization library with the help of a handy one-page reference. 

You'll see that this cheat sheet presents you with the five basic steps that you can go through to make beautiful statistical graphs in Python. 

Check out the infographic by clicking on the button below:

Seaborn Python cheat sheet

This cheat sheet will walk you through the five steps that you need to go through to make these plots: you'll see how you can load in data, set the figure aesthetics, plot, customize and eventually, show or save your plot with Seaborn.  

What might have looked difficult before will definitely be more clear once you start using this cheat sheet! Use it in combination with the Seaborn Gallery, the documentation and our tutorial.   

Also, don't miss out on our other cheat sheets for data science that cover SciPyNumpyScikit-LearnBokehPandas and the Python basics.

How to Stop Netflix From Sending You Emails and Notifications

Netflix is constantly adding new content, and the company doesn’t want you to forget it. You get emails or notifications when Netflix adds new shows, sends you recommendations, or even adds new features to its apps. Here’s how to turn off all those pestergrams.

Finn Partners Selected To Publicise Not-For-Profit Cloud Platform, The Good Exchange

Ongoing communications programme will raise brand awareness for start-up designed to connect funders and charitable causes across the UKLondon – 29th August 2017 – Global communications firm, Finn Partners, has today announced that The Good Exchange, a not-for-profit transformational cloud platform, has selected the agency to build brand awareness and publicise its charitable giving in the UK. The Good Exchange platform has been specifically designed to connect those organisations and individuals who have money to... Source: RealWire

Take the 2017 Jenkins Survey!

This is a guest post by Brian Dawson on behalf of CloudBees, where he works as a DevOps Evangelist responsible for developing and sharing continuous delivery and DevOps best practices. He also serves as the CloudBees Product Marketing Manager for Jenkins.

Once again it’s that time of year when CloudBees sponsors the Jenkins Community Survey to assist the community with gathering objective insights into how jenkins is being used and what users would like to see in the Jenkins project.

Your personal information (name, email address and company) will NOT be used by CloudBees for sales or marketing.

As an added incentive to take the survey, CloudBees will enter participants into a drawing for a free pass to Jenkins World 2018 (1st prize) and a $100 Amazon Gift Card (2nd prize). The survey will close at the end of September, so click the link at the end of the blog post to get started!

All participants will be able to access reports summarizing survey results. If you’re curious about what insights your input will provide, see the results of last year’s 2016 survey:

Your feedback helps capture a bigger picture of community trends and needs. There are laws that govern prize giveaways and eligibility; CloudBees has compiled all those fancy terms and conditions here.

Please take the survey and let your voice be heard - it will take less than 10 minutes.

How to Train Your Pandora Radio Stations Better

Pandora is one of the oldest and most popular streaming radio services, but if you’re a long-time user, you might notice a certain sameness in some of your custom stations. The Thumbs Up/Thumbs Down rating system tends to repeat the same 100 or so songs after a while, something I’ve certainly observed on some of the “evolving” stations I’ve been curating for years.

Real Python: User Authentication with Angular 4 and Flask

In this tutorial, we’ll demonstrate how to set up token-based authentication (via JSON Web Tokens) with Angular 4 and Flask.


angular4 auth

Main Dependencies:

  1. Angular v4.2.4 (via Angular CLI v1.3.2)
  2. Flask v0.12
  3. Python v3.6.2

Auth Workflow

Here’s the full user auth process:

  1. Client logs in and the credentials are sent to the server
  2. If the credentials are correct, the server generates a token and sends it as a response to the client
  3. Client receives and stores the token in Local Storage
  4. Client then sends token to server on subsequent requests within the request header

Project Setup

Start by globally installing the Angular CLI:

1
$ npm install -g @angular/cli@1.3.2

Then generate a new Angular 4 project boilerplate:

1
$ ng new angular4-auth

Fire up the app after the dependencies install:

1
2
$ cd angular4-auth
$ ng serve

It will probably take a minute or two to compile and build your application. Once done, navigate to http://localhost:4200 to ensure the app is up and running.

Open up the project in your favorite code editor, and then glance over the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
├── e2e
│   ├── app.e2e-spec.ts
│   ├── app.po.ts
│   └── tsconfig.e2e.json
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── src
│   ├── app
│   │   ├── app.component.css
│   │   ├── app.component.html
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   └── app.module.ts
│   ├── assets
│   ├── environments
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── favicon.ico
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.css
│   ├── test.ts
│   ├── tsconfig.app.json
│   ├── tsconfig.spec.json
│   └── typings.d.ts
├── tsconfig.json
└── tslint.json

In short, the client-side code lives in the “src” folder and the Angular app itself can be found in the “app” folder.

Take note of the AppModule within app.module.ts. This is used to bootstrap the Angular app. The @NgModule decorator takes metadata that lets Angular know how to run the app. Everything that we create in this tutorial will be added to this object.

Make sure you have a decent grasp of the app structure before moving on.

NOTE: Just getting started with Angular 4? Review the Angular Style Guide, since the app generated from the CLI follows the recommended structure from that guide, as well as the Angular4Crud Tutorial.

Did you notice that the CLI initialized a new Git repo? This part is optional, but it’s a good idea to create a new Github repository and update the remote:

1
$ git remote set-url origin <newurl>

Now, let’s wire up a new component

Auth Component

First, use the CLI to generate a new Login component:

1
$ ng generate component components/login

This set up the component files and folders and even wired it up to app.module.ts. Next, let’s change the login.component.ts file to the following:

1
2
3
4
5
6
7
8
9
10
11
import { Component } from '@angular/core';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})

export class LoginComponent {
  test: string = 'just a test';
}

If you haven’t used TypeScript before, then this code probably looks pretty foreign to you. TypeScript is a statically-typed superset of JavaScript that compiles to vanilla JavaScript, and it is the de facto programming language for building Angular 4 apps.

In Angular 4, we define a component by wrapping a config object with an @Component decorator. We can share code between packages by importing the classes we need; and, in this case, we import Component from the @angular/core package. The LoginComponent class is the component’s controller, and we use the export operator to make it available for other classes to import.

Add the following HTML to the login.component.html:

1
2
3
<h1>Login</h1>

<p></p>

Next, configure the routes, via the RouterModule in the app.module.ts file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      { path: 'login', component: LoginComponent }
    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule { }

Finish enabling routing by replacing all HTML in the app.component.html file with the <router-outlet> tag:

1
<router-outlet></router-outlet>

Run ng serve in your terminal, if you haven’t already, and then navigate to http://localhost:4200/login. If all went well you should see the just a test text.

Bootstrap Style

To quickly add some style, update the index.html, adding in Bootstrap and wrapping the <app-root></app-root> in a container:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Angular4Auth</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
  <div class="container">
    <app-root></app-root>
  </div>
</body>
</html>

You should see the app auto reload as soon as you save.

Auth Service

Next, let’s create a global service to handle a user logging in, logging out, and signing up:

1
$ ng generate service services/auth

Edit the auth.service.ts so that it has the following code:

1
2
3
4
5
6
7
8
import { Injectable } from '@angular/core';

@Injectable()
export class AuthService {
  test(): string {
    return 'working';
  }
}

Remember how providers worked in Angular 1? They were global objects that stored a single state. When the data in a provider changed, any object that had injected that provider would receive the updates. In Angular 4, providers retain their special behavior and they are defined with the @Injectable decorator.

Sanity Check

Before adding anything significant to AuthService, let’s make sure the service itself is wired up correctly. To do that, within login.component.ts inject the service and call the test() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})

export class LoginComponent implements OnInit {
  test: string = 'just a test';
  constructor(private auth: AuthService) {}
  ngOnInit(): void {
    console.log(this.auth.test());
  }
}

We’ve introduced some new concepts and keywords. The constructor() function is a special method that we use to set up a new instance of a class. The constructor() is where we pass any parameters that the class requires, including any providers (i.e., AuthService) that we want to inject. In TypeScript, we can hide variables from the outside world with the private keyword. Passing a private variable in the constructor is a shortcut to defining it within the class and then assigning the argument’s value to it. Notice how the auth variable is accessible to the this object after it is passed into the constructor.

We implement the OnInit interface to ensure that we explicitly define a ngOnInit() function. Implementing OnInit ensures that our component will be called after the first change detection check. This function is called once when the component first initializes, making it the ideal place to configure data that relies on other Angular classes.

Unlike components, which are automatically added, services have to be manually imported and configured on the @NgModule. So, to get it working, you’ll also have to import the AuthService in app.module.ts and add it to the providers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { AuthService } from './services/auth.service';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      { path: 'login', component: LoginComponent }
    ])
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})

export class AppModule { }

Run the server and then navigate to http://localhost:4200/login. You should see working logged to the JavaScript console.

User Login

To handle logging a user in, update the AuthService like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class AuthService {
  private BASE_URL: string = 'http://localhost:5000/auth';
  private headers: Headers = new Headers({'Content-Type': 'application/json'});
  constructor(private http: Http) {}
  login(user): Promise<any> {
    let url: string = `${this.BASE_URL}/login`;
    return this.http.post(url, user, {headers: this.headers}).toPromise();
  }
}

We employ the help of some built-in Angular classes, Headers and Http, to handle our AJAX calls to the server.

Also, update the app.module.ts file to import the HttpModule.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { AuthService } from './services/auth.service';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    HttpModule,
    RouterModule.forRoot([
      { path: 'login', component: LoginComponent }
    ])
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})

export class AppModule { }

Here, we are using the Http service to send an AJAX request to the /user/login endpoint. This returns a promise object.

NOTE: Make sure to remove console.log(this.auth.test()); from the LoginComponent component.

User Registration

Let’s go ahead and add the ability to register a user as well, which is similar to logging a user in. Update src/app/services/auth.service.ts, taking note of the register method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class AuthService {
  private BASE_URL: string = 'http://localhost:5000/auth';
  private headers: Headers = new Headers({'Content-Type': 'application/json'});
  constructor(private http: Http) {}
  login(user): Promise<any> {
    let url: string = `${this.BASE_URL}/login`;
    return this.http.post(url, user, {headers: this.headers}).toPromise();
  }
  register(user): Promise<any> {
    let url: string = `${this.BASE_URL}/register`;
    return this.http.post(url, user, {headers: this.headers}).toPromise();
  }
}

Now, to test this we need to set up a back end…

Server-side Setup

For the server-side, we’ll use the finished project from a previous blog post, Token-Based Authentication With Flask. You can view the code from the flask-jwt-auth repository.

NOTE: Feel free to use your own server, just make sure to update the baseURL in the AuthService.

Clone the project structure in a new terminal window:

1
$ git clone http://ift.tt/2kdBavV

Follow the directions in the README to set up the project, making sure the tests pass before moving on. Once done, run the server with python manage.py runserver, which will listen on port 5000.

Sanity Check

To test, update LoginComponent to use the login and register methods from the service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  test: string = 'just a test';
  constructor(private auth: AuthService) {}
  ngOnInit(): void {
    let sampleUser: any = {
      email: 'michael@realpython.com' as string,
      password: 'michael' as string
    };
    this.auth.register(sampleUser)
    .then((user) => {
      console.log(user.json());
    })
    .catch((err) => {
      console.log(err);
    });
    this.auth.login(sampleUser).then((user) => {
      console.log(user.json());
    })
    .catch((err) => {
      console.log(err);
    });
  }
}

Refresh http://localhost:4200/login in the browser and you should see a success in the JavaScript console, after the user is logged in, with the token:

1
2
3
4
5
{
  "auth_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1M…jozfQ.bPNQb3C98yyNe0LDyl1Bfkp0Btn15QyMxZnBoE9RQMI",
  "message": "Successfully logged in.",
  "status": "success"
}

Auth Login

Update login.component.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="row">
  <div class="col-md-4">
    <h1>Login</h1>
    <hr><br>
    <form (ngSubmit)="onLogin()" novalidate>
     <div class="form-group">
       <label for="email">Email</label>
       <input type="text" class="form-control" id="email" placeholder="enter email" [(ngModel)]="user.email" name="email" required>
     </div>
     <div class="form-group">
       <label for="password">Password</label>
       <input type="password" class="form-control" id="password" placeholder="enter password" [(ngModel)]="user.password" name="password" required>
     </div>
     <button type="submit" class="btn btn-default">Submit</button>
    </form>
  </div>
</div>

Take note of the form. We used the [(ngModel)] directive on each of the form inputs to capture those values in the controller. Also, when the form is submitted, the ngSubmit directive handles the event by firing the onLogin() method.

Now, let’s update the component code, adding in onLogin():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Component } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { User } from '../../models/user';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  user: User = new User();
  constructor(private auth: AuthService) {}
  onLogin(): void {
    this.auth.login(this.user)
    .then((user) => {
      console.log(user.json());
    })
    .catch((err) => {
      console.log(err);
    });
  }
}

If you have the Angular web server running, you should see the error Cannot find module '../../models/user' in the browser. Before our code will work, we need to create a User model.

1
$ ng generate class models/user

Update src/app/models/user.ts:

1
2
3
export class User {
  constructor(email?: string, password?: string) {}
}

Our User model has two properties, email and password. The ? character is a special operator that indicates that initializing User with explicit email and password values is optional. This is equivalent to the following class in Python:

1
2
3
4
class User(object):
    def __init__(self, email=None, password=None):
        self.email = email
        self.password = password

Don’t forget to update auth.service.ts to use the new object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import { User } from '../models/user';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class AuthService {
  private BASE_URL: string = 'http://localhost:5000/auth';
  private headers: Headers = new Headers({'Content-Type': 'application/json'});
  constructor(private http: Http) {}
  login(user: User): Promise<any> {
    let url: string = `${this.BASE_URL}/login`;
    return this.http.post(url, user, {headers: this.headers}).toPromise();
  }
  register(user: User): Promise<any> {
    let url: string = `${this.BASE_URL}/register`;
    return this.http.post(url, user, {headers: this.headers}).toPromise();
  }
}

One last thing. We need to import the FormsModule in the app.module.ts file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { AuthService } from './services/auth.service';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    HttpModule,
    FormsModule,
    RouterModule.forRoot([
      { path: 'login', component: LoginComponent }
    ])
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})

export class AppModule { }

So, when the form is submitted, we capture the email and password and pass them to the login() method on the service.

Test this out with-

  • email: michael@realpython.com
  • password: michael

Again, you should see a success in the javaScript console with the token.

Auth Register

Just like for the login functionality, we need to add a component for registering a user. Start by generating a new Register component:

1
$ ng generate component components/register

Update src/app/components/register/register.component.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="row">
  <div class="col-md-4">
    <h1>Register</h1>
    <hr><br>
    <form (ngSubmit)="onRegister()" novalidate>
     <div class="form-group">
       <label for="email">Email</label>
       <input type="text" class="form-control" id="email" placeholder="enter email" [(ngModel)]="user.email" name="email" required>
     </div>
     <div class="form-group">
       <label for="password">Password</label>
       <input type="password" class="form-control" id="password" placeholder="enter password" [(ngModel)]="user.password" name="password" required>
     </div>
     <button type="submit" class="btn btn-default">Submit</button>
    </form>
  </div>
</div>

Then, update src/app/components/register/register.component.ts as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Component } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { User } from '../../models/user';

@Component({
  selector: 'register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent {
  user: User = new User();
  constructor(private auth: AuthService) {}
  onRegister(): void {
    this.auth.register(this.user)
    .then((user) => {
      console.log(user.json());
    })
    .catch((err) => {
      console.log(err);
    });
  }
}

Add a new route handler to the app.module.ts file:

1
2
3
4
RouterModule.forRoot([
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent }
])

Test it out by registering a new user!

Local Storage

Next, let’s add the token to Local Storage for persistence by replacing the console.log(user.json()); with localStorage.setItem('token', user.data.token); in src/app/components/login/login.component.ts:

1
2
3
4
5
6
7
8
9
onLogin(): void {
  this.auth.login(this.user)
  .then((user) => {
    localStorage.setItem('token', user.json().auth_token);
  })
  .catch((err) => {
    console.log(err);
  });
}

Do the same within src/app/components/register/register.component.ts:

1
2
3
4
5
6
7
8
9
onRegister(): void {
  this.auth.register(this.user)
  .then((user) => {
    localStorage.setItem('token', user.json().auth_token);
  })
  .catch((err) => {
    console.log(err);
  });
}

As long as that token is present, the user can be considered logged in. And, when a user needs to make an AJAX request, that token can be used.

NOTE: Besides the token, you could also add the user id and email to Local Storage. You would just need to update the server-side to send back that info when a user logs in.

Test this out. Ensure that the token is present in Local Storage after you log in.

User Status

To test out login persistence, we can add a new view that verifies that the user is logged in and that the token is valid.

Add the following method to AuthService:

1
2
3
4
5
6
7
8
ensureAuthenticated(token): Promise<any> {
  let url: string = `${this.BASE_URL}/status`;
  let headers: Headers = new Headers({
    'Content-Type': 'application/json',
    Authorization: `Bearer ${token}`
  });
  return this.http.get(url, {headers: headers}).toPromise();
}

Take note of Authorization: 'Bearer ' + token. This is called a Bearer schema, which is sent along with the request. On the server, we are simply checking for the Authorization header, and then whether the token is valid. Can you find this code on the server-side?

Then, generate a new Status component:

1
$ ng generate component components/status

Create the HTML template, src/app/components/status/status.component.html:

1
2
3
4
5
6
7
<div class="row">
  <div class="col-md-4">
    <h1>User Status</h1>
    <hr><br>
    <p>Logged In? </p>
  </div>
</div>

And change the component code in src/app/components/status/status.component.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'status',
  templateUrl: './status.component.html',
  styleUrls: ['./status.component.css']
})
export class StatusComponent implements OnInit {
  isLoggedIn: boolean = false;
  constructor(private auth: AuthService) {}
  ngOnInit(): void {
    const token = localStorage.getItem('token');
    if (token) {
      this.auth.ensureAuthenticated(token)
      .then((user) => {
        console.log(user.json());
        if (user.json().status === 'success') {
          this.isLoggedIn = true;
        }
      })
      .catch((err) => {
        console.log(err);
      });
    }
  }
}

Finally, add a new route handler to the app.module.ts file:

1
2
3
4
5
RouterModule.forRoot([
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: 'status', component: StatusComponent }
])

Ready to test? Log in, and then navigate to http://localhost:4200/status. If there is a token in Local Storage, you should see:

1
2
3
4
{
  "message": "Signature expired. Please log in again.",
  "status": "fail"
}

Why? Well, if you dig deeper on the server-side, you will find that the token is only valid for 5 seconds in project/server/models.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def encode_auth_token(self, user_id):
    """
    Generates the Auth Token
    :return: string
    """
    try:
        payload = {
            'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=5),
            'iat': datetime.datetime.utcnow(),
            'sub': user_id
        }
        return jwt.encode(
            payload,
            app.config.get('SECRET_KEY'),
            algorithm='HS256'
        )
    except Exception as e:
        return e

Update this to 1 day:

1
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1, seconds=0)

And then test it again. You should now see something like:

1
2
3
4
5
6
7
8
9
{
  "data": {
    "admin": false,
    "email": "michael@realpython.com",
    "registered_on": "Sun, 13 Aug 2017 17:21:52 GMT",
    "user_id": 4
  },
  "status": "success"
}

Finally, let’s redirect to the status page after a user successfully registers or logs in. Update src/app/components/login/login.component.ts like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { User } from '../../models/user';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  user: User = new User();
  constructor(private router: Router, private auth: AuthService) {}
  onLogin(): void {
    this.auth.login(this.user)
    .then((user) => {
      localStorage.setItem('token', user.json().auth_token);
      this.router.navigateByUrl('/status');
    })
    .catch((err) => {
      console.log(err);
    });
  }
}

Then update src/app/components/register/register.component.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { User } from '../../models/user';

@Component({
  selector: 'register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent {
  user: User = new User();
  constructor(private router: Router, private auth: AuthService) {}
  onRegister(): void {
    this.auth.register(this.user)
    .then((user) => {
      localStorage.setItem('token', user.json().auth_token);
      this.router.navigateByUrl('/status');
    })
    .catch((err) => {
      console.log(err);
    });
  }
}

Test it out!

Route Restriction

Right now, all routes are open; so, regardless of whether a user is logged in or not, they they can access each route. Certain routes should be restricted if a user is not logged in, while other routes should be restricted if a user is logged in:

  1. / – no restrictions
  2. /login – restricted when logged in
  3. /register – restricted when logged in
  4. /status – restricted when not logged in

To achieve this, add either EnsureAuthenticated or LoginRedirect to each route, depending on whether you want to guide the user to the status view or the login view.

Start by creating two new services:

1
2
$ ng generate service services/ensure-authenticated
$ ng generate service services/login-redirect

Replace the code in the ensure-authenticated.service.ts file as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class EnsureAuthenticated implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}
  canActivate(): boolean {
    if (localStorage.getItem('token')) {
      return true;
    }
    else {
      this.router.navigateByUrl('/login');
      return false;
    }
  }
}

And replace the code in the login-redirect.service.ts like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class LoginRedirect implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}
  canActivate(): boolean {
    if (localStorage.getItem('token')) {
      this.router.navigateByUrl('/status');
      return false;
    }
    else {
      return true;
    }
  }
}

Finally, update the app.module.ts file to import and configure the new services:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { AuthService } from './services/auth.service';
import { RegisterComponent } from './components/register/register.component';
import { StatusComponent } from './components/status/status.component';
import { EnsureAuthenticated } from './services/ensure-authenticated.service';
import { LoginRedirect } from './services/login-redirect.service';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    RegisterComponent,
    StatusComponent,
  ],
  imports: [
    BrowserModule,
    HttpModule,
    FormsModule,
    RouterModule.forRoot([
      {
        path: 'login',
        component: LoginComponent,
        canActivate: [LoginRedirect]
      },
      {
        path: 'register',
        component: RegisterComponent,
        canActivate: [LoginRedirect]
      },
      {
        path: 'status',
        component: StatusComponent,
        canActivate:
        [EnsureAuthenticated]
      }
    ])
  ],
  providers: [
    AuthService,
    EnsureAuthenticated,
    LoginRedirect
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

Note how we are adding our services to a new route property, canActivate. The routing system uses the services in the canActivate array to determine whether to display the requested URL path. If the route has LoginRedirect and the user is already logged in, then they will be redirected to the status view. Including the EnsureAuthenticated service redirects the user to the login view if they attempt to access a URL that requires authentication.

Test one last time.

What’s Next?

In this tutorial, we went through the process of adding authentication to an Angular 4 + Flask app using JSON Web Tokens.

What’s next?

Try switching out the Flask back-end for a different web framework, like Django or Bottle, using the following endpoints:

  • /auth/register
  • /auth/login
  • /auth/logout
  • /auth/user

Add questions and/or comments below. Grab the final code from the angular4-auth repo.