Skip to content

Commit 542b38d

Browse files
authored
Merge pull request #741 from code-corps/739-add-website-field
Fixes #739 and fixes #740 by adding website to projects
2 parents bf313db + 1e7c6e1 commit 542b38d

File tree

11 files changed

+131
-16
lines changed

11 files changed

+131
-16
lines changed

lib/code_corps/helpers/url.ex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
defmodule CodeCorps.Helpers.URL do
2+
@moduledoc """
3+
Provides some helpers for assembling and validating URLs.
4+
"""
5+
6+
alias Ecto.Changeset
7+
8+
@doc """
9+
Prefixes the URL with `http://` in the event that `http://` and `https://` are
10+
not already the starting format. If `nil`, simply returns `nil`.
11+
"""
12+
def prefix_url(changeset, key) do
13+
changeset
14+
|> Changeset.update_change(key, &do_prefix_url/1)
15+
end
16+
17+
defp do_prefix_url(nil), do: nil
18+
defp do_prefix_url("http://" <> rest), do: "http://" <> rest
19+
defp do_prefix_url("https://" <> rest), do: "https://" <> rest
20+
defp do_prefix_url(value), do: "http://" <> value
21+
22+
def valid_format do
23+
~r/\A((http|https):\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(([0-9]{1,5})?\/.*)?#=\z/ix
24+
end
25+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule CodeCorps.Repo.Migrations.AddWebsiteToProject do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:projects) do
6+
add :website, :string
7+
end
8+
end
9+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule CodeCorps.Repo.Migrations.AddShouldLinkExternallyToProject do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:projects) do
6+
add :should_link_externally, :boolean, default: false
7+
end
8+
end
9+
end

priv/repo/structure.sql

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
-- PostgreSQL database dump
33
--
44

5-
-- Dumped from database version 9.5.1
6-
-- Dumped by pg_dump version 9.5.1
5+
-- Dumped from database version 9.5.4
6+
-- Dumped by pg_dump version 9.5.4
77

88
SET statement_timeout = 0;
99
SET lock_timeout = 0;
@@ -369,7 +369,9 @@ CREATE TABLE projects (
369369
approved boolean DEFAULT false,
370370
cloudinary_public_id character varying(255),
371371
default_color character varying(255),
372-
owner_id integer
372+
owner_id integer,
373+
website character varying(255),
374+
should_link_externally boolean DEFAULT false
373375
);
374376

375377

@@ -2608,5 +2610,5 @@ ALTER TABLE ONLY user_tasks
26082610
-- PostgreSQL database dump complete
26092611
--
26102612

2611-
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170228144515), (20170228145755);
2613+
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170308214128), (20170308220713);
26122614

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
defmodule CodeCorps.Helpers.URLTest do
2+
use ExUnit.Case, async: true
3+
import CodeCorps.Helpers.URL
4+
alias Ecto.Changeset
5+
6+
test "returns nil when nil" do
7+
changeset = create_prefixed_changeset(nil)
8+
assert Changeset.get_change(changeset, :url) == nil
9+
end
10+
11+
test "returns the original when starts with http://" do
12+
original = "http://www.google.com"
13+
changeset = create_prefixed_changeset(original)
14+
assert Changeset.get_change(changeset, :url) == original
15+
end
16+
17+
test "returns the original when starts with https://" do
18+
original = "https://www.google.com"
19+
changeset = create_prefixed_changeset(original)
20+
assert Changeset.get_change(changeset, :url) == original
21+
end
22+
23+
test "returns prefixed with http:// in every other case" do
24+
changeset = create_prefixed_changeset("www.google.com")
25+
assert Changeset.get_change(changeset, :url) == "http://www.google.com"
26+
end
27+
28+
defp create_prefixed_changeset(value) do
29+
%Changeset{changes: %{url: value}} |> prefix_url(:url)
30+
end
31+
end

test/models/project_test.exs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,41 @@ defmodule CodeCorps.ProjectTest do
9696
changeset = Project.update_changeset(%Project{}, %{organization_id: 1})
9797
assert :error == changeset |> fetch_change(:organization_id)
9898
end
99+
100+
test "requires :website to be in proper format" do
101+
project = %Project{}
102+
attrs = %{website: "bad <> website"}
103+
104+
changeset = Project.update_changeset(project, attrs)
105+
106+
assert_error_message(changeset, :website, "has invalid format")
107+
end
108+
109+
test "doesn't require :website to be part of the changes" do
110+
project = %Project{}
111+
attrs = %{}
112+
113+
changeset = Project.update_changeset(project, attrs)
114+
115+
refute Keyword.has_key?(changeset.errors, :website)
116+
end
117+
118+
test "prefixes website with 'http://' if there is no prefix" do
119+
project = %Project{website: "https://first.com"}
120+
attrs = %{website: "example.com"}
121+
122+
changeset = Project.update_changeset(project, attrs)
123+
124+
assert changeset.changes.website == "http://example.com"
125+
end
126+
127+
test "doesn't make a change to the url when there is no param for it" do
128+
project = %Project{website: "https://first.com"}
129+
attrs = %{}
130+
131+
changeset = Project.update_changeset(project, attrs)
132+
133+
refute Map.has_key?(changeset.changes, :website)
134+
end
99135
end
100136
end

