Gain Concealed Carry Confidence…From Home

Gain Concealed Carry Confidence…From Home

https://ift.tt/38mEaAQ

I remember the very first time I put a gun in a holster on my hip. 

In short, I was terrified

Concealed Carry Tugging at Shirt
Ohh the familiar “tugging on the shirt because you’re terrified someone knows you have a gun” move.

It took me a couple of months after taking my concealed carry course before I felt truly ready to head out into public with my little Walther P22 strapped to my hip.

And I’m not the only gun owner to feel the nerves when it comes time to leave the house with a gun. 

It’s a very common feeling to be unsure and even insecure with the thought of carrying when you’re new to the process. 

Nervous
Yeah, we’ve been there.

But that’s why you have us, friends. 

We’re here to pass on some tips to get you feeling confident and secure with your concealed carry setup.

Help

We’ll talk about the importance of training (and where you can score some free courses), as well as how to do some things at home to help ease your fear. 

So let’s get you ready to concealed carry

If you’re looking for even more insight, check out Brownells Daily Defense video with Jeff Gonzales below

Tips for Confident Concealed Carry

1. Get Training

Ok, so admittedly, this part might require you to leave home, but training is an essential part of the concealed carry equation. 

If all you take is one state-approved CCW course, you’re likely not going to walk away with a ton of confidence.

Training with a RE Factor Kill Zone
Training is a great way to gain confidence.

Depending on the class, you might walk away with even more questions bouncing around your head. 

So, if you can, sign up for another class geared towards concealed carry.

The more training you receive and the more hours you put in the classroom and on the range, the more confidence you’ll gain in your decision-making and skills. 

8. Dry Fire Mag Mantis X App
Not all your training has to be outside the home. Dry fire tools can help work on fundamentals at home.

All of this translates into how you carry yourself in the real world with a gun strapped to you. 

Bonus, you can totally explore concealed carry concepts and expert advice at home with programs like the USCCA.

Eric did a full review of the different tiers and which tier gets you the most FREE courses!

USCCA Proving Ground, Aftermath
USCCA Proving Ground — an awesome resource!

2. Check Your Guns + Gear

Next, you’ll want to take stock of the guns and gear you have at your disposal. 

Your carry setup can make or break your mindset, especially if you’re feeling iffy about everything. So, evaluate your CCW gun, holster, and belt. 

Concealed Carry Glock 19, Belt, Holster
Concealed Carry Glock 19, Belt, Holster

First, determine if your gun really works for you.

The handgun you chose for home defense might do great in a bedside safe…but may not perform so well in a holster.

Look at what guns you have, and don’t be afraid to step down to a smaller model if you need to.

S&W M&P Shield EZ shooting
Nothing wrong with a smaller gun.

(See our suggestions for great concealed carry models handguns.)

There’s nothing wrong with carrying a .380 ACP Sig Sauer P238, Ruger LCP, or a 9mm Smith & Wesson if that’s all you feel you can reasonably conceal. 

Concealed Carry Guns
Concealed Carry Guns (L to R: Gen 4. Glock G19, Smith & Wesson Shield, Sig Sauer P238)

Alternatively, if a Glock 19 feels the best — go for it! 

On a similar note, you want to make sure your holster and belt combo is set up for success. While most people do not want to invest $100 in a concealed carry belt, it’s worth shopping around a bit and finding a quality one. 

By that, I mean a belt that is rigid enough to support the weight of a holster and gun. 

Concealed Carry Holster Belt Gun
Volund Gearworks Atlas Belt, Dark Star Gear Orion Holster, Glock 19. All these work together to hold the gun in place.

Need recommendations? We have some in our Best Belts for Concealed Carry and the Range. 

And finally, choose a quality holster that provides adequate protection for the gun while also offering access to the gun should you need it. 

Holsters don’t have to be uncomfortable, but you should definitely prioritize safety and retention. 

Concealed Carry Gun in Holster
Your holster should keep the gun nice and safe.

There are plenty of great options on the market! 

But if you need holster inspiration, check out our list of the Best Concealed Carry Holsters.  

3. Carry Around the House

Once you have your setup narrowed down, it’s time to practice

The first time you suit up with a gun, it can feel…well, weird. You might not feel immediately ready to head to Target, and that’s ok. 

Wearing your gun around the house is a great place to start to build that confidence, learn your gear, and familiarize yourself with concealed carry. 

Concealed Carry Around House
Wearing your gun while you do housework will help you get accustomed to it. (Psst, there’s a Glock 19 hiding under there.)

Heck, I’ve been doing this for over 10 years, and I still like to try new outfits out at home before taking them into the wild.

It’s a great testing ground to see what works and doesn’t. 

So, pop that holster and unloaded gun on and take it for a test ride while you do laundry, cook dinner, or just hang.

Concealed Carry Around House
Sometimes me and the G19 like to just take a reading break.

You’ll quickly start to identify the quirks of your system and how to address them. 

4. Get Input from Friends

Once you feel pretty confident wearing your gun around the house, there’s one more step to take before going into public. Get your friends’ input

Ask trusted friends and family to take a look at some outfits you intend to wear. 

Concealed Carry Around House
Call some friends over to take a look at your outfit. They’ll be able to spot any issues.

They’re a great judge of a) your behavior and whether you’re concealing your intentions and b) the clothes you want to pair with your CCW rig.

While standing in front of a mirror can help you pinpoint some problem areas, you can’t see a full 360 view like your friends or family can. So, ask for help! 

Concealed Carry Mirror
Yes, a mirror works too, but you might miss something on your own.

Conclusion

Concealed carry is practical, but it’s also an art form. Learning how to do it and do it well takes time and practice. (Not to mention lots of trial and error.) 

Womens Brands Alexo Athletica Skirt
Get trained and get to know your gear.

Getting trained, carrying at home, evaluating your gear, and employing friends’ help will help you work towards a more confident concealed carry experience. 

Ready to learn more? Peep Brownells Daily Defense video with Jeff Gonzales below for more tips.

