diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml
index bd44d15a92..150f9c4b75 100644
--- a/.github/workflows/linters.yml
+++ b/.github/workflows/linters.yml
@@ -13,10 +13,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-ruby@v1
with:
- ruby-version: 2.6.x
+ ruby-version: 3.0.x
- name: Setup Rubocop
run: |
- gem install --no-document rubocop:'~>0.81.0' # https://docs.rubocop.org/en/stable/installation/
+ gem install --no-document rubocop -v '>= 1.0, < 2.0' # https://docs.rubocop.org/en/stable/installation/
[ -f .rubocop.yml ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/ror/.rubocop.yml
- name: Rubocop Report
run: rubocop --color
@@ -30,7 +30,7 @@ jobs:
node-version: "12.x"
- name: Setup Stylelint
run: |
- npm install --save-dev stylelint@13.3.x stylelint-scss@3.17.x stylelint-config-standard@20.0.x stylelint-csstree-validator
+ npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x
[ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/ror/.stylelintrc.json
- name: Stylelint Report
run: npx stylelint "**/*.{css,scss}"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 18b43c9cd2..b916d63abe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,9 +19,11 @@
/node_modules
/yarn-error.log
+/Gemfile.lock
/public/assets
.byebug_history
# Ignore master key for decrypting credentials and more.
/config/master.key
+
diff --git a/.rubocop.yml b/.rubocop.yml
index 89f3b6bdbd..d8187c3d53 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,7 +1,8 @@
AllCops:
+ NewCops: enable
Exclude:
- "db/**/*"
- - "bin/*"
+ - "bin/*"
- "config/**/*"
- "Guardfile"
- "Rakefile"
@@ -24,7 +25,7 @@ Metrics/AbcSize:
Metrics/ClassLength:
Max: 150
Metrics/BlockLength:
- ExcludedMethods: ["describe"]
+ IgnoredMethods: ['describe']
Max: 30
Style/Documentation:
diff --git a/.ruby-version b/.ruby-version
index 9aa34646dc..13d683ccbf 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.7.0
\ No newline at end of file
+3.0.1
\ No newline at end of file
diff --git a/.stylelintrc.json b/.stylelintrc.json
index c592372ef2..b7b365775d 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,16 +1,10 @@
-
{
"extends": ["stylelint-config-standard"],
"plugins": ["stylelint-scss", "stylelint-csstree-validator"],
"rules": {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true,
- "csstree/validator":
- {
- "properties": {
- "width": "| fit-content"
- }
- }
+ "csstree/validator": true
},
"ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css"]
}
diff --git a/Gemfile b/Gemfile
index 67b156b339..e4a9fccccd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,16 +1,25 @@
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
-ruby '2.7.0'
+# ruby '2.7.0'
+ruby '3.0.1'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
-gem 'rails', '~> 5.2.4'
+gem 'rails', '~> 6.1.3', '>= 6.1.3.2'
# Use postgresql as the database for Active Record
-gem 'pg', '>= 0.18', '< 2.0'
+group :development, :test do
+ gem 'sqlite3'
+end
+
+group :production do
+ gem 'pg'
+end
+
# Use Puma as the app server
-gem 'puma', '~> 3.12'
+gem 'puma', '~> 5.0'
# Use SCSS for stylesheets
-gem 'sass-rails', '~> 5.0'
+gem 'bootstrap', '~> 4.0'
+gem 'sass-rails', '>= 6'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
@@ -21,7 +30,7 @@ gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
-gem 'jbuilder', '~> 2.5'
+gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
@@ -48,6 +57,17 @@ group :test do
gem 'rspec'
end
+group :development, :test do
+ # The RSpec testing framework
+ gem 'rspec-rails'
+ # Capybara, the library that allows us to interact with the browser using Ruby
+ gem 'capybara'
+ # The following gems aids with the nuts and bolts
+ # of interacting with the browser.
+ gem 'webdrivers'
+end
+
+
group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'listen', '>= 3.0.5', '< 3.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index b67d4b3306..3f2999e5ac 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,55 +1,89 @@
GEM
remote: https://rubygems.org/
specs:
- actioncable (5.2.4.1)
- actionpack (= 5.2.4.1)
+ actioncable (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailer (5.2.4.1)
- actionpack (= 5.2.4.1)
- actionview (= 5.2.4.1)
- activejob (= 5.2.4.1)
+ actionmailbox (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ activejob (= 6.1.3.2)
+ activerecord (= 6.1.3.2)
+ activestorage (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ mail (>= 2.7.1)
+ actionmailer (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ actionview (= 6.1.3.2)
+ activejob (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.2.4.1)
- actionview (= 5.2.4.1)
- activesupport (= 5.2.4.1)
- rack (~> 2.0, >= 2.0.8)
+ actionpack (6.1.3.2)
+ actionview (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.2.4.1)
- activesupport (= 5.2.4.1)
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
+ actiontext (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ activerecord (= 6.1.3.2)
+ activestorage (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ nokogiri (>= 1.8.5)
+ actionview (6.1.3.2)
+ activesupport (= 6.1.3.2)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
- activejob (5.2.4.1)
- activesupport (= 5.2.4.1)
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
+ activejob (6.1.3.2)
+ activesupport (= 6.1.3.2)
globalid (>= 0.3.6)
- activemodel (5.2.4.1)
- activesupport (= 5.2.4.1)
- activerecord (5.2.4.1)
- activemodel (= 5.2.4.1)
- activesupport (= 5.2.4.1)
- arel (>= 9.0)
- activestorage (5.2.4.1)
- actionpack (= 5.2.4.1)
- activerecord (= 5.2.4.1)
- marcel (~> 0.3.1)
- activesupport (5.2.4.1)
+ activemodel (6.1.3.2)
+ activesupport (= 6.1.3.2)
+ activerecord (6.1.3.2)
+ activemodel (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ activestorage (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ activejob (= 6.1.3.2)
+ activerecord (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ marcel (~> 1.0.0)
+ mini_mime (~> 1.0.2)
+ activesupport (6.1.3.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- arel (9.0.0)
- ast (2.4.0)
- bcrypt (3.1.13)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ addressable (2.7.0)
+ public_suffix (>= 2.0.2, < 5.0)
+ ast (2.4.2)
+ autoprefixer-rails (10.2.5.1)
+ execjs (> 0)
+ bcrypt (3.1.16)
bindex (0.8.1)
- bootsnap (1.4.6)
+ bootsnap (1.7.5)
msgpack (~> 1.0)
+ bootstrap (4.6.0)
+ autoprefixer-rails (>= 9.1.0)
+ popper_js (>= 1.14.3, < 2)
+ sassc-rails (>= 2.0.0)
builder (3.2.4)
- byebug (11.1.1)
+ byebug (11.1.3)
+ capybara (3.35.3)
+ addressable
+ mini_mime (>= 0.1.3)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (>= 1.5, < 3.0)
+ xpath (~> 3.2)
+ childprocess (3.0.0)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
@@ -57,189 +91,206 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
- concurrent-ruby (1.1.6)
+ concurrent-ruby (1.1.9)
crass (1.0.6)
- devise (4.7.1)
+ devise (4.8.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
- diff-lcs (1.3)
- erubi (1.9.0)
- execjs (2.7.0)
- ffi (1.12.2)
- ffi (1.12.2-x64-mingw32)
+ diff-lcs (1.4.4)
+ erubi (1.10.0)
+ execjs (2.8.1)
+ ffi (1.15.3)
globalid (0.4.2)
activesupport (>= 4.2.0)
- i18n (1.8.2)
+ i18n (1.8.10)
concurrent-ruby (~> 1.0)
- jaro_winkler (1.5.4)
- jbuilder (2.10.0)
+ jbuilder (2.11.2)
activesupport (>= 5.0.0)
- listen (3.1.5)
+ listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
- ruby_dep (~> 1.2)
- loofah (2.4.0)
+ loofah (2.10.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
- marcel (0.3.3)
- mimemagic (~> 0.3.2)
- method_source (0.9.2)
- mimemagic (0.3.4)
- mini_mime (1.0.2)
- mini_portile2 (2.5.0)
- minitest (5.14.0)
- msgpack (1.3.3)
- msgpack (1.3.3-x64-mingw32)
- nio4r (2.5.2)
- nokogiri (1.11.1)
- mini_portile2 (~> 2.5.0)
- racc (~> 1.4)
- nokogiri (1.11.1-x64-mingw32)
+ marcel (1.0.1)
+ method_source (1.0.0)
+ mini_mime (1.0.3)
+ minitest (5.14.4)
+ msgpack (1.4.2)
+ nio4r (2.5.7)
+ nokogiri (1.11.7-x86_64-darwin)
racc (~> 1.4)
orm_adapter (0.5.0)
- parallel (1.19.1)
- parser (2.7.0.4)
- ast (~> 2.4.0)
- pg (1.2.2)
- pg (1.2.2-x64-mingw32)
- puma (3.12.6)
+ parallel (1.20.1)
+ parser (3.0.1.1)
+ ast (~> 2.4.1)
+ pg (1.2.3)
+ popper_js (1.16.0)
+ public_suffix (4.0.6)
+ puma (5.3.2)
+ nio4r (~> 2.0)
racc (1.5.2)
rack (2.2.3)
rack-test (1.1.0)
rack (>= 1.0, < 3)
- rails (5.2.4.1)
- actioncable (= 5.2.4.1)
- actionmailer (= 5.2.4.1)
- actionpack (= 5.2.4.1)
- actionview (= 5.2.4.1)
- activejob (= 5.2.4.1)
- activemodel (= 5.2.4.1)
- activerecord (= 5.2.4.1)
- activestorage (= 5.2.4.1)
- activesupport (= 5.2.4.1)
- bundler (>= 1.3.0)
- railties (= 5.2.4.1)
+ rails (6.1.3.2)
+ actioncable (= 6.1.3.2)
+ actionmailbox (= 6.1.3.2)
+ actionmailer (= 6.1.3.2)
+ actionpack (= 6.1.3.2)
+ actiontext (= 6.1.3.2)
+ actionview (= 6.1.3.2)
+ activejob (= 6.1.3.2)
+ activemodel (= 6.1.3.2)
+ activerecord (= 6.1.3.2)
+ activestorage (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
+ bundler (>= 1.15.0)
+ railties (= 6.1.3.2)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
- railties (5.2.4.1)
- actionpack (= 5.2.4.1)
- activesupport (= 5.2.4.1)
+ railties (6.1.3.2)
+ actionpack (= 6.1.3.2)
+ activesupport (= 6.1.3.2)
method_source
rake (>= 0.8.7)
- thor (>= 0.19.0, < 2.0)
+ thor (~> 1.0)
rainbow (3.0.0)
- rake (13.0.1)
- rb-fsevent (0.10.3)
+ rake (13.0.3)
+ rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
- responders (3.0.0)
+ regexp_parser (2.1.1)
+ responders (3.0.1)
actionpack (>= 5.0)
railties (>= 5.0)
- rexml (3.2.4)
- rspec (3.9.0)
- rspec-core (~> 3.9.0)
- rspec-expectations (~> 3.9.0)
- rspec-mocks (~> 3.9.0)
- rspec-core (3.9.1)
- rspec-support (~> 3.9.1)
- rspec-expectations (3.9.1)
+ rexml (3.2.5)
+ rspec (3.10.0)
+ rspec-core (~> 3.10.0)
+ rspec-expectations (~> 3.10.0)
+ rspec-mocks (~> 3.10.0)
+ rspec-core (3.10.1)
+ rspec-support (~> 3.10.0)
+ rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
- rspec-mocks (3.9.1)
+ rspec-support (~> 3.10.0)
+ rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
- rspec-support (3.9.2)
- rubocop (0.80.1)
- jaro_winkler (~> 1.5.1)
+ rspec-support (~> 3.10.0)
+ rspec-rails (5.0.1)
+ actionpack (>= 5.2)
+ activesupport (>= 5.2)
+ railties (>= 5.2)
+ rspec-core (~> 3.10)
+ rspec-expectations (~> 3.10)
+ rspec-mocks (~> 3.10)
+ rspec-support (~> 3.10)
+ rspec-support (3.10.2)
+ rubocop (1.17.0)
parallel (~> 1.10)
- parser (>= 2.7.0.1)
+ parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
rexml
+ rubocop-ast (>= 1.7.0, < 2.0)
ruby-progressbar (~> 1.7)
- unicode-display_width (>= 1.4.0, < 1.7)
- ruby-progressbar (1.10.1)
- ruby_dep (1.5.0)
- sass (3.7.4)
- sass-listen (~> 4.0.0)
- sass-listen (4.0.0)
- rb-fsevent (~> 0.9, >= 0.9.4)
- rb-inotify (~> 0.9, >= 0.9.7)
- sass-rails (5.1.0)
- railties (>= 5.2.0)
- sass (~> 3.1)
- sprockets (>= 2.8, < 4.0)
- sprockets-rails (>= 2.0, < 4.0)
- tilt (>= 1.1, < 3)
- spring (2.1.0)
+ unicode-display_width (>= 1.4.0, < 3.0)
+ rubocop-ast (1.7.0)
+ parser (>= 3.0.1.1)
+ ruby-progressbar (1.11.0)
+ rubyzip (2.3.0)
+ sass-rails (6.0.0)
+ sassc-rails (~> 2.1, >= 2.1.1)
+ sassc (2.4.0)
+ ffi (~> 1.9)
+ sassc-rails (2.1.2)
+ railties (>= 4.0.0)
+ sassc (>= 2.0)
+ sprockets (> 3.0)
+ sprockets-rails
+ tilt
+ selenium-webdriver (3.142.7)
+ childprocess (>= 0.5, < 4.0)
+ rubyzip (>= 1.2.2)
+ spring (2.1.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
- sprockets (3.7.2)
+ sprockets (4.0.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.2.1)
+ sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
- thor (1.0.1)
- thread_safe (0.3.6)
+ sqlite3 (1.4.2)
+ thor (1.1.0)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
- tzinfo (1.2.6)
- thread_safe (~> 0.1)
- tzinfo-data (1.2020.1)
- tzinfo (>= 1.0.0)
+ tzinfo (2.0.4)
+ concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
- unicode-display_width (1.6.1)
- warden (1.2.8)
- rack (>= 2.0.6)
- web-console (3.7.0)
- actionview (>= 5.0)
- activemodel (>= 5.0)
+ unicode-display_width (2.0.0)
+ warden (1.2.9)
+ rack (>= 2.0.9)
+ web-console (4.1.0)
+ actionview (>= 6.0.0)
+ activemodel (>= 6.0.0)
bindex (>= 0.4.0)
- railties (>= 5.0)
- websocket-driver (0.7.1)
+ railties (>= 6.0.0)
+ webdrivers (4.6.0)
+ nokogiri (~> 1.6)
+ rubyzip (>= 1.3.0)
+ selenium-webdriver (>= 3.0, < 4.0)
+ websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
+ xpath (3.2.0)
+ nokogiri (~> 1.8)
+ zeitwerk (2.4.2)
PLATFORMS
- ruby
- x64-mingw32
+ x86_64-darwin-19
DEPENDENCIES
bootsnap (>= 1.1.0)
+ bootstrap (~> 4.0)
byebug
+ capybara
coffee-rails (~> 4.2)
devise
- jbuilder (~> 2.5)
+ jbuilder (~> 2.7)
listen (>= 3.0.5, < 3.2)
- pg (>= 0.18, < 2.0)
- puma (~> 3.12)
- rails (~> 5.2.4)
+ pg
+ puma (~> 5.0)
+ rails (~> 6.1.3, >= 6.1.3.2)
rspec
+ rspec-rails
rubocop
- sass-rails (~> 5.0)
+ sass-rails (>= 6)
spring
spring-watcher-listen (~> 2.0.0)
+ sqlite3
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
+ webdrivers
RUBY VERSION
- ruby 2.7.0p0
+ ruby 3.0.1p64
BUNDLED WITH
- 2.1.2
+ 2.2.21
diff --git a/app/assets/stylesheets/friendship.scss b/app/assets/stylesheets/friendship.scss
new file mode 100644
index 0000000000..0bc6dcf556
--- /dev/null
+++ b/app/assets/stylesheets/friendship.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Friendship controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: https://sass-lang.com/
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index b0350d70e4..d2573592b7 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -9,4 +9,27 @@ def show
@user = User.find(params[:id])
@posts = @user.posts.ordered_by_most_recent
end
+
+ def request_friend
+ request = current_user.friendships.build(friend_id: params['id'], confirmed: false)
+ request.save
+ flash[:notice] = 'Friend Request Successfully sent'
+ redirect_to users_path
+ end
+
+ def accept_freind
+ current_user.accept_friendship(params[:id])
+ user = User.find(params[:id])
+
+ flash[:notice] = "You Accepted #{user.name}'s Friend Request!"
+ redirect_to users_path
+ end
+
+ def decline_friend
+ current_user.decline_friendship(params[:id])
+ user = User.find(params[:id])
+
+ flash[:notice] = "You Declined #{user.name}'s Friends Request"
+ redirect_to users_path
+ end
end
diff --git a/app/models/friendship.rb b/app/models/friendship.rb
new file mode 100644
index 0000000000..cbc99ab545
--- /dev/null
+++ b/app/models/friendship.rb
@@ -0,0 +1,7 @@
+class Friendship < ApplicationRecord
+ scope :pending_requests, -> { where(status: false) }
+ scope :accepted_requests, -> { where(status: true) }
+
+ belongs_to :user
+ belongs_to :friend, class_name: 'User'
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index e97f1363c0..4933e8dff0 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -9,4 +9,38 @@ class User < ApplicationRecord
has_many :posts
has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
+ has_many :friendships
+ has_many :inverse_friendships, class_name: 'Friendship', foreign_key: 'friend_id'
+
+ # Helper methods
+ def friends
+ friends_array = friendships.map { |friendship| friendship.friend if friendship.confirmed }
+ friends_array += inverse_friendships.map { |friendship| friendship.user if friendship.confirmed }
+ friends_array.compact
+ end
+
+ # Users who have yet to confirmed friend requests
+ def pending_friends
+ friendships.map { |friendship| friendship.friend unless friendship.confirmed }.compact
+ end
+
+ # Users who have requested to be friends
+ def friend_requests
+ inverse_friendships.map { |friendship| friendship.user unless friendship.confirmed }.compact
+ end
+
+ def confirm_friend(user)
+ friendship = inverse_friendships.find { |friend| friend.user == user }
+ friendship.confirmed = true
+ friendship.save
+ end
+
+ def friend?(user)
+ friends.include?(user)
+ end
+
+ def decline_friendship(user_id)
+ request = inverse_friendships.where(user_id: user_id).where(confirmed: false).first
+ request.destroy
+ end
end
diff --git a/app/views/posts/_post.html.erb b/app/views/posts/_post.html.erb
index 271625b734..dc4778b30c 100644
--- a/app/views/posts/_post.html.erb
+++ b/app/views/posts/_post.html.erb
@@ -1,23 +1,26 @@
-
- <%= link_to post.user.name, user_path(post.user), class: 'post-author' %>
-
-
- <%= post.created_at.strftime("%Y/%m/%d") %>
- <%= like_or_dislike_btn(post) %>
-
-
-
- <%= post.content %>
-
+ <% if current_user == post.user || current_user.friends.include?(post.user)%>
+
+ <%= link_to post.user.name, user_path(post.user), class: 'post-author' %>
+
+
+ <%= post.created_at.strftime("%Y/%m/%d") %>
+ <%= like_or_dislike_btn(post) %>
+
+
+
+ <%= post.content %>
+
-
diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb
index e03c4beb3f..e64b7a5469 100644
--- a/app/views/users/_user.html.erb
+++ b/app/views/users/_user.html.erb
@@ -2,5 +2,7 @@
Name: <%= user.name %>
<%= link_to 'See Profile', user_path(user), class: 'profile-link' %>
+
+ <%= request_status(user) %>
\ No newline at end of file
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index e9919805de..ec37835ba1 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -1,5 +1,8 @@
<%= "Name: #{@user.name}" %>
+
+ <%= request_status(@user)%>
+
Recent posts:
diff --git a/config/routes.rb b/config/routes.rb
index d34298b198..dfdb1c3e5c 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,8 +1,6 @@
Rails.application.routes.draw do
-
- root 'posts#index'
-
devise_for :users
+ root 'posts#index'
resources :users, only: [:index, :show]
resources :posts, only: [:index, :create] do
diff --git a/db/migrate/20210624220331_create_friendships.rb b/db/migrate/20210624220331_create_friendships.rb
new file mode 100644
index 0000000000..9351645cef
--- /dev/null
+++ b/db/migrate/20210624220331_create_friendships.rb
@@ -0,0 +1,13 @@
+class CreateFriendships < ActiveRecord::Migration[6.1]
+ def change
+ create_table :friendships do |t|
+ t.integer :friendship_id
+ t.references :user, null: false, foreign_key: true
+ t.references :friend, null: false
+ t.boolean :confirmed
+
+ t.timestamps
+ end
+ add_foreign_key :friendships, :users, column: :friend_id
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 30ee9f3fad..05e131fea4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -2,15 +2,15 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
-# Note that this schema.rb definition is the authoritative source for your
-# database schema. If you need to create the application database on another
-# system, you should be using db:schema:load, not running all the migrations
-# from scratch. The latter is a flawed and unsustainable approach (the more migrations
-# you'll amass, the slower it'll run and the greater likelihood for issues).
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_02_04_165841) do
+ActiveRecord::Schema.define(version: 2021_06_24_220331) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -25,6 +25,17 @@
t.index ["user_id"], name: "index_comments_on_user_id"
end
+ create_table "friendships", force: :cascade do |t|
+ t.integer "friendship_id"
+ t.bigint "user_id", null: false
+ t.bigint "friend_id", null: false
+ t.boolean "confirmed"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ t.index ["friend_id"], name: "index_friendships_on_friend_id"
+ t.index ["user_id"], name: "index_friendships_on_user_id"
+ end
+
create_table "likes", force: :cascade do |t|
t.integer "post_id"
t.integer "user_id"
@@ -54,4 +65,6 @@
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
+ add_foreign_key "friendships", "users"
+ add_foreign_key "friendships", "users", column: "friend_id"
end
diff --git a/docs/ERDdatabase.png b/docs/ERDdatabase.png
new file mode 100644
index 0000000000..85772010da
Binary files /dev/null and b/docs/ERDdatabase.png differ
diff --git a/spec/friendship_spec.rb b/spec/friendship_spec.rb
new file mode 100644
index 0000000000..2ca0e7ab8f
--- /dev/null
+++ b/spec/friendship_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+RSpec.describe User, type: :model do
+ describe 'associations' do
+ it 'belongs to a user' do
+ friendship = Friendship.reflect_on_association(:user)
+ expect(friendship.macro).to eq(:belongs_to)
+ end
+
+ it 'belongs to a friend' do
+ friendship = Friendship.reflect_on_association(:friend)
+ expect(friendship.macro).to eq(:belongs_to)
+ end
+ end
+end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
new file mode 100644
index 0000000000..00345af7c0
--- /dev/null
+++ b/spec/rails_helper.rb
@@ -0,0 +1,64 @@
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+require 'spec_helper'
+ENV['RAILS_ENV'] ||= 'test'
+require File.expand_path('../config/environment', __dir__)
+# Prevent database truncation if the environment is production
+abort("The Rails environment is running in production mode!") if Rails.env.production?
+require 'rspec/rails'
+# Add additional requires below this line. Rails is not loaded until this point!
+
+# Requires supporting ruby files with custom matchers and macros, etc, in
+# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
+# run as spec files by default. This means that files in spec/support that end
+# in _spec.rb will both be required and run as specs, causing the specs to be
+# run twice. It is recommended that you do not name files matching this glob to
+# end with _spec.rb. You can configure this pattern with the --pattern
+# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
+#
+# The following line is provided for convenience purposes. It has the downside
+# of increasing the boot-up time by auto-requiring all files in the support
+# directory. Alternatively, in the individual `*_spec.rb` files, manually
+# require only the support files necessary.
+#
+# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
+
+# Checks for pending migrations and applies them before tests are run.
+# If you are not using ActiveRecord, you can remove these lines.
+begin
+ ActiveRecord::Migration.maintain_test_schema!
+rescue ActiveRecord::PendingMigrationError => e
+ puts e.to_s.strip
+ exit 1
+end
+RSpec.configure do |config|
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
+
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+
+ # You can uncomment this line to turn off ActiveRecord support entirely.
+ # config.use_active_record = false
+
+ # RSpec Rails can automatically mix in different behaviours to your tests
+ # based on their file location, for example enabling you to call `get` and
+ # `post` in specs under `spec/controllers`.
+ #
+ # You can disable this behaviour by removing the line below, and instead
+ # explicitly tag your specs with their type, e.g.:
+ #
+ # RSpec.describe UsersController, type: :controller do
+ # # ...
+ # end
+ #
+ # The different available types are documented in the features, such as in
+ # https://relishapp.com/rspec/rspec-rails/docs
+ config.infer_spec_type_from_file_location!
+
+ # Filter lines from Rails gems in backtraces.
+ config.filter_rails_from_backtrace!
+ # arbitrary gems may also be filtered via:
+ # config.filter_gems_from_backtrace("gem name")
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index a403ac5360..ce33d66df6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,4 +1,4 @@
-# This file was generated by the `rspec --init` command. Conventionally, all
+# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
@@ -44,55 +44,53 @@
# triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups
- # The settings below are suggested to provide a good initial experience
- # with RSpec, but feel free to customize to your heart's content.
- # # This allows you to limit a spec run to individual examples or groups
- # # you care about by tagging them with `:focus` metadata. When nothing
- # # is tagged with `:focus`, all examples get run. RSpec also provides
- # # aliases for `it`, `describe`, and `context` that include `:focus`
- # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
- # config.filter_run_when_matching :focus
- #
- # # Allows RSpec to persist some state between runs in order to support
- # # the `--only-failures` and `--next-failure` CLI options. We recommend
- # # you configure your source control system to ignore this file.
- # config.example_status_persistence_file_path = "spec/examples.txt"
- #
- # # Limits the available syntax to the non-monkey patched syntax that is
- # # recommended. For more details, see:
- # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
- # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
- # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
- # config.disable_monkey_patching!
- #
- # # This setting enables warnings. It's recommended, but in some cases may
- # # be too noisy due to issues in dependencies.
- # config.warnings = true
- #
- # # Many RSpec users commonly either run the entire suite or an individual
- # # file, and it's useful to allow more verbose output when running an
- # # individual spec file.
- # if config.files_to_run.one?
- # # Use the documentation formatter for detailed output,
- # # unless a formatter has already been configured
- # # (e.g. via a command-line flag).
- # config.default_formatter = "doc"
- # end
- #
- # # Print the 10 slowest examples and example groups at the
- # # end of the spec run, to help surface which specs are running
- # # particularly slow.
- # config.profile_examples = 10
- #
- # # Run specs in random order to surface order dependencies. If you find an
- # # order dependency and want to debug it, you can fix the order by providing
- # # the seed, which is printed after each run.
- # # --seed 1234
- # config.order = :random
- #
- # # Seed global randomization in this process using the `--seed` CLI option.
- # # Setting this allows you to use `--seed` to deterministically reproduce
- # # test failures related to randomization by passing the same `--seed` value
- # # as the one that triggered the failure.
- # Kernel.srand config.seed
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+ # This allows you to limit a spec run to individual examples or groups
+ # you care about by tagging them with `:focus` metadata. When nothing
+ # is tagged with `:focus`, all examples get run. RSpec also provides
+ # aliases for `it`, `describe`, and `context` that include `:focus`
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
+ config.filter_run_when_matching :focus
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
+ config.disable_monkey_patching!
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ config.default_formatter = "doc"
+ end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ Kernel.srand config.seed
+=end
end
diff --git a/spec/user_spec.rb b/spec/user_spec.rb
new file mode 100644
index 0000000000..3b6978ff4e
--- /dev/null
+++ b/spec/user_spec.rb
@@ -0,0 +1,149 @@
+require 'rails_helper'
+
+RSpec.describe User, type: :model do
+ include Warden::Test::Helpers
+ Warden.test_mode!
+
+ let(:current_user) { User.create!(name: 'Tester', email: 'test@example.com', password: 'f4k3p455w0rd') }
+ let(:user) { User.create(name: 'JohnDoe', email: 'johndoe@example.com', password: '123456') }
+ let(:user2) { User.create(name: 'Ying Yang', email: 'yingyang@example.com', password: '123456') }
+
+ describe 'validations' do
+ describe 'name' do
+ it 'must be present' do
+ user = described_class.new(name: 'John', email: 'john@example.com', password: '123456')
+ expect(user).to be_valid
+ user.name = nil
+ expect(user).to_not be_valid
+ end
+ end
+
+ describe 'email' do
+ it 'must be present' do
+ user = described_class.new(name: 'John', email: 'john@example.com', password: '123456')
+ expect(user).to be_valid
+ user.email = nil
+ expect(user).to_not be_valid
+ end
+ end
+
+ describe 'password' do
+ it 'must be present' do
+ user = described_class.new(name: 'John', email: 'john@example.com', password: '123456')
+ expect(user).to be_valid
+ user.password = nil
+ expect(user).to_not be_valid
+ end
+ end
+ end
+
+ describe 'associations' do
+ it 'has many posts' do
+ user = User.reflect_on_association(:posts)
+ expect(user.macro).to eq(:has_many)
+ end
+
+ it 'has many comments' do
+ user = User.reflect_on_association(:comments)
+ expect(user.macro).to eq(:has_many)
+ end
+
+ it 'has many likes' do
+ user = User.reflect_on_association(:likes)
+ expect(user.macro).to eq(:has_many)
+ end
+
+ it 'has many sent friendships' do
+ user = User.reflect_on_association(:friendships)
+ expect(user.macro).to eq(:has_many)
+ end
+
+ it 'has many received friendships' do
+ user = User.reflect_on_association(:inverse_friendships)
+ expect(user.macro).to eq(:has_many)
+ end
+ end
+
+ describe '#pending_friends' do
+ it 'returns an array' do
+ login_as(current_user, scope: :user)
+
+ pending_requests = current_user.pending_friends
+ expect(pending_requests).to be_an Array
+ end
+
+ # it 'should return an array with status false for all containing object' do
+ # login_as(current_user, scope: :user)
+ # current_user.friendships.build(friend_id: user.id, confirmed: false).save
+
+ # pending_requests = current_user.pending_friends
+ # request_statuses = pending_requests.map do |user|
+ # user.inverse_friendships.where(user_id: current_user.id).pending_requests.first.confirmed
+ # end.compact
+ # expect(request_statuses.all?(false)).to be true
+ # end
+ end
+
+ describe '#friends' do
+ it 'returns an array' do
+ login_as(current_user, scope: :user)
+
+ requests = current_user.friends
+ expect(requests).to be_an Array
+ end
+
+ it 'should return an array with status true for all containing object' do
+ login_as(current_user, scope: :user)
+ current_user.friendships.build(friend_id: user, confirmed: true).save
+ user.friendships.build(friend_id: current_user, confirmed: true).save
+
+ requests = current_user.friends
+ request_statuses = requests.map do |user|
+ user.friendships.where(friend_id: current_user.id).accepted_requests.first.status
+ end.compact
+ expect(request_statuses.all?(true)).to be true
+ end
+ end
+
+ describe '#friend_requests' do
+ it 'returns an array' do
+ login_as(current_user, scope: :user)
+
+ requests = current_user.friend_requests
+ expect(requests).to be_an Array
+ end
+
+ it 'should return an array with status false for all containing object' do
+ login_as(current_user, scope: :user)
+ user.friendships.build(friend_id: current_user, confirmed: false).save
+ user2.friendships.build(friend_id: current_user, confirmed: false).save
+
+ requests = current_user.friend_requests
+ request_statuses = requests.map do |user|
+ user.friendships.where(friend_id: current_user).pending_requests.first.confirmed
+ end.compact
+ expect(request_statuses.all?(false)).to be true
+ end
+ end
+
+ describe '#confirm_friend' do
+ it 'should change friend request status to true' do
+ login_as(current_user, scope: :user)
+ user.friendships.build(friend_id: current_user.id, confirmed: false).save
+
+ current_user.confirm_friend(user)
+ expect(current_user.friends[0]).to eq user
+ expect(user.friends[0]).to eq current_user
+ end
+ end
+
+ describe '#decline_friendship' do
+ it 'should change friend request status to true' do
+ login_as(current_user, scope: :user)
+ user.friendships.build(friend_id: current_user.id, confirmed: false).save
+
+ current_user.decline_friendship(user.id)
+ expect(current_user.friends[0]).to be nil
+ end
+ end
+end
\ No newline at end of file