lauren marie Software Engineer Highly adaptable and process driven

How to create your own RecyclerView - Android

~Currently Editing~

How to create login/registration authentication in Spring

Dependencies Link

  • Create a User model.

    Users should have attributes for any field that users have a relationship with
    At the very minimum, they need a User Name or E-mail to login with and a User Password
    For a better user experience, a Password Confirmation member variable should exist on creation
    The Password Confrimaton will NOT be stored in our database.

In order to create a User model that requires users to confirm their password on user creation, but who’s password confirmation is not stored in the databse at the time of serialization we can use the @Transient variables modifier.

Our User model should look something like this:

@Entity
@Table(name="users")
public class User {
 @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Size(min = 5, max = 100)
    private String email;
    @Size(min = 5, max = 100)
    private String password;
    @Transient
    private String passwordConfirmation;
    @Column(updatable=false)
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createdAt;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date updatedAt;
}

I will go over using regex to validate user email address in another post.

Once the User model is set up with its proper constructors and getters and setters, and we’ve initialized our User repository to extend CrudRepository we can move onto the service file of our application.

The Service file is important, because this is where we are going to actually decide how our information looks when we pass it into our databse. We will be using BCrypt to store User Passwords.

The most important thing to remember when dealing with login/registration is to never store a password in raw plain text.

We can use BCrypt on user registration by first hashing the password, and then storing that hashed String as the password for the user before saving it to our database.

   public User registerUser(User user) {
        String hashed = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt());
        user.setPassword(hashed);
        return userRepository.save(user);
    }

For logging in, we need to check the password inputted into our login form against our stored hashed password for the User. We can do this in a boolean where we return true if the user logged in successfully, or false if we were unable to match the information provided to any users in our databse.

It’s a good idea to check if the email exists, and if it doesn’t return false before we check the password. Why would we check if a password matches an email if we don’t even have the email in our collection?

   public boolean authenticateUser(String email, String password) {
        User user = userRepository.findByEmail(email);
        if(user == null) {
            return false;
        } else {
            return BCrypt.checkpw(password, user.getPassword()) ? true : false;
        }
    }

All the logic officially exists for user login and registration! Now, it’s time to hook up our authenticator to the rest of our application by connecting it to the front end with some jsp forms. In our User controller, we can reference our service file to check validity of inputted information when logging in as well as hashing the password string we store on registration. It is also a good idea to store our user to the session for easy access across all of our views upon successful login or registration.

Handy Dandy Spring Dependencies for Pom

Project Dependencies:

spring-boot-starter-jpa
spring-boot-starter-web
devtools (optional)
mysql-connector-java (runtime)
tomcat-embed-jasper
jstl
jbcrypt

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mindrot</groupId>
            <artifactId>jbcrypt</artifactId>
            <version>0.4</version>
        </dependency>

How to Basic MERN Setup

This part of the tutorial sets up a beginning file structure skeleton for your entire project, but is focused on the relationship between your Express server and MongoDB. If after using this tutorial you want to check out my basic React setup tutorial, check out the link at the bottom of this page that will take you to that post.

Before starting any actual programming, create a project folder that will house the server and the client. Now it’s time to create our client.

  • The client is our React app
  • Our server will be the Mongoose/Express portion of the project.

Inside of the terminal we can run the following commands to set up front end dependencies. Make sure you are inside of the project folder:

npx create-react-app client
cd my-app
npm start
npm i @reach/router

For our back end dependencies, we should first create a server folder inside of the project folder at the same level as our client. After navigating into the server folder from the terminal, we should first create our Server.js file that will live at the root of the server folder. While in the server folder, we can run the following commands to set up mongoose and express.:

npm i mongoose express cors
npm init -y

Before going further, it’s a good idea to set up the express server. Using cors allows us to have different domains for our server and client that can still communicate restricted resources to each other.

Setting the app to have json spaces, makes our json pretty and easily readable without having to use an external json parser.

server.js

const express = require("express");
const cors = require('cors');
const app = express();
app.set('json spaces', 4)
app.use(cors())

// This will fire our mongoose.connect statement to initialize our database connection
require("../server/config/mongoose.config");

app.use(express.json(), express.urlencoded({ extended: true }));

// This is where we import the users routes function from our user.routes.js file
const AllMyFooRoutes = require("../server/routes/Foos.routes");
AllMyFooRoutes(app);

app.listen(8000, () => console.log("The server is all fired up on port 8000"));

For the server a solid file structure is having a config folder, models, controllers, and routes folder. Inside of each of the appropriate folders will be the config settings/models/controllers/routes files.

Setting up mongoose is easy, and using it gives us access to a lot of really handy ways to interact with our MongoDB using JavaScript.

Here is a sample conection

(mongoose.config.js)

const mongoose = require("mongoose");

mongoose.connect("mongodb://localhost/foos", {
    useNewUrlParser: true,
    useUnifiedTopology: true,
})
    .then(() => console.log("Established a connection to the database"))
    .catch(err => console.log("Something went wrong when connecting to the database", err));

