From 7e14eefc819ce27f45406452a4f8e2039d0f0886 Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Mon, 26 Sep 2016 23:55:21 +0200 Subject: [PATCH] Replace logo, fix #57 - delete/unreblog/unfavourite API, fix #45 - app registration API --- app/assets/images/logo.png | Bin 0 -> 24218 bytes .../components/actions/interactions.jsx | 20 +++++ app/assets/stylesheets/application.scss | 82 +++++------------- app/controllers/api/apps_controller.rb | 13 +++ app/controllers/api/statuses_controller.rb | 17 ++++ app/controllers/api_controller.rb | 4 + app/controllers/auth/sessions_controller.rb | 6 ++ app/controllers/home_controller.rb | 2 +- .../oauth/applications_controller.rb | 18 ---- app/helpers/api/apps_helper.rb | 2 + app/helpers/oauth/applications_helper.rb | 2 - app/services/unfavourite_service.rb | 12 +++ app/views/api/apps/create.rabl | 4 + app/views/application/_logo.html.erb | 11 --- app/views/layouts/auth.html.haml | 2 +- config/application.rb | 6 -- config/initializers/doorkeeper.rb | 2 +- config/routes.rb | 13 +-- ...926213048_remove_owner_from_application.rb | 7 ++ db/schema.rb | 5 +- public/favicon.ico | Bin 2319 -> 927 bytes spec/controllers/api/apps_controller_spec.rb | 26 ++++++ .../api/statuses_controller_spec.rb | 58 +++++++++++++ .../auth/sessions_controller_spec.rb | 2 +- .../oauth/applications_controller_spec.rb | 18 ---- spec/helpers/api/apps_helper_spec.rb | 15 ++++ .../helpers/oauth/applications_helper_spec.rb | 5 -- 27 files changed, 216 insertions(+), 136 deletions(-) create mode 100644 app/assets/images/logo.png create mode 100644 app/controllers/api/apps_controller.rb delete mode 100644 app/controllers/oauth/applications_controller.rb create mode 100644 app/helpers/api/apps_helper.rb delete mode 100644 app/helpers/oauth/applications_helper.rb create mode 100644 app/services/unfavourite_service.rb create mode 100644 app/views/api/apps/create.rabl delete mode 100644 app/views/application/_logo.html.erb create mode 100644 db/migrate/20160926213048_remove_owner_from_application.rb create mode 100644 spec/controllers/api/apps_controller_spec.rb delete mode 100644 spec/controllers/oauth/applications_controller_spec.rb create mode 100644 spec/helpers/api/apps_helper_spec.rb delete mode 100644 spec/helpers/oauth/applications_helper_spec.rb diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3a5a743c0ca10a039ea0bf34e46e0880e8290dfe GIT binary patch literal 24218 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 literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/components/actions/interactions.jsx b/app/assets/javascripts/components/actions/interactions.jsx index f2c615b005..3b3e2a6b60 100644 --- a/app/assets/javascripts/components/actions/interactions.jsx +++ b/app/assets/javascripts/components/actions/interactions.jsx @@ -22,6 +22,16 @@ export function reblog(status) { }; }; +export function unreblog(status) { + return (dispatch, getState) => { + api(getState).post(`/api/statuses/${status.get('id')}/unreblog`).then(response => { + // + }).catch(error => { + // + }); + }; +}; + export function reblogRequest(status) { return { type: REBLOG_REQUEST, @@ -57,6 +67,16 @@ export function favourite(status) { }; }; +export function unfavourite(status) { + return (dispatch, getState) => { + api(getState).post(`/api/statuses/${status.get('id')}/unfavourite`).then(response => { + // + }).catch(error => { + // + }); + }; +}; + export function favouriteRequest(status) { return { type: FAVOURITE_REQUEST, diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index fd0e257a75..84f15eaca3 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -59,7 +59,7 @@ table { body { font-family: 'Roboto', sans-serif; - background: #282c37 image-url('background-photo.jpeg'); + background: #282c37 image-url('background-photo.jpg'); background-size: cover; background-attachment: fixed; font-size: 13px; @@ -104,10 +104,29 @@ body { font-size: 48px; font-weight: 500; + img { + display: block; + margin: 20px auto; + width: 180px; + height: 180px; + } + a { color: inherit; text-decoration: none; outline: 0; + + img { + opacity: 0.8; + transition: all 0.8s ease; + } + + &:hover { + img { + opacity: 1; + transition-duration: 0.2s; + } + } } small { @@ -313,67 +332,6 @@ body { } } -.turbolinks-progress-bar { - background-color: #2b90d9; -} - -.mastodon { - $head: #282c37; - $tusk: #d9e1e8; - $backdrop: #2b90d9; - $highlight: 18%; - - .mastodon-backdrop { - fill: $backdrop; - } - - #mastodon-ear { - fill: lighten($head, 5%); - - &:hover, &.highlight { - fill: lighten($head, $highlight); - } - } - - #mastodon-head-backdrop { - fill: darken($head, 5%); - - &:hover, &.highlight { - fill: darken($head, 5%); - } - } - - #mastodon-nose, #mastodon-cheek, #mastodon-forehead, #mastodon-backhead { - fill: $head; - - &:hover, &.highlight { - fill: lighten($head, $highlight); - } - } - - #mastodon-tusk-front { - fill: lighten($tusk, 5%); - } - - #mastodon-tusk-back { - fill: $tusk; - - &:hover, &.highlight { - fill: lighten($tusk, $highlight); - } - } - - .mastodon-shape { - transition: all 0.8s ease; - stroke: transparent; - stroke-width: 0px; - - &:hover, &.highlight { - transition-duration: 0.2s; - } - } -} - @import 'accounts'; @import 'stream_entries'; @import 'components' diff --git a/app/controllers/api/apps_controller.rb b/app/controllers/api/apps_controller.rb new file mode 100644 index 0000000000..629cb2416c --- /dev/null +++ b/app/controllers/api/apps_controller.rb @@ -0,0 +1,13 @@ +class Api::AppsController < ApplicationController + respond_to :json + + def create + @app = Doorkeeper::Application.create!(app_params) + end + + private + + def app_params + params.permit(:name, :redirect_uri) + end +end diff --git a/app/controllers/api/statuses_controller.rb b/app/controllers/api/statuses_controller.rb index f68f298d8c..44fb40bae9 100644 --- a/app/controllers/api/statuses_controller.rb +++ b/app/controllers/api/statuses_controller.rb @@ -17,16 +17,33 @@ class Api::StatusesController < ApiController render action: :show end + def destroy + @status = Status.where(account_id: current_user.account).find(params[:id]) + RemoveStatusService.new.(@status) + render_empty + end + def reblog @status = ReblogService.new.(current_user.account, Status.find(params[:id])).reload render action: :show end + def unreblog + RemoveStatusService.new.(Status.where(account_id: current_user.account, reblog_of_id: params[:id]).first!) + @status = Status.find(params[:id]) + render action: :show + end + def favourite @status = FavouriteService.new.(current_user.account, Status.find(params[:id])).status.reload render action: :show end + def unfavourite + @status = UnfavouriteService.new.(current_user.account, Status.find(params[:id])).status.reload + render action: :show + end + def home @statuses = Feed.new(:home, current_user.account).get(20, params[:max_id]).to_a end diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index cbe7141b92..e3ac9fc67e 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -27,4 +27,8 @@ class ApiController < ApplicationController def current_user super || current_resource_owner end + + def render_empty + render json: {}, status: 200 + end end diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index fe0adc9bbe..1418ab2ca5 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -8,4 +8,10 @@ class Auth::SessionsController < Devise::SessionsController remember_me(resource) end end + + protected + + def after_sign_in_path_for(_resource) + root_path + end end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index f159c3df88..6b52b704df 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -7,7 +7,7 @@ class HomeController < ApplicationController @mentions = Feed.new(:mentions, current_user.account).get(20) @token = find_or_create_access_token.token end - + private def find_or_create_access_token diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb deleted file mode 100644 index 47935bf7cf..0000000000 --- a/app/controllers/oauth/applications_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -class Oauth::ApplicationsController < Doorkeeper::ApplicationsController - before_action :authenticate_user! - - def index - @applications = current_user.oauth_applications - end - - def create - @application = Doorkeeper::Application.new(application_params) - @application.owner = current_user - - if @application.save - redirect_to oauth_application_url(@application) - else - render :new - end - end -end diff --git a/app/helpers/api/apps_helper.rb b/app/helpers/api/apps_helper.rb new file mode 100644 index 0000000000..f6b0c66357 --- /dev/null +++ b/app/helpers/api/apps_helper.rb @@ -0,0 +1,2 @@ +module Api::AppsHelper +end diff --git a/app/helpers/oauth/applications_helper.rb b/app/helpers/oauth/applications_helper.rb deleted file mode 100644 index 2c18180556..0000000000 --- a/app/helpers/oauth/applications_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module Oauth::ApplicationsHelper -end diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb new file mode 100644 index 0000000000..2491c194f1 --- /dev/null +++ b/app/services/unfavourite_service.rb @@ -0,0 +1,12 @@ +class UnfavouriteService < BaseService + def call(account, status) + favourite = Favourite.find_by!(account: account, status: status) + favourite.destroy! + + unless status.local? + NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id) + end + + favourite + end +end diff --git a/app/views/api/apps/create.rabl b/app/views/api/apps/create.rabl new file mode 100644 index 0000000000..1ff6469a46 --- /dev/null +++ b/app/views/api/apps/create.rabl @@ -0,0 +1,4 @@ +object @app +attributes :id, :redirect_uri +node(:client_id) { |app| app.uid } +node(:client_secret) { |app| app.secret } diff --git a/app/views/application/_logo.html.erb b/app/views/application/_logo.html.erb deleted file mode 100644 index 21fa4f657e..0000000000 --- a/app/views/application/_logo.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="<%= dim %>" height="<%= dim %>" class="mastodon" viewBox="-100 0 1390 750"> - <circle cx="600" cy="380" r="500" fill="#9baec8" class="mastodon-backdrop"/> - <path fill="#282c37" d="M500 200l130-60h140l160 130-90 160-250 45-150-24-26 56 16 83h60l10 40-50 50-80-40-60-160 90-180" class="mastodon-shape" id="mastodon-head-backdrop"/> - <path fill="#282c37" d="M442.1204 451.3337l-42.08-151.3737-.0425.0424-89.993 180.007 60.002 159.9848 80.003 40.0015 49.9913-49.9913-10.011-40.0015h-59.981l-16.0134-82.994 26.003-56.015 2.121.3393z" class="mastodon-shape" id="mastodon-nose"/> - <path fill="#282c37" d="M498.2625 201.7378L400.0403 299.96l42.08 151.3737 147.8742 23.67.5515-.106-92.2835-273.16z" class="mastodon-shape" id="mastodon-cheek"/> - <path fill="#282c37" d="M498.2625 201.7378l92.2835 273.16.7635-.1273L770.0862 140.06l-.0848-.0637H629.996l-129.9943 60.0023-1.7392 1.7392z" class="mastodon-shape" id="mastodon-forehead"/> - <path fill="#282c37" d="M770.0862 140.06L591.3095 474.7705l248.684-44.7737 90.014-160.006L770.0862 140.06z" class="mastodon-shape" id="mastodon-backhead"/> - <path fill="#fff" d="M440 450l-40 80-170-20L70 390-80 230 0 390l100 100 120 100 120 20h130l90-140" class="mastodon-shape" id="mastodon-tusk-front"/> - <path fill="#d9e1e8" d="M268 516L120 360 80 260l70 90 110 90 59 22-8 18 15 41" class="mastodon-shape" id="mastodon-tusk-back"/> - <path fill="#282c37" d="M780 190l110 80-80 140-40-80" class="mastodon-shape" id="mastodon-ear"/> - </svg> diff --git a/app/views/layouts/auth.html.haml b/app/views/layouts/auth.html.haml index bddba570ac..54aa07e2cd 100644 --- a/app/views/layouts/auth.html.haml +++ b/app/views/layouts/auth.html.haml @@ -3,7 +3,7 @@ .logo-container %h1 = link_to root_path do - = render partial: 'application/logo', locals: { dim: 200 } + = image_tag 'logo.png' %small= Rails.configuration.x.local_domain .form-container diff --git a/config/application.rb b/config/application.rb index 81205de329..f6a5f6f9e5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,12 +27,6 @@ module Mastodon config.active_job.queue_adapter = :sidekiq - config.to_prepare do - # Doorkeeper::ApplicationsController.layout 'dashboard' - # Doorkeeper::AuthorizedApplicationsController.layout 'dashboard' - Doorkeeper::AuthorizationsController.layout 'auth' - end - config.middleware.use Rack::Attack config.middleware.use Rack::Deflater diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 0d6574d9f7..2c02d2b54e 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -45,7 +45,7 @@ Doorkeeper.configure do # Optional parameter :confirmation => true (default false) if you want to enforce ownership of # a registered application # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support - enable_application_owner :confirmation => true + # enable_application_owner :confirmation => true # Define access token scopes for your provider # For more information go to diff --git a/config/routes.rb b/config/routes.rb index 51f1f86da0..737dbbecf4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,9 +7,7 @@ Rails.application.routes.draw do mount Sidekiq::Web => '/sidekiq' end - use_doorkeeper do - controllers applications: 'oauth/applications' - end + use_doorkeeper get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger @@ -31,7 +29,7 @@ Rails.application.routes.draw do resource :settings, only: [:show, :update] resources :media, only: [:show] - + namespace :api do # PubSubHubbub resources :subscriptions, only: [:show] @@ -41,7 +39,7 @@ Rails.application.routes.draw do post '/salmon/:id', to: 'salmon#update', as: :salmon # JSON / REST API - resources :statuses, only: [:create, :show] do + resources :statuses, only: [:create, :show, :destroy] do collection do get :home get :mentions @@ -51,13 +49,16 @@ Rails.application.routes.draw do get :context post :reblog + post :unreblog post :favourite + post :unfavourite end end resources :follows, only: [:create] resources :media, only: [:create] - + resources :apps, only: [:create] + resources :accounts, only: [:show] do collection do get :relationships diff --git a/db/migrate/20160926213048_remove_owner_from_application.rb b/db/migrate/20160926213048_remove_owner_from_application.rb new file mode 100644 index 0000000000..a42f53a294 --- /dev/null +++ b/db/migrate/20160926213048_remove_owner_from_application.rb @@ -0,0 +1,7 @@ +class RemoveOwnerFromApplication < ActiveRecord::Migration[5.0] + def change + remove_index :oauth_applications, [:owner_id, :owner_type] + remove_column :oauth_applications, :owner_id, :integer, null: true + remove_column :oauth_applications, :owner_type, :string, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 7127762152..f0d7cf5d34 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160920003904) do +ActiveRecord::Schema.define(version: 20160926213048) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -114,10 +114,7 @@ ActiveRecord::Schema.define(version: 20160920003904) do t.string "scopes", default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.integer "owner_id" - t.string "owner_type" t.boolean "superapp", default: false, null: false - t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end diff --git a/public/favicon.ico b/public/favicon.ico index 84a0b854c534e10a79f340b3aab87d56ed6a31a6..3673ac0d5467a6d5f88ae0ec01827b1a2b539c06 100644 GIT binary patch delta 901 zcmV;01A6?A5}yYU000310RS*C00031AOML2kq{|=15imsK~!jg)!Ivo9Yque@ZWS4 zj2g%I0)?31orxm2O*SUr3tVdALU0rCfr1}E!AN3U_yNS7I-q3bN)UA8#(*(d>8PU^ zqas8X5(7>&lZkU(RJXae(^dD;J#+j1;lRCps?PaWS9SL}r)ows*oi&ZjSlX@EViJF zWt_u*PdJ4y@ELw+$p2W_j#u%$Kyn=U4hOMqBZ<#r0jo8Lmt__2Vs1T&Z^jX<<WAQb z96(`f1&4EAjpAN>y$-}<16jm9O_AS+^Xo`DCd+uNF8OD0$@<>))NEYB({;$NO^AH& zAl7m&BVnJ(-TBx|485Fo;;)vF?;XT>;boG4#AcV@Hf@weT$38Wkrt2~B!^?<=Y<bR zo0d-1Qd$xDVlOo4=p-J(wH1C2Hemmqve7$*c%<s?k2)hK#Y2HjI5URLGM`m>0C-hy z_(0F^GA`l+A#%I}PvF)_TX-4&M0E4Gz2bToGr|kxBVn1`j|Y2n1!i)t2ZU#qoLtp^ zXn%EOOfrj4Bkj9F4iLj5iGFV&E4AM*zA~1IMso?Hdm=<`!r6%7s}lowG~(xzM4v+m zew_?^BOQMhvZgAW#fSQ*whrD)=-yB0_GZ`>QT{%_>2Cw{qafw$OhUIS6CSK8bO$&c zq~8d1G9dw<R&+AlIB6C&Fq`4JNwcVbfi30t?$jX@a?feSawb&Fn#86tb>rY%hSLoj zy*r_6tW=WYbSBg)o5V|z>$7;VVPB^*oQNp54(Pm6ajlCd@s|Feu7i)UBVsESy%OTC z7)}rm=GKG+KZd6g{kr%YpW{pX8);j}Z3#awB>HuVMzL`ExG?oqxJAen>ZYK7#}nl5 z!=I6UOI%K3j;c<UcjGI(nRmEQ(jUVE2?8k;iOMlNT+-bjBs9;9XLm<?|7;ge940BT z6n9lfgZr@10>Z<}6-hnQRaW``;Vt9!7LXhyuf@m{9++=hKr$wahS<F+io260TV6Ut z6?Y4?vAq8Hu;dFor#%}S&yGrLzIPCl-eMY?e1ZKYx5+p1vWa1;w^<8p#76f8p_JJ8 zMt3jfgku3s9yPd#w{38ZYMZcGu~dWjw|GU3!yZi)XXo@Ex7mT4aeb~|#vk}a|8bii b>pK1qGTT)WtYa=e00000NkvXXu0mjf5NfKv delta 2304 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 ar1(GII>W~YGIRg{0000<MNUMnLSTYqm~wgm diff --git a/spec/controllers/api/apps_controller_spec.rb b/spec/controllers/api/apps_controller_spec.rb new file mode 100644 index 0000000000..ebadddde2c --- /dev/null +++ b/spec/controllers/api/apps_controller_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe Api::AppsController, type: :controller do + render_views + + describe 'POST #create' do + before do + post :create, params: { name: 'Test app', redirect_uri: 'urn:ietf:wg:oauth:2.0:oob' } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'creates an OAuth app' do + expect(Doorkeeper::Application.find_by(name: 'Test app')).to_not be nil + end + + it 'returns client ID and client secret' do + json = body_as_json + + expect(json[:client_id]).to_not be_blank + expect(json[:client_secret]).to_not be_blank + end + end +end diff --git a/spec/controllers/api/statuses_controller_spec.rb b/spec/controllers/api/statuses_controller_spec.rb index d02cc9b290..b1f0a7bcc6 100644 --- a/spec/controllers/api/statuses_controller_spec.rb +++ b/spec/controllers/api/statuses_controller_spec.rb @@ -57,6 +57,22 @@ RSpec.describe Api::StatusesController, type: :controller do end end + describe 'DELETE #destroy' do + let(:status) { Fabricate(:status, account: user.account) } + + before do + post :destroy, params: { id: status.id } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'removes the status' do + expect(Status.find_by(id: status.id)).to be nil + end + end + describe 'POST #reblog' do let(:status) { Fabricate(:status, account: user.account) } @@ -85,6 +101,27 @@ RSpec.describe Api::StatusesController, type: :controller do end end + describe 'POST #unreblog' do + let(:status) { Fabricate(:status, account: user.account) } + + before do + post :reblog, params: { id: status.id } + post :unreblog, params: { id: status.id } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'updates the reblogs count' do + expect(status.reblogs_count).to eq 0 + end + + it 'updates the reblogged attribute' do + expect(user.account.reblogged?(status)).to be false + end + end + describe 'POST #favourite' do let(:status) { Fabricate(:status, account: user.account) } @@ -112,4 +149,25 @@ RSpec.describe Api::StatusesController, type: :controller do expect(hash_body[:favourited]).to be true end end + + describe 'POST #unfavourite' do + let(:status) { Fabricate(:status, account: user.account) } + + before do + post :favourite, params: { id: status.id } + post :unfavourite, params: { id: status.id } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'updates the favourites count' do + expect(status.favourites_count).to eq 0 + end + + it 'updates the favourited attribute' do + expect(user.account.favourited?(status)).to be false + end + end end diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index 48c9b34a1a..9dbbb5d453 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Auth::SessionsController, type: :controller do post :create, params: { user: { email: user.email, password: user.password } } end - it 'redirects to home page' do + it 'redirects to home' do expect(response).to redirect_to(root_path) end diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb deleted file mode 100644 index ecd8b16c65..0000000000 --- a/spec/controllers/oauth/applications_controller_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'rails_helper' - -RSpec.describe Oauth::ApplicationsController, type: :controller do - before do - sign_in Fabricate(:user), scope: :user - end - - describe 'GET #index' do - it 'returns http success' do - get :index - expect(response).to have_http_status(:success) - end - end - - describe 'POST #create' do - it 'redirects to the application page' - end -end diff --git a/spec/helpers/api/apps_helper_spec.rb b/spec/helpers/api/apps_helper_spec.rb new file mode 100644 index 0000000000..e26bca2cc1 --- /dev/null +++ b/spec/helpers/api/apps_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the Api::AppsHelper. For example: +# +# describe Api::AppsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe Api::AppsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/oauth/applications_helper_spec.rb b/spec/helpers/oauth/applications_helper_spec.rb deleted file mode 100644 index 749e739db9..0000000000 --- a/spec/helpers/oauth/applications_helper_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe Oauth::ApplicationsHelper, type: :helper do - -end -- GitLab