Do you have any at-home tips for better concealed carry? Let us know in the comments below. For even more concealed carry content, check out our Definitive Guide to Concealed Carry

The post Gain Concealed Carry Confidence…From Home appeared first on Pew Pew Tactical.

guns

via Pew Pew Tactical https://ift.tt/2m7cc0U

March 8, 2021 at 06:43PM

Laravel Tutorial: Step by Step Guide to Building Your First Laravel Application

Laravel Tutorial: Step by Step Guide to Building Your First Laravel Application

https://ift.tt/2mS5E8j


Since its initial release in 2011, Laravel has experienced exponential growth. In 2015, it became the most starred PHP framework on GitHub and rose to the go-to framework for people all over the world.

Laravel focuses on the end-user first: which means it focus is on simplicity, clarity, and getting work done. People and companies are using it to build everything from simple hobby projects all the way to Fortune 500 companies.

My goal with this Laravel tutorial to create a guide for those just learning Laravel. This guide will take you from the very beginning of an idea into a real deployable application. If you’d prefer to read this as an ebook you can join our weekly Laravel Newsletter and get it for free.

This look at Laravel will not be exhaustive, but if you want a more exhaustive introduction I recommend the book Laravel: Up and Running. This tutorial does expect a few prerequisites and here is what you will need to follow along:

  • A local PHP environment (Valet, Homestead, Vagrant, MAMP, etc.).
  • A database (I’ll be using MySQL)
  • PHPUnit installed.
  • Node JS installed.

Note: For the local PHP development I Recommend Mac OSX and Valet because it automatically sets everything up. If you are on Windows, consider Homestead or some flavor of a virtual machine. Another option is a community-provided Windows port of Valet.

I am attempting to go through the process of creating a new application just as I would in a real-world environment. In fact, the code and idea are from a project I built.

Planning

Every project has to start somewhere; either a project assignment at work or just an idea in your head. No matter where it originates, thoroughly planning out all the features before you start coding is paramount in completing a project.

How you plan is dependent on how your mind works. As a visual person, I like to plan on paper, drawing out the way I picture the screens looking and then working backward into how I would code it. Others prefer to write a project plan in a text file, wiki, or some mind mapping tool. It doesn’t matter how you plan, just that you do it.

For this guide, we are going to be building a link directory. Here is a list of fundamental goals for this links app:

  1. Display a simple list of links.
  2. Create a form where people can submit new links.
  3. Validate the form.
  4. Insert the data into the database.

Let’s get started!

The First Steps

With a simple plan of attack outlined, it’s time to get a brand new empty project up and running. I like to put all my projects in a ~/Sites directory, and these instructions will use that location. I’ve already “parked” this directory in Valet, so any folders will automatically be mapped to “foldername.test” in the browser.

Open your terminal application and switch into this directory.

mkdir ~/Sites
cd ~/Sites

Laravel provides a convenient installer. If you’re planning on writing Laravel apps, follow the installation documentation for details on setting up the installer.

Whether you set up the installer or want to use composer, run one of the following to create a new Laravel project for the links application:

# Via the installer
laravel new links

# Via composer
composer create-project --prefer-dist laravel/laravel links "7.*"

This will create a new directory at ~/Sites/links and install a new Laravel project.

Visiting links.test in the browser now shows the default Laravel welcome page:

Database Setup

When you create a new Laravel project, the installation process automatically creates a .env file (copied from the .env.example file) for configuration and credentials. Depending on your setup, you’ll need to modify the following block of settings to match your database configuration:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

You may want to create a new database for this project:

# Connect via the mysql CLI
mysql -u root -p
mysql> create database links_development;
mysql> exit

# Or use the -e flag to run the create command
mysql -u root -e'create database links_development'

You would then want to adjust the database configuration in .env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=links_development
DB_USERNAME=root
DB_PASSWORD=

The best way to test your database connection is running the migrate artisan command:

php artisan migrate

If everything went according to plan, you should see something like the following after running the migrate command:

Authentication Scaffolding

Laravel has a separate first-party package for generating common scaffolding that makes setting up authentication a breeze. To use it, we need to install the UI composer package:

composer install laravel/ui

The UI package provides a few commands for setting up scaffolding for tools like React, Vue, and Bootstrap. We’ll create simple auth scaffolding for this project, but feel free to follow the frontend setup documentation.

Run the following to generate routes, controllers, views, and other files necessary for auth:

php artisan ui bootstrap --auth

Last, we need to compile our CSS UI with the following:

npm install

# Build dev assets
npm run dev

# Or use a watcher to automatically update changes
npm run watch

The watch command will listen for files changes to JS and CSS files, and automatically update them. You probably want to have npm run watch running in a separate tab while developing.

Even though this tutorial will not dive into authentication by running this command, it will modify our views and routes. So by doing it early, we don’t have to worry about it messing with any of our code.

With the basics set up and working, it’s time to start doing some coding.

Building a List of Links

If you start thinking about a finished project, it’s easy to get overwhelmed. The best way to fight this is to break the project down into small tasks. So, let’s start by showing a list of links.

Even though showing a list of links sounds like a small task it still requires a database, a database table, data in the table, a database query, and a view file.

Creating a migration will be the first step, and the Laravel Artisan command line tool can help us build that.

php artisan make:migration create_links_table --create=links

Now, open the file this command created. It will be located at database/migrations/_create_links_table.php. You’ll notice a few other migrations in this folder as well, which the framework provides.

Inside the “up()” method, add the following schema:

Schema::create('links', function (Blueprint $table) {
      $table->increments('id');
      $table->string('title');
      $table->string('url')->unique();
      $table->text('description');
      $table->timestamps();
});

Save the file and run the migration:

php artisan migrate

While you are working with test data, you can quickly apply the schema:

php artisan migrate:fresh

Next, we need some data and a model to work with our database table. Laravel provides two features to help with this, the first is a database seeder, which populates the database with data, and second, the model factory files that allow us to generate fake model data that we can use to fill our development database and tests:

php artisan make:model --factory Link

The make:model command creates an app/Link.php model file. Laravel models provide a powerful database API called Eloquent, which you can explore in great detail in the Eloquent documentation.

The --factory flag will generate a new factory file in the database/factories path for generating app data. In our case, a new LinkFactory file will include an empty factory definition for our Link model.

Open the LinkFactory.php file and fill in the following:

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Link;
use Faker\Generator as Faker;

$factory->define(Link::class, function (Faker $faker) {
    return [
        'title' => substr($faker->sentence(2), 0, -1),
        'url' => $faker->url,
        'description' => $faker->paragraph,
    ];
});

We use the $faker->sentence() method to generate a title, and substr to remove the period at the end of the sentence.

Next, create the link seeder, so we can easily add demo data to the table:

php artisan make:seeder LinksTableSeeder

The make:seeder command generates a new database class to seed our links table with data.

Open the database/seeds/LinksTableSeeder.php file and add the following:

public function run()
{
    factory(App\Link::class, 5)->create();
}

In order to “activate” the LinksTableSeeder, we need to call it from the main database/seeds/DatabaseSeeder.php run method:

public function run()
{
    $this->call(LinksTableSeeder::class);
}

You can now run the migrations and seeds to add data to the table automatically. Using the migrate:fresh command, we can get a clean schema that applies all migrations and then seeds the database:

$ php artisan migrate:fresh --seed
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2017_11_03_023418_create_links_table
Migrated:  2017_11_03_023418_create_links_table
Seeding: LinksTableSeeder

Using the tinker shell you can start playing around with the model data:

$ php artisan tinker
>>> \App\Link::first();
=> App\Link {#3060
     id: 1,
     title: "Rerum doloremque",
     url: "http://russel.info/suscipit-et-iste-debitis-beatae-repudiandae-eveniet.html",
     description: "Dolorem voluptas voluptatum voluptatem consequuntur amet dolore odit. Asperiores ullam alias vel soluta ut in. Facere quia et sit laudantium culpa ea possimus.",
     created_at: "2020-04-05 00:44:33",
     updated_at: "2020-04-05 00:44:33",
   }
>>>

We have the data place and a model to interact with the database! Let’s start building the UI to add new links to the application.

Routing and Views

To build out a view showing the list of links, we need to update the main project route and also define a new route that will display our submission form. We can add new routes to our application in the routes/web.php file.

In the web routes file you should see the default route below:

Route::get('/', function () {
    return view('welcome');
});

To create a new route, we can either use a route closure or a dedicated controller class. In this tutorial, we will use closures for our submission and index routes.

First, let’s update the home route by getting a collection of links from the database and passing them to the view:

Route::get('/', function () {
    $links = \App\Link::all();

    return view('welcome', ['links' => $links]);
});

The second argument can be an associative array of data, and the key ends up being the variable name in the template file.

You can also use a fluent API to define variables if you prefer:

// with()
return view('welcome')->with('links', $links);

// dynamic method to name the variable
return view('welcome')->withLinks($links);

Next, edit the welcome.blade.php file and add a simple foreach to show all the links:

@foreach ($links as $link)
    <a href=""></a>
@endforeach

Here’s what the welcome.blade.php HTML should look like:

<body>
    <div class="flex-center position-ref full-height">
        @if (Route::has('login'))
            <div class="top-right links">
                @auth
                    <a href="">Home</a>
                @else
                    <a href="">Login</a>
                    <a href="">Register</a>
                @endauth
            </div>
        @endif

        <div class="content">
            <div class="title m-b-md">
                Laravel
            </div>

            <div class="links">
                @foreach ($links as $link)
                    <a href=""></a>
                @endforeach
            </div>
        </div>
    </div>
</body>

If you refresh your browser, you should now see the list of all the links added. With that all set, let’s move to submitting links.

Displaying the Link Submission Form

We are almost done creating our first application in Laravel!

We will round out this Laravel tutorial with the ability for others to submit links into the app, which requires three fields: title, URL, and a description.

I am a visual person, and before planning out features requiring HTML, I like to draw them out so I can get an idea of what I’m building in my head. Here is a simple drawing of this form:

Since we’ve added all the core structure, model factory, migration, and model, in the last section, we can reap the benefits by reusing all those for this section.

First, create a new route in the routes/web.php file:

Route::get('/submit', function () {
    return view('submit');
});

Next, we need to create the submit.blade.php template at resources/views/submit.blade.php with the following boilerplate bootstrap markup:

@extends('layouts.app')
@section('content')
    <div class="container">
        <div class="row">
            <h1>Submit a link</h1>
        </div>
        <div class="row">
            <form action="/submit" method="post">
                @csrf
                @if ($errors->any())
                    <div class="alert alert-danger" role="alert">
                        Please fix the following errors
                    </div>
                @endif
                <div class="form-group">
                    <label for="title">Title</label>
                    <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" placeholder="Title" value="">
                    @error('title')
                        <div class="invalid-feedback"></div>
                    @enderror
                </div>
                <div class="form-group">
                    <label for="url">Url</label>
                    <input type="text" class="form-control @error('url') is-invalid @enderror" id="url" name="url" placeholder="URL" value="">
                    @error('url')
                        <div class="invalid-feedback"></div>
                    @enderror
                </div>
                <div class="form-group">
                    <label for="description">Description</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" id="description" name="description" placeholder="description"></textarea>
                    @error('description')
                        <div class="invalid-feedback"></div>
                    @enderror
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </form>
        </div>
    </div>
@endsection

There’s quite a bit going on in this form, so let’s go over the major points that might be confusing when you are new to Laravel.

Near the top of the form, we have a blade conditional that checks to see if there are any validation errors. When errors exist, the bootstrap alert message will be shown, prompting the user to fix the invalid form fields:

@if ($errors->any())
    <div class="alert alert-danger" role="alert">
        Please fix the following errors
    </div>
@endif

Each individual form field checks for validation errors and displays an error message and outputs a has-error class:

<div class="form-group">
    <label for="title">Title</label>
    <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" placeholder="Title" value="">
    @error('title')
        <div class="invalid-feedback"></div>
    @enderror
</div>

If the user submits invalid data, the route will store validation in the session and redirect the user back to the form. The function will populate the originally submitted data. If a user forgot to submit one of the fields, the other fields that have data would be populated after validation fails and errors are shown.

If a field has an error, the @error directive provides an error message variable you can use within the directive block:

@error('title')
    <div class="invalid-feedback"></div>
@enderror

Another way to check and dispay errors involves the $error variable provided to the view after a validation failure and redirect:

@if($errors->has('title'))
    <div class="invalid-feedback"></div>
@endif

The @error directive uses the same variable under the hood, feel free to use whichever method you prefer.

Submitting the Form

With the form in place, we are ready to handle sending and validating form data on the server. Back in the routes/web.php file, create another route for the POST request:

use Illuminate\Http\Request;

Route::post('/submit', function (Request $request) {
    $data = $request->validate([
        'title' => 'required|max:255',
        'url' => 'required|url|max:255',
        'description' => 'required|max:255',
    ]);

    $link = tap(new App\Link($data))->save();

    return redirect('/');
});

Note: make sure you add use Illuminate\Http\Request near the top of web.php.

This route is a little more complicated than the others.

First, we are injecting the Illuminate\Http\Request object, which holds the POST data and other data about the request.

Next, we use the request’s validate() method to validate the form data. The validate method was introduced in Laravel 5.5 and is a nice shortcut over other methods used for validation. As a bonus, the validated fields are returned to the $data variable, and we can use them to populate our model.

We require all three fields, and using the pipe character we can define multiple rules. All three rules can have a max of 255 characters, and the url field requires a valid URL.

If validation fails, an exception is thrown, and the route returns the user with the original input data and validation errors.

Next, we use the tap() helper function to create a new Link model instance and then save it. Using tap allows us to call save() and still return the model instance after the save.

Typically, you would have to do the following without tap, it just adds a little syntactic sugar:

$link = new \App\Link($data);
$link->save();

return $link;

If we want to populate a new model with data, we need to allow the fields to be “fillable” via mass assignment. The fillable property is designed to prevent fields from being mass-assigned except for the items you define in the array.

Think about this for a minute: we are taking user input from the request and mass assigning the values on the database model. Be aware of the dangers of user-submitted data and take care to guard against data you don’t intend the user to directly manipulate via a form.

In our case, we are validating each field so allowing them to be mass-assigned is safe. To allow our model to assign values to these fields, open the app/Link.php file and update it to look like the following:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Link extends Model
{
    protected $fillable = [
        'title',
        'url',
        'description'
    ];
}

If we wanted to avoid mass-assignment, this is how our code might look:

$data = $request->validate([
    'title' => 'required|max:255',
    'url' => 'required|url|max:255',
    'description' => 'required|max:255',
]);

$link = new \App\Link;
$link->title = $data['title'];
$link->url = $data['url'];
$link->description = $data['description'];

// Save the model
$link->save();

The last thing we do in our POST route redirects the user back to the home page after saving the link successfully.

At this point, our form should prevent submitting links with invalid fields:

If the form passes validation, the data should be saved in the database and the user redirect back to the homepage.

Testing the Form Submission

We have a basic working form, but we should make sure it continues to work by writing tests.

Laravel makes HTTP testing a breeze for performing integration tests against routes and middleware, so let’s write a few feature tests to verify our code works as expected.

Before we get started, we need to adjust a few things in our phpunit.xml file so that we can use an in-memory SQLite database. You will need to make sure that you have the proper PHP modules installed.

As of Laravel 7, the project’s phpunit.xml file configures an in-memory SQLite database. If you’re using an older version of Laravel, change the database connection by adding the following:

<php>
        <!-- ... -->
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
        <!-- ... -->
</php>

Next, remove the placeholder test that ships with Laravel:

rm tests/Feature/ExampleTest.php

We are ready to start testing the /submit form through HTTP requests to make sure that the route validation, saving, and redirecting are working as expected.

First, let’s create a new feature test to test against our route:

php artisan make:test SubmitLinksTest

The command creates a new testing file with the proper dependencies, including a RefreshDatabase trait that we are going to use to verify that our links are being saved to the database when valid.

Open the new tests/Feature/SubmitLinksTest.php file and let’s define a few skeleton tests in the body of the class that we are going to flesh out:

/** @test */
function guest_can_submit_a_new_link() {}

/** @test */
function link_is_not_created_if_validation_fails() {}

/** @test */
function link_is_not_created_with_an_invalid_url() {}

/** @test */
function max_length_fails_when_too_long() {}

/** @test */
function max_length_succeeds_when_under_max() {}

These tests should give you a high-level overview of what we are going to test:

  1. Verify that valid links get saved in the database
  2. When validation fails, links are not in the database
  3. Invalid URLs are not allowed
  4. Validation should fail when the fields are longer than the max:255 validation rule
  5. Validation should succeed when the fields are long enough according to max:255.

We might be missing some things, but for your first Laravel application, this is a decent list that should illustrate some basic HTTP testing techniques in Laravel.

Saving a valid link

The first test we’ll write is the test that verifies that valid data gets stored in the database:

<?php

namespace Tests\Feature;

use Illuminate\Validation\ValidationException;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class SubmitLinksTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    function guest_can_submit_a_new_link()
    {
        $response = $this->post('/submit', [
            'title' => 'Example Title',
            'url' => 'http://example.com',
            'description' => 'Example description.',
        ]);

        $this->assertDatabaseHas('links', [
            'title' => 'Example Title'
        ]);

        $response
            ->assertStatus(302)
            ->assertHeader('Location', url('/'));

        $this
            ->get('/')
            ->assertSee('Example Title');
    }
}

Take note of the RefreshDatabase trait which makes sure that each test has a new database to give each test a pristine database environment with all the migrations.

Our first test submits valid post data, which returns a response object that we can use to assert that our route responded as expected. We verify that the database contains a record with the title we just created.