Inside of the models folder, we can create any models that we want to keep track of. For the purpose of this exercise, let’s just create a model for ‘foo’. Let’s give ‘foo’ a title, price, and description in the schema just to have a few different input fields to work with.

(foo.model.js)

const mongoose = require("mongoose");

const FooSchema = new mongoose.Schema({
    title: "",
    price: "",
    description: ""
});

const Foo = mongoose.model("Foo", FooSchema);

module.exports = Foo;

We can use our controller to handle any CRUD communications we want to perform on the database.

(foo.controller.js)

const Foo = require("../models/foo.model");


module.exports.createNewFoo = (req, res) => {
    Foo.create(req.body)
        .then(newlyCreatedFoo => res.json({ Foo : newlyCreatedFoo }))
        .catch(err => res.json({ message: "Something went wrong", error: err }));
};
module.exports.findAllFoos = (req, res) => {
    Foo.find()
        .then(allFoos => res.json({ Foos: allFoos }))
        .catch(err => res.json({ message: "Something went wrong", error: err }));
};

module.exports.findOneSingleFoo = (req, res) => {
    Foo.findOne({ _id: req.params.id })
        .then(oneSingleFoo => res.json({ Foo: oneSingleFoo }))
        .catch(err => res.json({ message: "Something went wrong", error: err }));
};
module.exports.updateExistingFoo = (req, res) => {
    Foo.findOneAndUpdate({ _id: req.params.id }, req.body, { new: true })
        .then(updatedFoo => res.json({ Foo: updatedFoo }))
        .catch(err => res.json({ message: "Something went wrong", error: err }));
};
module.exports.deleteAnExistingFoo = (req, res) => {
    Foo.deleteOne({ _id: req.params.id })
        .then(result => res.json({ result: result }))
        .catch(err => res.json({ message: "Something went wrong", error: err }));
};

Finally, we can create our api end points so that we can access our API from the front end or an API development tool like Postman.

(Foos.routes.js)

const FooController = require("../controllers/Foos.controller");

module.exports = app => {
    app.get("/api/Foos/", FooController.findAllFoos);
    app.post("/api/Foos/new", FooController.createNewFoo);
    app.get("/api/Foos/:id", FooController.findOneSingleFoo);
    app.put("/api/Foos/update/:id", FooController.updateExistingFoo);
    app.delete("/api/Foos/delete/:id", FooController.deleteAnExistingFoo);
};

That’s it for our server! Now we can move onto our front end, and deciding how we want to display our information in our views. I am writing another post which goes into a basic front end set up more in depth.

Art how you want to

art farts.

Simple Rock, Paper, Scissors

This Rock, Paper, Scissors tutorial was made using the ‘random’ module package from the python standard library and is played using the terminal.

  • Working out the logic of who wins what is a good first step, since everything about this games logic will use it.
    1. rock wins scissors
    2. paper wins rock
    3. scissors wins paper
  • It’s also a good idea to create a boolean where we keep track of the running state of the game, to easily replay the game without relaunching.
print("Welcome to Rock, Paper, Scissors!")

running = False

def did_win(computer_choice, user_choice):
    if user_choice == "rock" and computer_choice == "scissors":
        return True
    elif user_choice == "scissors" and computer_choice == "paper":
        return True
    elif user_choice == "paper" and computer_choice == "rock":
        return True
    return False

Now that our game knows the underlying logic, we can build out the rest.

  • keeping an array that stores all of the possible options is a great way to save space, we know which word is at which index so we
def gameplay():
    # play options :
    options = ["rock", "paper", "scissors"]
    # make computer choose randomly
    computer_choice = random.choice(options)

    user_choice = input("Type your choice: ROCK, PAPER or SCISSORS")
    user_choice = user_choice.lower()

    if computer_choice == user_choice:
        print("ITS A TIE!")
        replay()
    elif did_win(computer_choice, user_choice):
        print("YOU WON")
        print("Computer Choice: " + computer_choice)
        print("Your Choice: " + user_choice)
        replay()
    else:
        print("YOU LOST!")
        print("Computer Choice: " + computer_choice)
        print("Your Choice: " + user_choice)
        replay()

At the end of all of this, we can make use of our running boolean and choose whether or not to replay the game.

def yesno():
    global running
    if response == "y":
        running = True
    elif response == "n":
        print("GOODBYE")
        sys.exit()
    else:
        print("Enter either Y or N")

def replay():
    global response
    response = input("Do you want to play again? (Y/N)?")
    yesno()

Finally, with all of the logic in place and working we can initialize a game. Because we created a different response on startup than on replay we should also let the program know which one to call first. Time to wrap up our program!

def initial():
    global running
    global response
    response = input("Would you like to play a game? (Y/N)")
    response = response.lower()
    yesno()

Start/Stop Gameplay:

while True:
    if running:
        gameplay()
    else:
        initial()

Run your python script in your terminal, and play until you are satisfied with the results!

URL Shortener

This is a very basic URL shortener program that utilizes the pyshorteners Python library to access TinyUrl from your terminal.

A URL shortener is useful when dealing with long links, and the pyshorteners API wrapper is a really simple way to do that. Another cool feature of utilizing Shortener is that we can also expand URL’s that were previously shortened.

