How to create your own RecyclerView - Android
~Currently Editing~
~Currently Editing~
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.
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>
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.
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 farts.
This Rock, Paper, Scissors tutorial was made using the ‘random’ module package from the python standard library and is played using the terminal.
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.
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!
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()
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')