Next, we verify that the response was a 302 status code with a Location header pointing to the homepage.

Last, we request the home page and verify that the link title is visible on the homepage.

Let’s run our first test to make sure things pass as expected. Laravel 7 adds a new artisan test command, or you can use phpunit:

php artisan test

# Or run phpunit directly
vendor/bin/phpunit

You should see that the test suite passes:

Testing Failed Validation

When a user generally submits bad data, we expect the validation to trigger an exception and we can use that to make sure our validation layer is working:

/** @test */
function link_is_not_created_if_validation_fails()
{
    $response = $this->post('/submit');

    $response->assertSessionHasErrors(['title', 'url', 'description']);
}

We use Laravel’s assertSessionHasErrors() to make sure that the session has validation errors for each of our required fields. Because we submitted empty data to the route, we expect the required rule will trigger for each field.

Let’s run the test suite to verify our work thus far:

$ php artisan test tests/Feature/SubmitLinksTest

   PASS  Tests\Feature\SubmitLinksTest
  ✓ guest can submit a new link
  ✓ link is not created if validation fails

  Tests:  2 passed
  Time:   0.32s

Testing URL Validation

We expect only valid URLs to pass validation so that our application doesn’t try to display invalid data.

/** @test */
function link_is_not_created_with_an_invalid_url()
{
    $this->withoutExceptionHandling();

    $cases = ['//invalid-url.com', '/invalid-url', 'foo.com'];

    foreach ($cases as $case) {
        try {
            $response = $this->post('/submit', [
                'title' => 'Example Title',
                'url' => $case,
                'description' => 'Example description',
            ]);
        } catch (ValidationException $e) {
            $this->assertEquals(
                'The url format is invalid.',
                $e->validator->errors()->first('url')
            );
            continue;
        }

        $this->fail("The URL $case passed validation when it should have failed.");
    }
}

Laravel has a withoutExceptionHandling() method which disables Laravel’s route exception handling code used to generate an HTTP response after an exception. We use this to our advantage so we can inspect the validation exception object and assert against the error messages.

We loop through various cases (add your own if you’d like to cover more scenarios) and catch instances of ValidationException. If the text makes it past the exception handling, we manually fail the test because we expect the route throws a ValidationExcepiton exception each time.

The catch block uses the validator object to check the url error and asserts that the actual error message matches the expected validation error message.

I like using the try/catch technique, followed by a $this->fail() as a safety harness instead of using exception annotations provided by PHPUnit. Be sure to return in the caught exception to avoid confusing test failures. I feel catching the exception allows the ability to do assertions that wouldn’t otherwise be possible and provides a more granular control that I like in most cases.

Testing Max Length Validation

We will test a few scenarios with the max:255 validations rules: when the field fails max-length validation with a length of 256 characters, and when the field is long enough to pass validation at 255 characters.

Although Laravel contains the max validation rule functionality, I like to test it to verify that my application applies the rules. If someone removes the max validation rule, then the tests will catch it.

I like to test the threshold of min and max validation rules as an extra caution to make sure my application respects the min and max boundaries I set.

First, let’s test the “max length” scenario:

/** @test */
function max_length_fails_when_too_long()
{
    $this->withoutExceptionHandling();

    $title = str_repeat('a', 256);
    $description = str_repeat('a', 256);
    $url = 'http://';
    $url .= str_repeat('a', 256 - strlen($url));

    try {
        $this->post('/submit', compact('title', 'url', 'description'));
    } catch(ValidationException $e) {
        $this->assertEquals(
            'The title may not be greater than 255 characters.',
            $e->validator->errors()->first('title')
        );

        $this->assertEquals(
            'The url may not be greater than 255 characters.',
            $e->validator->errors()->first('url')
        );

        $this->assertEquals(
            'The description may not be greater than 255 characters.',
            $e->validator->errors()->first('description')
        );

        return;
    }

    $this->fail('Max length should trigger a ValidationException');
}

Again, we disable exception handling and create data that is one character too long to pass validation.

We assert each field to make sure they all have a max length validation error message.

Last, we need to return in the caught exception and use the $this->fail() as a safety harness to fail the test.

Next, we test the “under the max” scenario:

/** @test */
function max_length_succeeds_when_under_max()
{
    $url = 'http://';
    $url .= str_repeat('a', 255 - strlen($url));

    $data = [
        'title' => str_repeat('a', 255),
        'url' => $url,
        'description' => str_repeat('a', 255),
    ];

    $this->post('/submit', $data);

    $this->assertDatabaseHas('links', $data);
}

We make the form data long enough to pass max:255 validation and assert that the data is in the database after submitting the data.

Run the test suite and make sure everything is passing:

$ php artisan test tests/Feature/SubmitLinksTest

   PASS  Tests\Feature\SubmitLinksTest
  ✓ guest can submit a new link
  ✓ link is not created if validation fails
  ✓ link is not created with an invalid url
  ✓ max length fails when too long
  ✓ max length succeeds when under max

  Tests:  5 passed
  Time:   0.58s

Conclusion

Congratulations on making it through the tutorial!

This guide was designed to get you started on building your app, and you can use this as a building block to gain the skills you need to develop your application. I know this covers a lot of features and can be overwhelming if you are not familiar with the framework.

I hope this introduction to Laravel shows you why so many people are excited about the framework.

Join the weekly newsletter and check out the Laravel tutorials section of the site to go deeper and learn even more about Laravel.

programming

via Laravel News https://ift.tt/14pzU0d

March 7, 2021 at 12:04PM

How LEGO Bricks Are Made

How LEGO Bricks Are Made

https://ift.tt/2OqCEqm

How LEGO Bricks Are Made

Link

LEGO bricks are the world’s favorite construction toys. We know they’re made out of plastic, but how do they make so many different colors and shapes? And how do they package just the right quantity of the right bricks? The LEGO Group takes us inside of their factories for an inside look at how a finished set comes together.

fun

via The Awesomer https://theawesomer.com