from pyshorteners import Shortener

class Shortening:
    shortener = Shortener('Tinyurl')

    def shortenURL(self):
        self.url = input("Enter the URL you would like to shorten: ")
        shortURL = self.shortener.short(self.url)
        print("Your new URL is: " + shortURL)

    def decodeURL(self):
        self.url = input("Enter the URL you would like to expand: ")
        longURL = self.shortener.expand(self.url)
        print("Your new URL is: " + longURL)

app = Shortening()

app.shortenURL()

Social Media Interactions - Django

On brand with the python groove I have been in, I thought it would be neat to have a simple user log in/registration with validations in my arsenal.

I put the log in/validation in a simple post/message board application I built using python/django and used bcrypt to encrypt user passwords.

First I created my models.

(models.py)

class User(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    email = models.CharField(max_length=255)
    password = models.CharField(max_length=45)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    objects = UserManager()


class Message(models.Model):
    user = models.ForeignKey(User, related_name="messages", default=None, on_delete=models.CASCADE)
    message_text = models.CharField(max_length=255, default=None)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class Comment(models.Model):
    comment_text = models.CharField(max_length=255, default=None)
    messages = models.ForeignKey(Message, related_name="comments", default=None, on_delete=models.CASCADE)
    users = models.ForeignKey(User, related_name="comments", default=None, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

after that, I created my UserManager which housed my validators

(models.py)

class UserManager(models.Manager):
    def basic_validator(self, postData):
        EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+$')
        errors = {}
        if len(postData['first_name']) < 2:
            errors['first_name'] = "First name should be at least 2 characters long!"
        if len(postData['last_name']) < 2:
            errors['last_name'] = "Last name should be at least 2 characters long!"
        if User.objects.filter(email=postData['email']).exists():
            errors['email'] = "Email should be unique!"
        if not EMAIL_REGEX.match(postData['email']):  # test whether a field matches the pattern
            errors['email_makes_sense'] = "Invalid email address!"
        if len(postData['password']) < 8:
            errors['pw_length'] = "Passwords should be at least 8 characters long!"
        if postData['password'] != postData['password_confirm']:
            errors['pw_confirm'] = "Your passwords need to match!"
        return errors

    def basic_validator2(self, postData):
        EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+$')
        errors = {}
        if not User.objects.filter(email=postData['email']).exists():
            errors['email'] = "Email not in db!"
        if not EMAIL_REGEX.match(postData['email']):  # test whether a field matches the pattern
            errors['email_makes_sense'] = "Invalid email address!"
        this_user = User.objects.get(email=postData['email'])
        check_it = bcrypt.checkpw(postData['password'].encode(), this_user.password.encode())
        if check_it is False:
            errors['password'] = "you typed the wrong password!"
        return errors

Made sure to create some simple and descriptive url paths to use on the front end

(urls.py)

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
    path('register_user', views.register_user),
    path('login', views.login),
    path('wall', views.wall),
    path('logout', views.logout),
    path('post_message', views.post_message),
    path('post_comment', views.post_comment),
    path('delete_message', views.delete_message),
]

Finally, I hooked up my urls to their views

(views.py)

def index(request):
    return render(request, 'index.html')


def register_user(request):
    errors = User.objects.basic_validator(request.POST)
    if len(errors) > 0:
        for key, value in errors.items():
            messages.error(request, value)
        return redirect('/')
    else:
        hash1 = bcrypt.hashpw(request.POST['password'].encode(), bcrypt.gensalt()).decode()
        print(hash1)
        c = User.objects.create(first_name=request.POST['first_name'], last_name=request.POST['last_name'],
                                email=request.POST['email'], password=hash1)
        c.save()
        request.session['this_user'] = c.id
        request.session['right_message'] = "Successfully created a new account!"
        return redirect('/wall')


def login(request):
    errors = User.objects.basic_validator2(request.POST)
    if len(errors) > 0:
        for key, value in errors.items():
            messages.error(request, value)
        return redirect('/')
    else:
        getting_something = User.objects.get(email=request.POST['email'])
        request.session['this_user'] = getting_something.id
        request.session['right_message'] = "Successfully logged in!"
        return redirect('/wall')


def wall(request):
    this_message = request.session['right_message']

    context = {
        'users': User.objects.all(),
        'user': User.objects.get(id=request.session['this_user']),
        'message': this_message,
        'message_list': reversed(Message.objects.all())
    }
    return render(request, 'wall.html', context)


def logout(request):
    request.session.flush()
    return redirect('/')


def post_message(request):
    c = Message.objects.create(user_id=request.session['this_user'], message_text=request.POST['message_content'])
    c.save()
    return redirect('/wall')

def post_comment(request):
    c = Comment.objects.create(messages_id=request.POST['post_it'], users_id=request.session['this_user'], comment_text=request.POST['comment_content'])
    c.save()
    return redirect('/wall')

def delete_message(request):
    this_message = request.POST['delete_it']
    c = Message.objects.get(id=this_message)
    c.delete()
    return redirect('/wall')