test/support/factories.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ defmodule CodeCorps.Factories do
7878
title: sequence(:title, &"Project #{&1}"),
7979
slug: sequence(:slug, &"project-#{&1}"),
8080
organization: build(:organization),
81-
owner: build(:user)
81+
owner: build(:user),
82+
website: sequence(:website, &"http://test-#{&1}.com")
8283
}
8384
end
8485

test/views/project_view_test.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ defmodule CodeCorps.ProjectViewTest do
3030
"inserted-at" => project.inserted_at,
3131
"long-description-body" => project.long_description_body,
3232
"long-description-markdown" => project.long_description_markdown,
33+
"should-link-externally" => project.should_link_externally,
3334
"slug" => project.slug,
3435
"title" => project.title,
3536
"total-monthly-donated" => project.total_monthly_donated,
3637
"updated-at" => project.updated_at,
38+
"website" => project.website,
3739
},
3840
"id" => project.id |> Integer.to_string,
3941
"relationships" => %{

web/models/project.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ defmodule CodeCorps.Project do
77

88
import CodeCorps.Helpers.RandomIconColor
99
import CodeCorps.Helpers.Slug
10+
import CodeCorps.Helpers.URL, only: [prefix_url: 2]
1011
import CodeCorps.Validators.SlugValidator
1112

1213
alias CodeCorps.Services.MarkdownRendererService
@@ -21,9 +22,11 @@ defmodule CodeCorps.Project do
2122
field :description, :string
2223
field :long_description_body, :string
2324
field :long_description_markdown, :string
25+
field :should_link_externally, :boolean, default: false # temporary for linking to projects off Code Corps while in alpha
2426
field :slug, :string
2527
field :title, :string
2628
field :total_monthly_donated, :integer, default: 0
29+
field :website, :string
2730

2831
belongs_to :organization, CodeCorps.Organization
2932
belongs_to :owner, CodeCorps.User
@@ -73,6 +76,9 @@ defmodule CodeCorps.Project do
7376
def update_changeset(struct, params) do
7477
struct
7578
|> changeset(params)
79+
|> cast(params, [:website])
80+
|> prefix_url(:website)
81+
|> validate_format(:website, CodeCorps.Helpers.URL.valid_format())
7682
end
7783

7884
def update_total_changeset(struct, params) do

web/models/user.ex

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule CodeCorps.User do
66
use CodeCorps.Web, :model
77

88
import CodeCorps.Helpers.RandomIconColor
9+
import CodeCorps.Helpers.URL, only: [prefix_url: 2]
910
import CodeCorps.Validators.SlugValidator
1011

1112
alias CodeCorps.SluggedRoute
@@ -90,7 +91,7 @@ defmodule CodeCorps.User do
9091
|> changeset(params)
9192
|> cast(params, [:biography, :cloudinary_public_id, :first_name, :last_name, :state_transition, :twitter, :website])
9293
|> prefix_url(:website)
93-
|> validate_format(:website, ~r/\A((http|https):\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(([0-9]{1,5})?\/.*)?#=\z/ix)
94+
|> validate_format(:website, CodeCorps.Helpers.URL.valid_format())
9495
|> validate_format(:twitter, ~r/\A[a-zA-Z0-9_]{1,15}\z/)
9596
|> apply_state_transition(struct)
9697
end
@@ -136,15 +137,6 @@ defmodule CodeCorps.User do
136137
end
137138
end
138139

139-
defp prefix_url(changeset, key) do
140-
changeset
141-
|> update_change(key, &do_prefix_url/1)
142-
end
143-
defp do_prefix_url(nil), do: nil
144-
defp do_prefix_url("http://" <> rest), do: "http://" <> rest
145-
defp do_prefix_url("https://" <> rest), do: "https://" <> rest
146-
defp do_prefix_url(value), do: "http://" <> value
147-
148140
defp check_email_valid(struct, email) do
149141
struct
150142
|> Map.put(:valid, String.match?(email, ~r/@/))

0 commit comments

Comments
 (0)