March 5, 2021 at 05:45PM

This Site Spits Out AI-Generated Rejection Emails so You Can Copy and Paste Disappointment

This Site Spits Out AI-Generated Rejection Emails so You Can Copy and Paste Disappointment

https://ift.tt/3bhEbb8


Screenshot: Unfortunately.io/Gizmodo

Crushing a starry-eyed startup’s hopes and dreams can be a pain, but now you can outsource that emotional labor to a heartless AI instead. Because rejection doesn’t have to hurt…err, not you at least, I mean.

That’s the idea behind Unfortunately.io, an online tool that uses artificial intelligence to generate rejection emails. It’s the latest brainchild of Danielle Baskin, a San Francisco-based designer and artist whose works embody that deranged intersection endemic of online humor where one-off goofs and genuinely fantastic ideas blur into one. Her previous projects include Face ID-compatible face masks, an online graveyard for expired domain names, and Quarantine Chat, a call service co-created with fellow artist Max Hawkins that connects two random strangers over the phone and which made headlines last March as the world descended into coronavirus-related lockdown (and loneliness).

Baskin debuted Unfortunately via Twitter on Friday, explaining that she built the prototype after a conversation with its now-lead investor, Jack Dreifuss, who initially suggested the idea. It’s simple: You just copy and paste whatever rejection email Unfortunately spits out, filling in relevant information such as your name and that of the poor soul whose inbox this polite “no” is destined for, and bam, you’re done.

We took it for a test run, as you can see below. The randomized email we got really softens the blow by pointing downtrodden entrepreneurs toward [insert insightful Medium article here].

Screenshot: Unfortunately.io/Gizmodo

G/O Media may get a commission

At the moment it can only generate emails for letting down startup ventures—”If you’re an angel investor or a VC—let us handle the heavy work,” reads Unfortunately’s pitch. But the site promises that expanded formats tailored to rejecting candidates and movie/tv pitches are “coming soon.”

The site advertises a paid tier for $25 per month or $149 per year (which we assume is a joke but it’s always so hard to tell on the internet) that will customize the tone of your randomly generated rejection emails with “4 possible emotions,” as shown below, and incorporate OpenAI’s GPT-3 language model for “more nuance and detail.”

Gif: Unfortunately.io/Gizmodo

Unfortunately also encourages visitors to submit their own rejection letter anonymously to be used as part of the site’s dataset. And for anyone out there dealing with a particularly rough rejection right now, there’s the Unfortunately hotline where you can submit an anonymous memo unloading your troubles. “We’re here to listen,” Unfortunately’s site claims, but something tells me you should take that promise with a grain of salt. Just a hunch.

geeky,Tech

via Gizmodo https://gizmodo.com

March 6, 2021 at 02:12AM

5 Reasons Why Democrats’ Extremist Gun Control Will Always Fail

5 Reasons Why Democrats’ Extremist Gun Control Will Always Fail

https://ift.tt/3rlCLlx

Gun Control Background Checks
Gun Control Background Checks

U.S.A.-(AmmoLand.com)- With the launch of their frontal assault on firearms rights via H.R. 8 and H.R. 127, Capitol Hill Democrats have made it clear they are not interested in facts or the “common sense” their gun control campaign perennially claims to represent, and instead provided all the justification necessary for a hard-hitting pro-rights ad campaign by a grassroots gun rights organization now heading into its second week.

Ammoland News did some homework and found five clear reasons—call them examples—why gun control fails and will always fail; the proof routinely ignored by gun prohibitionists whose ultimate goal, according to Second Amendment activists, has never been violent crime reduction but unilateral public disarmament.

Reason 1:

A Meridian, Mississippi man identified as Edmond Dewayne Miller was sentenced recently to 51 months in federal prison, plus three years of supervised release, for being a convicted felon in possession of a firearm. In a Justice Department news release, Miller was stopped by a Lauderdale County Sheriff’s Deputy as he headed for the home of a neighbor who had called in a noise complaint. Miller was carrying a .40-caliber pistol that turned out to be stolen, and the lawman learned he was a convicted felon, unable to possess a firearm. Miller pled guilty in January 2020 but only recently was sentenced.

Reason 2:

Michael D. Moore of Kansas City, Missouri pleaded guilty in federal court to illegal possession of a firearm following an armed standoff last Aug. 17. Moore had been under surveillance by police as a suspect in two armed robberies and when they moved in, he exited a BMW SUV, took cover and drew a Smith & Wesson 9mm pistol that was later found to have been stolen. As more police arrived, Moore threw down the gun and ran a short distance before being taken into custody.

Reason 3:

Tampa, Florida resident Devon Cohen was sentenced to five years in federal prison for being a convicted felon in possession of a firearm and ammunition. Police stopped Cohen after observing him violate several traffic laws and a search of the car turned up a loaded pistol in the console. Cohen admitted he possessed the pistol. His criminal record included multiple felonies.

Reason 4:

A 28-year-old suspect identified by NorthEscambia.com as Christopher Torrey, Jr. has been charged with aggravated assault with a deadly weapon, discharge of a weapon in public by firing into an occupied vehicle, firing a weapon into a building, meth possession, and being a convicted felon in possession of a firearm. He was being held in the Escambia County Jail without bond.

Reason 5:

Torrey has company in that jail, NorthExcambia.com reported separately. A suspect identified as 22-year-old Larry Clay is charged with trafficking and possession of drugs, and probation violation. He was arrested on a search warrant and in addition to drugs, police found four handguns, a shotgun and a rifle, the news agency said. He was being held without bond.

Each of these cases underscores why gun control is inherently and irreversibly doomed to failure, says the Second Amendment community. Criminals do not obey gun laws. They never have and never will.

It is not that anti-gunners don’t understand this fundamental fact; they deliberately ignore it. Admitting that criminals routinely disobey gun laws is anathema to the gun prohibitionist mindset, and they will never acknowledge this error in logic. It is this stubborn refusal to recognize the obvious that keeps anti-gunners in a perpetual frenzy to pass restrictive gun laws, say rights advocates. They’ve apparently convinced themselves that restricting the rights of law-abiding citizens will somehow translate to disarming criminals and reducing violent crime.

The Federalist just published an Op-Ed by firearms attorney Ryan Cleckner, detailing the “Top 9 Reasons” a new gun control bill introduced by Democrats “is a terrible idea.” In his essay, Cleckner managed to dismantle virtually every argument in favor of gun control ever put forward by so-called “gun safety” organizations. In order, here are the reasons H.R. 8 is doomed to failure, Cleckner says:

  • Demands for New Gun Control Are an Admission That Gun Control Doesn’t Work
  • Gun Dealers Already Conduct Background Checks
  • There Is No ‘Gun-Show Loophole’
  • There Is No ‘Online Gun Sales Loophole’
  • Universal Background Checks Won’t Stop Criminals from Getting Guns
  • Background Checks Won’t Stop Mass Shootings
  • In-State Commerce Is a State Issue
  • Universal Background Checks Are Too Burdensome
  • Universal Background Checks Create a De Facto Federal Gun Registry

In an email blast Thursday, anti-gun billionaire Michael Bloomberg’s Everytown for Gun Safety declared, “This is a pivotal moment. Legislation to expand background checks to all gun sales has been introduced in both the House and the Senate.

“HR 8 closes a dangerous loophole in our background check system that allows individuals to avoid a background check if they purchase guns in a private sale,” the Everytown message claims. “This gap allows individuals who are prohibited from possessing firearms to purchase them anyway. That doesn’t make sense. If someone can’t pass a background check at a gun store, they shouldn’t be able to buy one at a gun show no questions asked.

“For the first time in decades, there are gun responsibility majorities in Congress, which means this policy has a real chance. We are working tirelessly to make sure those gun responsibility candidates keep their promise and support HR 8. We need your help to hold them accountable.”

Everytown, like other gun prohibition lobbying groups, erroneously deems Capitol Hill anti-gunners as “gun responsibility” politicians.

One example would be Texas Congresswoman Sheila Jackson Lee, whose H.R. 127 is criticized by gun rights activists as being so egregiously ignorant of constitutional rights it has brought the Citizens Committee for the Right to Keep and Bear Arms into the media arena with a devastating 60-second advertisement calling for public opposition. CCRKBA is the grassroots sister organization of the Second Amendment Foundation, and typically remains in the background while SAF has emerged as a legal powerhouse since winning the 2010 Supreme Court case of McDonald v. City of Chicago.

CCRKBA’s campaign is called “SAVE2A.US” and is aimed squarely at Jackson Lee’s legislation. Public response during the first week was so stunning that CCRKBA Chairman Alan Gottlieb quickly extended it fr at least seven more days.

The message is appearing 66 times during the second week on the following networks: DirecTV, Fox News, Fox Business, CNN, MSNBC, CNBC, Bloomberg, DishTV, the Weather Channel, HLN, OANN, the Outdoor Channel, Sportsman Channel and the Inspiration Channel.

“By the end of the week,” Gottlieb said in a news release, “CCRKBA’s message will have been aired a total of 119 times.”

He said H.R. 127 represents the “ultimate wish list” of gun control zealots.

“This bill really is a sinister attack on Second Amendment rights,” Gottlieb stated. “Democrats are determined to reduce rights protected by the Second Amendment to the level of privileges so tightly regulated by government red tape that they no longer really exist. The Washington Post likes to tell people that ‘freedom dies in darkness,’ but H.R. 127 is being pushed in broad daylight by people claiming some sort of mandate to trash individual rights.

“Anti-gunners have waited for years to launch this attack,” he added. “With Joe Biden in the White House, Beltway Democrats are determined to destroy the Constitution’s cornerstone Amendment, and we are determined to stop them.”

American gun owners can join this campaign by visiting ‘SAVE2A.US’ or text SAVE2A to 474747.


About Dave Workman

Dave Workman is a senior editor at TheGunMag.com and Liberty Park Press, author of multiple books on the Right to Keep & Bear Arms, and formerly an NRA-certified firearms instructor.

Dave Workman

The post 5 Reasons Why Democrats’ Extremist Gun Control Will Always Fail appeared first on AmmoLand.com.

guns

via AmmoLand.com https://ift.tt/2okaFKE

March 5, 2021 at 07:37PM

WATCH: Whistleblower from Merrill Lynch leaks BOMBSHELL phone call on the day Robinhood restricted trading

WATCH: Whistleblower from Merrill Lynch leaks BOMBSHELL phone call on the day Robinhood restricted trading

https://ift.tt/3sTJ3sR

Project Veritas has just gone public on Friday with a leaked phone call given to them by a whistleblower, in which a Merrill Lynch employee admits that the bank was on the "side of the institutional investors". The Robinhood App put restrictions in place on the same day.

"WALL STREET: Citizen Journalist/Retail Investor LEAKS RECORDING to Veritas of @MerrillLynch Employee Admitting Bank Had ‘Taken the Side of the Institutional Investors’ in the Same Day @RobinhoodApp Restricted Trading … ‘It Sounds Fishy’ … ‘It Sounds Strange’"

At the beginning of the video, one can hear the voice asking:

"Now, tell me the truth. You guys know that this stock is going to go up and you want me to sell my shares to put some liquidity into the market, don’t you?"

The Merrill Lynch employee replies:

"If I take the Merrill name badge off of my shirt right now, watching what’s been going on today, it’s very clear to me that it looks like they’ve taken the side of the institutional investors."

All of this went down at the same time as the investor app Robinhood and others were restricting the ability to buy the stock in question in various ways.

The stock in question is BNGO, or BioNano Genomics. However, this whole controversy original centered around a group of stocks, the most prominent of which was GameStop. An informal group of independent traders based off of Reddit heavily invest in that stock in order to counter a move by the hedge funds.

For example, Merrill Lynch’s representative in the case of this particular phone call told the customer that the margin requirement was going up from 30% to 75% in order "to manage the risk in the account."  As stated a bit later in the video, "that’s a big difference."

When something like this happens, an investor is forced to either cough up the extra cash (if the investor even has that much cash on hand), or sell some of the shares off to meet the new margin requirement.

It could be rightly said that this was a strong-arm tactic on the part of Merrill Lynch to make their own customers do their bidding. As it was put in the video, they are telling customers that "forced losses are for your own good."

Responses to the tweet were overwhelmingly appreciative:

"This s**t is nuts! James [O’Keefe, CEO of Project Veritas] you literally are the f**king best!!"

"Love it when you call out these d**che bags"

news

via Conservative Review https://ift.tt/1ntNrMz

March 5, 2021 at 08:56PM

laravel-notification-channels/microsoft-teams

laravel-notification-channels/microsoft-teams

https://ift.tt/3kPMgXR


Microsoft Teams Notifications Channel for Laravel

Latest Version on Packagist
Software License
Build Status
StyleCI
Quality Score
Code Coverage
Total Downloads

This package makes it easy to send notifications using Microsoft Teams with Laravel 5.5+, 6.x, 7.x and 8.x

return MicrosoftTeamsMessage::create()
    ->to(config('services.teams.sales_url'))
    ->type('success')
    ->title('Subscription Created')
    ->content('Yey, you got a **new subscription**. Maybe you want to contact him if he needs any support?')
    ->button('Check User', 'https://foo.bar/users/123');

Contents

Installation

You can install the package via composer:

composer require laravel-notification-channels/microsoft-teams

Next, if you’re using Laravel without auto-discovery, add the service provider to config/app.php:

'providers' => [
    // ...
    NotificationChannels\MicrosoftTeams\MicrosoftTeamsServiceProvider::class,
],

Setting up the Connector

Please check out this for setting up and adding a webhook connector to your Team’s channel. Basic Markdown is supported, please also check out the message card reference article which goes in more detail about the do’s and don’ts.

Setting up the MicrosoftTeams service

Then, configure your webhook url:

Add the following code to your config/services.php:

// config/services.php
...
'teams' => [
    'webhook_url' => env('TEAMS_WEBHOOK_URL'),
],
...

You can also add multiple webhooks if you have multiple teams or channels, it’s up to you.

// config/services.php
...
'teams' => [
    'sales_url' => env('TEAMS_SALES_WEBHOOK_URL'),
    'dev_url' => env('TEAMS_DEV_WEBHOOK_URL'),
],
...

Usage

Now you can use the channel in your via() method inside the notification:

use Illuminate\Notifications\Notification;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;

class SubscriptionCreated extends Notification
{
    public function via($notifiable)
    {
        return [MicrosoftTeamsChannel::class];
    }

    public function toMicrosoftTeams($notifiable)
    {
        return MicrosoftTeamsMessage::create()
            ->to(config('services.teams.sales_url'))
            ->type('success')
            ->title('Subscription Created')
            ->content('Yey, you got a **new subscription**. Maybe you want to contact him if he needs any support?')
            ->button('Check User', 'https://foo.bar/users/123');
    }
}

Instead of adding the to($url) method for the recipient you can also add the routeNotificationForMicrosoftTeams method inside your Notifiable model. This method needs to return the webhook url.

public function routeNotificationForMicrosoftTeams(Notification $notification)
{
    return config('services.teams.sales_url')
}

Available Message methods

  • to(string $webhookUrl): Recipient’s webhook url.
  • title(string $title): Title of the message.
  • summary(string $summary): Summary of the message.
  • type(string $type): Type which is used as theme color (any valid hex code or one of: primary|secondary|accent|error|info|success|warning).
  • content(string $content): Content of the message (Markdown supported).
  • button(string $text, string $url = '', array $params = []): Text and url of a button. Wrapper for an potential action.
  • action(string $text, $type = 'OpenUri', array $params = []): Text and type for a potential action. Further params can be added depending on the action. For more infos about different types check out this link.
  • options(array $options, $sectionId = null): Add additional options to pass to the message payload object.

Sections

It is possible to define one or many sections inside a message card. The following methods can be used within a section

  • addStartGroupToSection($sectionId = 'standard_section'): Add a startGroup property which marks the start of a logical group of information.
  • activity(string $activityImage = '', string $activityTitle = '', string $activitySubtitle = '', string $activityText = '', $sectionId = 'standard_section'): Add an activity to a section.
  • fact(string $name, string $value, $sectionId = 'standard_section'): Add a fact to a section (Supports Markdown).
  • image(string $imageUri, string $title = '', $sectionId = 'standard_section'): Add an image to a section.
  • heroImage(string $imageUri, string $title = '', $sectionId = 'standard_section'): Add a hero image to a section.

Additionally the title, content, button and action can be also added to a section through the optional params value:

  • title(string $title, array $params = ['section' => 'my-section']): Title of the message and add it to my-section.
  • content(string $content, array $params = ['section' => 'my-section']): Content of the message and add it to my-section (Markdown supported).
  • button(string $text, string $url = '', array $params = ['section' => 'my-section']): Text and url of a button and add it to my-section.
  • action(string $text, $type = 'OpenUri', array $params = ['section' => 'my-section']): Text and type of an potential action and add it to my-section.

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

Security

If you discover any security related issues, please email tobias.madner@gmx.at instead of using the issue tracker.

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.

programming

via Packalyst :: Latest Packages https://ift.tt/2OrBsQj

March 5, 2021 at 05:05PM

The Most ’80s Ad

The Most ’80s Ad

https://ift.tt/3e7QOr9

The Most ’80s Ad

Link

Ready for a trip back to the 1980s? The guys at We Are the Mutants spotted this gem of a commercial that perfectly captures the sci-fi aesthetics of the era. This big budget ad spot that implies General Electric’s cassette tape players will free the oppressed was obviously influenced by Apple’s famous 1984 Super Bowl spot.

fun

via The Awesomer https://theawesomer.com

March 4, 2021 at 12:30PM