├── .env.example ├── .gitattributes ├── .gitignore ├── .styleci.yml ├── _config.yml ├── app ├── Answer.php ├── Classes │ ├── QuestionValidation.php │ └── Url.php ├── Console │ └── Kernel.php ├── Events │ ├── AnswerEvent.php │ └── VoteEvent.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── AnswerController.php │ │ ├── Auth │ │ │ ├── ForgotPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── RegisterController.php │ │ │ └── ResetPasswordController.php │ │ ├── Controller.php │ │ ├── HomeController.php │ │ ├── QuestionController.php │ │ ├── TagController.php │ │ ├── UserController.php │ │ └── VoteController.php │ ├── Kernel.php │ └── Middleware │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustProxies.php │ │ └── VerifyCsrfToken.php ├── Listeners │ ├── AnswerListener.php │ └── VoteListener.php ├── Notifications │ ├── Answer.php │ └── Vote.php ├── Policies │ └── QuestionPolicy.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Question.php ├── Tag.php ├── User.php └── Vote.php ├── artisan ├── bootstrap ├── app.php ├── autoload.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── filesystems.php ├── hashing.php ├── logging.php ├── mail.php ├── queue.php ├── services.php ├── session.php └── view.php ├── database ├── .gitignore ├── factories │ ├── AnswerFactory.php │ ├── QuestionFactory.php │ ├── TagFactory.php │ ├── UserFactory.php │ └── VoteFactory.php ├── migrations │ ├── 2017_04_09_000000_create_qna_schema.php │ ├── 2017_05_16_064641_create_notifications_table.php │ └── 2017_06_03_223031_notifications_foreign_key.php └── seeds │ └── DatabaseSeeder.php ├── npm-debug.log ├── package.json ├── phpunit.xml ├── public ├── .htaccess ├── css │ ├── app.css │ ├── editable.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff2 │ ├── mdb.min.css │ ├── style.css │ └── tags.css ├── favicon.ico ├── font │ └── roboto │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.eot │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Regular.woff │ │ ├── Roboto-Regular.woff2 │ │ ├── Roboto-Thin.eot │ │ ├── Roboto-Thin.ttf │ │ ├── Roboto-Thin.woff │ │ └── Roboto-Thin.woff2 ├── images │ └── screenshots │ │ ├── ScreenShot1.png │ │ ├── ScreenShot2.png │ │ ├── ScreenShot3.png │ │ └── ScreenShot4.png ├── index.php ├── js │ ├── app.js │ ├── editable.js │ ├── mdb.min.js │ ├── tags.js │ ├── typeahead │ │ ├── .gitignore │ │ ├── .jshintrc │ │ ├── .travis.yml │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── Gruntfile.js │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bower.json │ │ ├── composer.json │ │ ├── dist │ │ │ ├── bloodhound.js │ │ │ ├── bloodhound.min.js │ │ │ ├── typeahead.bundle.js │ │ │ ├── typeahead.bundle.min.js │ │ │ ├── typeahead.jquery.js │ │ │ └── typeahead.jquery.min.js │ │ ├── doc │ │ │ ├── bloodhound.md │ │ │ ├── jquery_typeahead.md │ │ │ └── migration │ │ │ │ └── 0.10.0.md │ │ ├── karma.conf.js │ │ ├── package.json │ │ ├── src │ │ │ ├── bloodhound │ │ │ │ ├── bloodhound.js │ │ │ │ ├── lru_cache.js │ │ │ │ ├── options_parser.js │ │ │ │ ├── persistent_storage.js │ │ │ │ ├── prefetch.js │ │ │ │ ├── remote.js │ │ │ │ ├── search_index.js │ │ │ │ ├── tokenizers.js │ │ │ │ ├── transport.js │ │ │ │ └── version.js │ │ │ ├── common │ │ │ │ └── utils.js │ │ │ └── typeahead │ │ │ │ ├── dataset.js │ │ │ │ ├── default_menu.js │ │ │ │ ├── event_bus.js │ │ │ │ ├── event_emitter.js │ │ │ │ ├── highlight.js │ │ │ │ ├── input.js │ │ │ │ ├── menu.js │ │ │ │ ├── plugin.js │ │ │ │ ├── typeahead.js │ │ │ │ └── www.js │ │ ├── test │ │ │ ├── bloodhound │ │ │ │ ├── bloodhound_spec.js │ │ │ │ ├── lru_cache_spec.js │ │ │ │ ├── options_parser_spec.js │ │ │ │ ├── persistent_storage_spec.js │ │ │ │ ├── prefetch_spec.js │ │ │ │ ├── remote_spec.js │ │ │ │ ├── search_index_spec.js │ │ │ │ ├── tokenizers_spec.js │ │ │ │ └── transport_spec.js │ │ │ ├── ci │ │ │ ├── fixtures │ │ │ │ ├── ajax_responses.js │ │ │ │ ├── data.js │ │ │ │ └── html.js │ │ │ ├── helpers │ │ │ │ └── typeahead_mocks.js │ │ │ ├── integration │ │ │ │ ├── test.html │ │ │ │ └── test.js │ │ │ ├── playground.html │ │ │ └── typeahead │ │ │ │ ├── dataset_spec.js │ │ │ │ ├── default_results_spec.js │ │ │ │ ├── event_bus_spec.js │ │ │ │ ├── event_emitter_spec.js │ │ │ │ ├── highlight_spec.js │ │ │ │ ├── input_spec.js │ │ │ │ ├── plugin_spec.js │ │ │ │ ├── results_spec.js │ │ │ │ └── typeahead_spec.js │ │ └── typeahead.js.jquery.json │ └── upvote.js ├── plugins │ ├── bootstrap-tagsinput │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── Gruntfile.js │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bootstrap-tagsinput.jquery.json │ │ ├── bower.json │ │ ├── dist │ │ │ ├── bootstrap-tagsinput-angular.js │ │ │ ├── bootstrap-tagsinput-angular.min.js │ │ │ ├── bootstrap-tagsinput-angular.min.js.map │ │ │ ├── bootstrap-tagsinput-typeahead.css │ │ │ ├── bootstrap-tagsinput.css │ │ │ ├── bootstrap-tagsinput.js │ │ │ ├── bootstrap-tagsinput.less │ │ │ ├── bootstrap-tagsinput.min.js │ │ │ ├── bootstrap-tagsinput.min.js.map │ │ │ └── bootstrap-tagsinput.zip │ │ ├── examples │ │ │ ├── assets │ │ │ │ ├── app.css │ │ │ │ ├── app.js │ │ │ │ ├── app_bs2.js │ │ │ │ ├── app_bs3.js │ │ │ │ ├── cities.json │ │ │ │ └── citynames.json │ │ │ ├── bootstrap-2.3.2.html │ │ │ ├── index.html │ │ │ └── lib │ │ │ │ ├── bootstrap-2.3.2 │ │ │ │ └── docs │ │ │ │ │ └── assets │ │ │ │ │ ├── css │ │ │ │ │ ├── bootstrap.css │ │ │ │ │ └── docs.css │ │ │ │ │ └── js │ │ │ │ │ └── bootstrap.min.js │ │ │ │ ├── bootstrap-3 │ │ │ │ └── dist │ │ │ │ │ ├── css │ │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ │ └── bootstrap.min.css │ │ │ │ │ └── js │ │ │ │ │ └── bootstrap.min.js │ │ │ │ ├── jquery │ │ │ │ └── dist │ │ │ │ │ └── jquery.min.js │ │ │ │ └── typeahead.js │ │ │ │ └── dist │ │ │ │ └── typeahead.bundle.js │ │ ├── karma.conf.js │ │ ├── package.json │ │ ├── src │ │ │ ├── bootstrap-tagsinput-angular.js │ │ │ ├── bootstrap-tagsinput-typeahead.css │ │ │ ├── bootstrap-tagsinput.css │ │ │ └── bootstrap-tagsinput.js │ │ └── test │ │ │ ├── bootstrap-tagsinput-angular.tests.js │ │ │ ├── bootstrap-tagsinput │ │ │ ├── events.tests.js │ │ │ ├── input_with_object_items.tests.js │ │ │ ├── input_with_string_items.tests.js │ │ │ ├── reproduced_bugs.tests.js │ │ │ ├── select_with_object_items.tests.js │ │ │ └── select_with_string_items.tests.js │ │ │ ├── helpers.js │ │ │ └── index.html │ └── jquery-upvote │ │ ├── images │ │ ├── sprites-meta-stackoverflow.png │ │ ├── sprites-programmers.png │ │ ├── sprites-serverfault.png │ │ ├── sprites-stackoverflow.png │ │ ├── sprites-superuser.png │ │ └── sprites-unix.png │ │ ├── jquery.upvote.css │ │ └── jquery.upvote.js ├── robots.txt ├── server.php └── web.config ├── readme.md ├── resources ├── assets │ ├── js │ │ ├── app.js │ │ ├── bootstrap.js │ │ └── components │ │ │ └── Example.vue │ └── sass │ │ ├── _variables.scss │ │ └── app.scss ├── lang │ └── en │ │ ├── auth.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php └── views │ ├── auth │ ├── login.blade.php │ ├── passwords │ │ ├── email.blade.php │ │ └── reset.blade.php │ └── register.blade.php │ ├── containers │ ├── answer.blade.php │ ├── question.blade.php │ ├── question_nolink.blade.php │ ├── question_novote.blade.php │ └── tags.blade.php │ ├── errors │ ├── 401.blade.php │ └── 404.blade.php │ ├── index.blade.php │ ├── layouts │ ├── app.blade.php │ ├── sidebar.blade.php │ └── sidebar_auth.blade.php │ ├── modals │ └── login.blade.php │ ├── question.blade.php │ ├── questions │ ├── ask.blade.php │ ├── edit.blade.php │ ├── new.blade.php │ └── top.blade.php │ ├── search.blade.php │ ├── tag.blade.php │ └── user │ ├── answers.blade.php │ ├── index.blade.php │ ├── notifications.blade.php │ └── questions.blade.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── CreatesApplication.php ├── Feature │ └── QuestionTest.php └── TestCase.php └── webpack.mix.js /.env.example: -------------------------------------------------------------------------------- 1 | APP_ENV=local 2 | APP_KEY= 3 | APP_DEBUG=true 4 | APP_LOG_LEVEL=debug 5 | APP_URL=http://localhost 6 | 7 | DB_CONNECTION=mysql 8 | DB_HOST=127.0.0.1 9 | DB_PORT=3306 10 | DB_DATABASE=homestead 11 | DB_USERNAME=homestead 12 | DB_PASSWORD=secret 13 | 14 | BROADCAST_DRIVER=log 15 | CACHE_DRIVER=file 16 | SESSION_DRIVER=file 17 | QUEUE_DRIVER=sync 18 | 19 | REDIS_HOST=127.0.0.1 20 | REDIS_PASSWORD=null 21 | REDIS_PORT=6379 22 | 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=mailtrap.io 25 | MAIL_PORT=2525 26 | MAIL_USERNAME=null 27 | MAIL_PASSWORD=null 28 | MAIL_ENCRYPTION=null 29 | 30 | PUSHER_APP_ID= 31 | PUSHER_APP_KEY= 32 | PUSHER_APP_SECRET= 33 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/storage 3 | /public/adminer.php 4 | /public/hot 5 | /storage/*.key 6 | /vendor 7 | /.idea 8 | Homestead.json 9 | Homestead.yaml 10 | .env 11 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-modernist -------------------------------------------------------------------------------- /app/Answer.php: -------------------------------------------------------------------------------- 1 | AnswerEvent::class, 12 | ]; 13 | 14 | public function user() 15 | { 16 | return $this->belongsTo(User::class); 17 | } 18 | 19 | public function question() 20 | { 21 | return $this->belongsTo(Question::class); 22 | } 23 | 24 | public function votes() 25 | { 26 | return $this->hasMany(Vote::class); 27 | } 28 | 29 | /** 30 | * Insert an answer. 31 | * @param $answer_text 32 | * @param $question_id 33 | * @param $user_id 34 | * @return Answer 35 | */ 36 | public static function insert($answer_text, $question_id, $user_id) 37 | { 38 | $answer = new self; 39 | $answer->answer = $answer_text; 40 | $answer->user_id = $user_id; 41 | $answer->question_id = $question_id; 42 | $answer->save(); 43 | 44 | return $answer; 45 | } 46 | 47 | /** 48 | * Update an answer. 49 | * @param $answer_id 50 | * @param $answer 51 | * @return bool 52 | */ 53 | public static function update_answer($answer_id, $answer) 54 | { 55 | $answer_data = self::whereId($answer_id)->first(); 56 | $answer_data->answer = $answer; 57 | if ($answer_data->save()) { 58 | return true; 59 | } 60 | } 61 | 62 | /** 63 | * Get answers and sort by vote sum(). 64 | * @param $question_id 65 | * @return mixed 66 | */ 67 | public static function get_sorted($question_id) 68 | { 69 | $answer = self::where('question_id', '=', $question_id)->get(); 70 | 71 | return $answer->sortByDesc(function ($answer) { 72 | return $answer->votes->sum('vote'); 73 | }); 74 | } 75 | 76 | /** 77 | * Get answers and sort by vote sum(). 78 | * @param $question_id 79 | * @return mixed 80 | */ 81 | public static function get_answer_ids($question_id) 82 | { 83 | $answer_ids = self::select('user_id')->distinct()->where('question_id', $question_id)->get()->toArray(); 84 | 85 | $answer_array = []; 86 | foreach ($answer_ids as $var) { 87 | $answer_array[] = $var['user_id']; 88 | } 89 | 90 | return $answer_array; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/Classes/QuestionValidation.php: -------------------------------------------------------------------------------- 1 | join('tags', 'tags.id', '=', 'question_tag.tag_id') 20 | ->select('questions.*') 21 | ->where('question', '=', $question); 22 | foreach ($tags as $tag_id) { 23 | $rec = $does_exist->whereHas('tags', function ($q) use ($tag_id) { 24 | $q->where('question_tag.tag_id', $tag_id); 25 | }); 26 | } 27 | $questions = $rec->get(); 28 | 29 | if (isset($questions[0])) { 30 | return $questions[0]; 31 | } else { 32 | return false; 33 | } 34 | } 35 | 36 | public static function CheckDuplicateLoose($question, $tag) 37 | { 38 | $tags = explode(',', $tag); 39 | 40 | $does_exist = Question::join('question_tag', 'question_tag.question_id', '=', 'questions.id') 41 | ->join('tags', 'tags.id', '=', 'question_tag.tag_id') 42 | ->select('questions.*') 43 | ->where('question', '=', $question) 44 | ->whereIn('id', $tags) 45 | ->get(); 46 | 47 | if (isset($does_exist[0])) { 48 | return $does_exist[0]; 49 | } else { 50 | return false; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/Classes/Url.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 28 | } 29 | 30 | /** 31 | * Register the commands for the application. 32 | * 33 | * @return void 34 | */ 35 | protected function commands() 36 | { 37 | $this->load(__DIR__.'/Commands'); 38 | 39 | require base_path('routes/console.php'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Events/AnswerEvent.php: -------------------------------------------------------------------------------- 1 | answer = $answer; 25 | } 26 | 27 | /** 28 | * Get the channels the event should broadcast on. 29 | * 30 | * @return Channel|array 31 | */ 32 | public function broadcastOn() 33 | { 34 | return new PrivateChannel('channel-name'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Events/VoteEvent.php: -------------------------------------------------------------------------------- 1 | vote = $vote; 25 | } 26 | 27 | /** 28 | * Get the channels the event should broadcast on. 29 | * 30 | * @return Channel|array 31 | */ 32 | public function broadcastOn() 33 | { 34 | return new PrivateChannel('channel-name'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | id); 22 | Session::flash('flash_message', '

Thanks for answering the question!

'); 23 | 24 | return Redirect::to('question/'.Request::get('question_id').'/'.Request::get('question_url')); 25 | } 26 | 27 | /** 28 | * Update the answer from jquery. 29 | * @return Response 30 | */ 31 | public function update() 32 | { 33 | $answer = Answer::update_answer(Request::get('pk'), Request::get('value')); 34 | if ($answer) { 35 | return Response::json(['status'=>1]); 36 | } else { 37 | return Response::json(['status'=>0]); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest', ['except' => 'logout']); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 40 | } 41 | 42 | /** 43 | * Get a validator for an incoming registration request. 44 | * 45 | * @param array $data 46 | * @return \Illuminate\Contracts\Validation\Validator 47 | */ 48 | protected function validator(array $data) 49 | { 50 | return Validator::make($data, [ 51 | 'name' => 'required|max:255', 52 | 'email' => 'required|email|max:255|unique:users', 53 | 'password' => 'required|min:6|confirmed', 54 | ]); 55 | } 56 | 57 | /** 58 | * Create a new user instance after a valid registration. 59 | * 60 | * @param array $data 61 | * @return User 62 | */ 63 | protected function create(array $data) 64 | { 65 | return User::create([ 66 | 'name' => $data['name'], 67 | 'email' => $data['email'], 68 | 'password' => bcrypt($data['password']), 69 | ]); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | paginate(10); 17 | $top = Question::top_limited(3); 18 | 19 | return view('index')->with('questions', $questions)->with('top', $top)->with('page_title', 'Q&A - Interview Questions'); 20 | } 21 | 22 | /** 23 | * Show the homepage. 24 | * @return View 25 | */ 26 | public function search() 27 | { 28 | $query = Input::get('query'); 29 | $questions = Question::search($query); 30 | 31 | return view('search')->with('questions', $questions)->with('page_title', 'Search')->with('query', $query); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Controllers/TagController.php: -------------------------------------------------------------------------------- 1 | $tag, 21 | 'questions' => Question::recent_relevant($tag->pluck('name')->toArray()), 22 | 'page_title' => 'Newest ' . $tag->name . ' Questions', 23 | 'sort' => 'new', 24 | 'tags' => Tag::get_tags() 25 | ] 26 | ); 27 | } 28 | 29 | /** 30 | * Show show top tag questions. 31 | * 32 | * @param Tag $tag 33 | * @return Response 34 | */ 35 | public function show_top(Tag $tag) 36 | { 37 | return view('tag', 38 | [ 39 | 'tag_info' => $tag, 40 | 'questions' => Question::top_relevant($tag->pluck('name')->toArray()), 41 | 'page_title' => 'Top ' . $tag->name . ' Questions', 42 | 'sort' => 'top', 43 | 'tags' => Tag::get_tags() 44 | ] 45 | ); 46 | } 47 | 48 | /** 49 | * Get the top questions according to votes. 50 | * @param Tag $tag 51 | * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View 52 | */ 53 | public function show_most_answered(Tag $tag) 54 | { 55 | return view('tag', 56 | [ 57 | 'tag_info' => $tag, 58 | 'questions' => Question::most_answered($tag->pluck('name')->toArray()), 59 | 'page_title' => 'Most Answered ' . $tag->name . ' Questions', 60 | 'sort' => 'top_answered' 61 | ] 62 | ); 63 | } 64 | 65 | /** 66 | * Get unanswered questions according to votes. 67 | * @param Tag $tag 68 | * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View 69 | */ 70 | public function show_unanswered(Tag $tag) 71 | { 72 | return view('tag', 73 | [ 74 | 'tag_info' => $tag, 75 | 'questions' => Question::unanswered($tag->pluck('name')->toArray()), 76 | 'page_title' => 'Unanswered ' . $tag->name . ' Questions', 77 | 'sort' => 'not_answered' 78 | ] 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/Http/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | take(10)->orderBy('id', 'DESC')->get(); 27 | $answers = Answer::where('user_id', '=', $id)->take(10)->orderBy('id', 'DESC')->get(); 28 | 29 | return view('user.index')->with('questions', $questions)->with('user', $user)->with('answers', $answers)->with('page_title', $user->name.''); 30 | } 31 | 32 | public function questions($id) 33 | { 34 | $user = User::findOrFail($id); 35 | $questions = Question::where('user_id', '=', $id)->orderBy('id', 'DESC')->paginate(10); 36 | 37 | return view('user.questions')->with('questions', $questions)->with('user', $user)->with('page_title', $user->name.' Questions'); 38 | } 39 | 40 | public function answers($id) 41 | { 42 | $user = User::findOrFail($id); 43 | $answers = Answer::where('user_id', '=', $id)->orderBy('id', 'DESC')->paginate(10); 44 | 45 | return view('user.answers')->with('user', $user)->with('answers', $answers)->with('page_title', $user->name.'Answers'); 46 | } 47 | 48 | public function participation($id) 49 | { 50 | $user = User::findOrFail($id); 51 | $questions = User::get_participation($id); 52 | 53 | return view('user.participation')->with('user', $user)->with('questions', $questions)->with('page_title', $user->name.'Answers'); 54 | } 55 | 56 | public function notifications($id) 57 | { 58 | if (! isset(Auth::user()->id)) { 59 | abort(401, 'Unauthorized'); 60 | } 61 | 62 | if (Auth::user()->id == $id) { 63 | $user = User::findOrFail($id); 64 | 65 | return view('user.notifications')->with('user', $user)->with('user', $user)->with('page_title', $user->name.'Notifications'); 66 | } else { 67 | abort(401, 'Unauthorized'); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/Http/Controllers/VoteController.php: -------------------------------------------------------------------------------- 1 | [ 32 | \App\Http\Middleware\EncryptCookies::class, 33 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 34 | \Illuminate\Session\Middleware\StartSession::class, 35 | // \Illuminate\Session\Middleware\AuthenticateSession::class, 36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 37 | \App\Http\Middleware\VerifyCsrfToken::class, 38 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 39 | ], 40 | 41 | 'api' => [ 42 | 'throttle:60,1', 43 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 44 | ], 45 | ]; 46 | 47 | /** 48 | * The application's route middleware. 49 | * 50 | * These middleware may be assigned to groups or used individually. 51 | * 52 | * @var array 53 | */ 54 | protected $routeMiddleware = [ 55 | 'auth' => \App\Http\Middleware\Authenticate::class, 56 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 57 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 58 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 59 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 60 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 61 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 62 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 63 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 64 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 65 | ]; 66 | } 67 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckForMaintenanceMode.php: -------------------------------------------------------------------------------- 1 | check()) { 22 | return redirect(RouteServiceProvider::HOME); 23 | } 24 | 25 | return $next($request); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | answer->toArray(); 35 | $question = Question::find($answer['question_id']); 36 | $user = User::find($question->user_id); 37 | Notification::send($user, new Answer($answer)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Listeners/VoteListener.php: -------------------------------------------------------------------------------- 1 | vote->toArray(); 35 | if (isset($vote['question_id'])) { 36 | $question = Question::find($vote['question_id']); 37 | $user = User::find($question->user_id); 38 | Notification::send($user, new Vote($vote)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Notifications/Answer.php: -------------------------------------------------------------------------------- 1 | answer = $answer; 24 | } 25 | 26 | /** 27 | * Get the notification's delivery channels. 28 | * 29 | * @param mixed $notifiable 30 | * @return array 31 | */ 32 | public function via($notifiable) 33 | { 34 | return ['mail', 'database']; 35 | } 36 | 37 | /** 38 | * Get the mail representation of the notification. 39 | * 40 | * @param mixed $notifiable 41 | * @return \Illuminate\Notifications\Messages\MailMessage 42 | */ 43 | public function toMail($notifiable) 44 | { 45 | $question = Question::find($this->answer['question_id']); 46 | $user = User::find($this->answer['user_id']); 47 | 48 | return (new MailMessage) 49 | ->subject('Someone Answered Your Question') 50 | ->greeting('Someone Answered Your Question!') 51 | ->line($question->question) 52 | ->line($user->name.' Said') 53 | ->line('"'.$this->answer['answer'].'"') 54 | ->action('See All Answers', url('/question/'.$question->id.'/'.Url::get_slug($question->question))); 55 | } 56 | 57 | /** 58 | * Get the mail representation of the notification. 59 | * 60 | * @param mixed $notifiable 61 | * @return \Illuminate\Notifications\Messages\MailMessage 62 | */ 63 | public function toDatabase($notifiable) 64 | { 65 | $question = Question::find($this->answer['question_id']); 66 | 67 | return [ 68 | 'question_id' => $question->id, 69 | 'answer_id' => $this->answer['id'], 70 | 'user_id' => $this->answer['user_id'], 71 | 'created_at' => Carbon::now(), 72 | ]; 73 | } 74 | 75 | /** 76 | * Get the array representation of the notification. 77 | * 78 | * @param mixed $notifiable 79 | * @return array 80 | */ 81 | public function toArray($notifiable) 82 | { 83 | return []; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/Notifications/Vote.php: -------------------------------------------------------------------------------- 1 | vote = $vote; 19 | } 20 | 21 | /** 22 | * Get the notification's delivery channels. 23 | * 24 | * @param mixed $notifiable 25 | * @return array 26 | */ 27 | public function via($notifiable) 28 | { 29 | return ['database']; 30 | } 31 | 32 | /** 33 | * Get the mail representation of the notification. 34 | * 35 | * @param mixed $notifiable 36 | * @return \Illuminate\Notifications\Messages\MailMessage 37 | */ 38 | public function toDatabase($notifiable) 39 | { 40 | return [ 41 | 'question_id' => $this->vote['question_id'], 42 | 'user_id' => $this->vote['user_id'], 43 | 'vote' => $this->vote['vote'], 44 | ]; 45 | } 46 | 47 | /** 48 | * Get the array representation of the notification. 49 | * 50 | * @param mixed $notifiable 51 | * @return array 52 | */ 53 | public function toArray($notifiable) 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/Policies/QuestionPolicy.php: -------------------------------------------------------------------------------- 1 | id === $question->user_id; 57 | } 58 | 59 | /** 60 | * Determine whether the user can delete the model. 61 | * 62 | * @param User $user 63 | * @param Question $question 64 | * @return mixed 65 | */ 66 | public function delete(User $user, Question $question) 67 | { 68 | return $user->id === $question->user_id; 69 | } 70 | 71 | /** 72 | * Determine whether the user can restore the model. 73 | * 74 | * @param User $user 75 | * @param Question $question 76 | * @return mixed 77 | */ 78 | public function restore(User $user, Question $question) 79 | { 80 | // 81 | } 82 | 83 | /** 84 | * Determine whether the user can permanently delete the model. 85 | * 86 | * @param User $user 87 | * @param Question $question 88 | * @return mixed 89 | */ 90 | public function forceDelete(User $user, Question $question) 91 | { 92 | // 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | composer('containers.tags', function ($view) { 29 | $view->with('tags', \App\Tag::get_tags()); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 16 | ]; 17 | 18 | /** 19 | * Register any authentication / authorization services. 20 | * 21 | * @return void 22 | */ 23 | public function boot() 24 | { 25 | $this->registerPolicies(); 26 | 27 | // 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | 'App\Listeners\AnswerListener', 20 | ], 21 | 'App\Events\VoteEvent' => [ 22 | 'App\Listeners\VoteListener', 23 | ], 24 | Registered::class => [ 25 | SendEmailVerificationNotification::class, 26 | ], 27 | ]; 28 | 29 | /** 30 | * Register any events for your application. 31 | * 32 | * @return void 33 | */ 34 | public function boot() 35 | { 36 | parent::boot(); 37 | 38 | // 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 46 | 47 | $this->mapWebRoutes(); 48 | 49 | // 50 | } 51 | 52 | /** 53 | * Define the "web" routes for the application. 54 | * 55 | * These routes all receive session state, CSRF protection, etc. 56 | * 57 | * @return void 58 | */ 59 | protected function mapWebRoutes() 60 | { 61 | Route::middleware('web') 62 | ->namespace($this->namespace) 63 | ->group(base_path('routes/web.php')); 64 | } 65 | 66 | /** 67 | * Define the "api" routes for the application. 68 | * 69 | * These routes are typically stateless. 70 | * 71 | * @return void 72 | */ 73 | protected function mapApiRoutes() 74 | { 75 | Route::prefix('api') 76 | ->middleware('api') 77 | ->namespace($this->namespace) 78 | ->group(base_path('routes/api.php')); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/Tag.php: -------------------------------------------------------------------------------- 1 | belongsToMany(Question::class, 'question_tag', 'tag_id', 'question_id'); 15 | } 16 | 17 | /** 18 | * Returns an object off all the tags being used by questions. 19 | * @return object 20 | * todo this should be cached 21 | */ 22 | public static function get_tags() 23 | { 24 | return self::distinct()->orderBy('name', 'asc')->get(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/User.php: -------------------------------------------------------------------------------- 1 | email; 22 | } 23 | 24 | /** 25 | * The attributes that are mass assignable. 26 | * 27 | * @var array 28 | */ 29 | protected $fillable = [ 30 | 'name', 'email', 'password', 31 | ]; 32 | 33 | /** 34 | * The attributes that should be hidden for arrays. 35 | * 36 | * @var array 37 | */ 38 | protected $hidden = [ 39 | 'password', 'remember_token', 40 | ]; 41 | 42 | public function votes() 43 | { 44 | return $this->hasMany('App\Vote'); 45 | } 46 | 47 | /** 48 | * Needs mysql 5.7 49 | * Would allow to check past notifications. 50 | * 51 | * @param $question_id 52 | * @return mixed 53 | */ 54 | public static function get_meta($question_id) 55 | { 56 | return DB::table('notifications') 57 | ->where('data->question_id', '=', $question_id) 58 | ->get(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/Vote.php: -------------------------------------------------------------------------------- 1 | VoteEvent::class, 15 | 'updated' => VoteEvent::class, 16 | ]; 17 | 18 | protected $fillable = [ 19 | 'user_id', 20 | 'answer_id', 21 | 'question_id', 22 | 'vote', 23 | ]; 24 | 25 | public function user() 26 | { 27 | return $this->belongsTo(User::class); 28 | } 29 | 30 | public function answer() 31 | { 32 | return $this->belongsTo(Answer::class); 33 | } 34 | 35 | public function question() 36 | { 37 | return $this->belongsTo(Question::class); 38 | } 39 | 40 | /** 41 | * Insert/Update & Delete from votes table 42 | * If identical previous/new vote destroy otherwise insert/update. 43 | * @param $user_id 44 | * @param $id - ID question/answer 45 | * @param $vote - Integer of vote value 46 | * @param $column - the vote table uses question_id or answer_id 47 | * @return array 48 | */ 49 | public static function vote($user_id, $id, $vote, $column) 50 | { 51 | $voted = self::where('user_id', $user_id)->where($column, $id)->first(); 52 | if (isset($voted->vote) && $voted->vote == $vote) { 53 | self::destroy($voted->id); 54 | $ajax_response = ['status' => 'success', 'msg' => "Vote nullified on $column $id"]; 55 | } else { 56 | self::updateOrCreate([$column => $id, 'user_id' => $user_id], ['vote' => $vote]); 57 | $ajax_response = ['status' => 'success', 'msg' => "Vote cast on $column $id"]; 58 | } 59 | 60 | return $ajax_response; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/autoload.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'useTLS' => true, 41 | ], 42 | ], 43 | 44 | 'redis' => [ 45 | 'driver' => 'redis', 46 | 'connection' => 'default', 47 | ], 48 | 49 | 'log' => [ 50 | 'driver' => 'log', 51 | ], 52 | 53 | 'null' => [ 54 | 'driver' => 'null', 55 | ], 56 | 57 | ], 58 | 59 | ]; 60 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['api/*'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Cloud Filesystem Disk 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Many applications store files both locally and in the cloud. For this 24 | | reason, you may specify a default "cloud" driver here. This driver 25 | | will be bound as the Cloud disk implementation in the container. 26 | | 27 | */ 28 | 29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Filesystem Disks 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may configure as many filesystem "disks" as you wish, and you 37 | | may even configure multiple disks of the same driver. Defaults have 38 | | been setup for each driver as an example of the required options. 39 | | 40 | | Supported Drivers: "local", "ftp", "sftp", "s3" 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'url' => env('APP_URL').'/storage', 55 | 'visibility' => 'public', 56 | ], 57 | 58 | 's3' => [ 59 | 'driver' => 's3', 60 | 'key' => env('AWS_ACCESS_KEY_ID'), 61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 62 | 'region' => env('AWS_DEFAULT_REGION'), 63 | 'bucket' => env('AWS_BUCKET'), 64 | 'url' => env('AWS_URL'), 65 | 'endpoint' => env('AWS_ENDPOINT'), 66 | ], 67 | 68 | ], 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Symbolic Links 73 | |-------------------------------------------------------------------------- 74 | | 75 | | Here you may configure the symbolic links that will be created when the 76 | | `storage:link` Artisan command is executed. The array keys should be 77 | | the locations of the links and the values should be their targets. 78 | | 79 | */ 80 | 81 | 'links' => [ 82 | public_path('storage') => storage_path('app/public'), 83 | ], 84 | 85 | ]; 86 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /database/factories/AnswerFactory.php: -------------------------------------------------------------------------------- 1 | define(App\Answer::class, function (Faker $faker) { 8 | return [ 9 | 'user_id' => factory(App\User::class), 10 | 'question_id' => factory(App\Question::class), 11 | 'answer' => $faker->text, 12 | ]; 13 | }); 14 | -------------------------------------------------------------------------------- /database/factories/QuestionFactory.php: -------------------------------------------------------------------------------- 1 | define(App\Question::class, function (Faker $faker) { 8 | return [ 9 | 'user_id' => factory(App\User::class), 10 | 'question' => $faker->word, 11 | 'level' => 'Beginner', 12 | 'solved' => $faker->boolean, 13 | ]; 14 | }); 15 | -------------------------------------------------------------------------------- /database/factories/TagFactory.php: -------------------------------------------------------------------------------- 1 | define(App\Tag::class, function (Faker $faker) { 8 | return [ 9 | 'name' => $faker->name, 10 | 'display' => $faker->word, 11 | 'deleted_at' => $faker->dateTime(), 12 | ]; 13 | }); 14 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(App\User::class, function (Faker $faker) { 8 | return [ 9 | 'name' => $faker->name, 10 | 'email' => $faker->safeEmail, 11 | 'email_verified_at' => $faker->dateTime(), 12 | 'password' => bcrypt('secret'), 13 | 'remember_token' => Str::random(10), 14 | ]; 15 | }); -------------------------------------------------------------------------------- /database/factories/VoteFactory.php: -------------------------------------------------------------------------------- 1 | define(App\Vote::class, function (Faker $faker) { 8 | return [ 9 | 'user_id' => factory(App\User::class), 10 | 'question_id' => factory(App\Question::class), 11 | 'answer_id' => factory(App\Answer::class), 12 | 'vote' => $faker->randomNumber(), 13 | ]; 14 | }); 15 | -------------------------------------------------------------------------------- /database/migrations/2017_05_16_064641_create_notifications_table.php: -------------------------------------------------------------------------------- 1 | uuid('id')->primary(); 18 | $table->string('type'); 19 | $table->morphs('notifiable'); 20 | $table->text('data'); 21 | $table->timestamp('read_at')->nullable(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('notifications'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2017_06_03_223031_notifications_foreign_key.php: -------------------------------------------------------------------------------- 1 | foreign('notifiable_id') 18 | ->references('id')->on('users') 19 | ->onDelete('cascade'); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UsersTableSeeder::class); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 5 | "watch": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch-poll": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "hot": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 8 | "production": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 9 | }, 10 | "devDependencies": { 11 | "axios": "^0.15.3", 12 | "bootstrap-sass": "^3.3.7", 13 | "jquery": "^3.1.1", 14 | "laravel-mix": "^0.8.1", 15 | "lodash": "^4.17.4", 16 | "vue": "^2.1.10" 17 | }, 18 | "dependencies": { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Unit 14 | 15 | 16 | ./tests/Feature 17 | 18 | 19 | 20 | 21 | 22 | ./app 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /public/css/editable.css: -------------------------------------------------------------------------------- 1 | /* Make inline editables take the full width of their parents */ 2 | .editable-container.editable-inline, 3 | .editable-container.editable-inline .control-group.form-group, 4 | .editable-container.editable-inline .control-group.form-group .editable-input, 5 | .editable-container.editable-inline .control-group.form-group .editable-input textarea, 6 | .editable-container.editable-inline .control-group.form-group .editable-input select, 7 | .editable-container.editable-inline .control-group.form-group .editable-input input:not([type=radio]):not([type=checkbox]):not([type=submit]) 8 | { 9 | width: 95%; 10 | } 11 | .editable-custom 12 | { 13 | cursor: pointer; 14 | border: none; 15 | } -------------------------------------------------------------------------------- /public/css/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/css/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/css/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/css/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/css/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/css/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/css/tags.css: -------------------------------------------------------------------------------- 1 | .tt-input { 2 | height:24px; 3 | padding:5px; 4 | } 5 | 6 | .tt-suggestion:hover { /* UPDATE: newer versions use .tt-suggestion.tt-cursor */ 7 | color: #fff; 8 | background-color: #0097cf; 9 | cursor: pointer; 10 | } 11 | 12 | .tt-menu.tt-open { 13 | top: 10px !important; 14 | } 15 | 16 | .tt-query { 17 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 18 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 19 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 20 | } 21 | 22 | .tt-hint { 23 | color: #999 24 | } 25 | 26 | .tt-dropdown-menu { 27 | width: 422px; 28 | margin-top: 4px; 29 | padding: 4px 0; 30 | background-color: #fff; 31 | border: 1px solid #ccc; 32 | border: 1px solid rgba(0, 0, 0, 0.2); 33 | -webkit-border-radius: 4px; 34 | -moz-border-radius: 4px; 35 | border-radius: 4px; 36 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 37 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 38 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 39 | } 40 | 41 | .tt-suggestion { 42 | padding: 3px 20px; 43 | line-height: 24px; 44 | } 45 | 46 | .tt-suggestion.tt-cursor { 47 | color: #fff; 48 | background-color: #0097cf; 49 | 50 | } 51 | 52 | .tt-suggestion p { 53 | margin: 0; 54 | } 55 | 56 | 57 | .bootstrap-tagsinput .label { 58 | background-color: #0097cf; 59 | display:inline-block; 60 | font-size: 110%; 61 | font-weight: 700; 62 | line-height: 1; 63 | color: #fff; 64 | text-align: center; 65 | white-space: nowrap; 66 | vertical-align: middle; 67 | border-radius: .25em; 68 | margin: 20px 10px 0px 0px; 69 | padding: .2em .6em .3em; 70 | } 71 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/favicon.ico -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /public/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /public/images/screenshots/ScreenShot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/images/screenshots/ScreenShot1.png -------------------------------------------------------------------------------- /public/images/screenshots/ScreenShot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/images/screenshots/ScreenShot2.png -------------------------------------------------------------------------------- /public/images/screenshots/ScreenShot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/images/screenshots/ScreenShot3.png -------------------------------------------------------------------------------- /public/images/screenshots/ScreenShot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealJAG/Laravel-QuestionAnswer/8853ed40cbcf008e04962b964851ff8da4a2e28f/public/images/screenshots/ScreenShot4.png -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | 9 | /* 10 | |-------------------------------------------------------------------------- 11 | | Register The Auto Loader 12 | |-------------------------------------------------------------------------- 13 | | 14 | | Composer provides a convenient, automatically generated class loader for 15 | | our application. We just need to utilize it! We'll simply require it 16 | | into the script here so that we don't have to worry about manual 17 | | loading any of our classes later on. It feels nice to relax. 18 | | 19 | */ 20 | 21 | require __DIR__.'/../bootstrap/autoload.php'; 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Turn On The Lights 26 | |-------------------------------------------------------------------------- 27 | | 28 | | We need to illuminate PHP development, so let us turn on the lights. 29 | | This bootstraps the framework and gets it ready for use, then it 30 | | will load up this application so that we can run it and send 31 | | the responses back to the browser and delight our users. 32 | | 33 | */ 34 | 35 | $app = require_once __DIR__.'/../bootstrap/app.php'; 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Run The Application 40 | |-------------------------------------------------------------------------- 41 | | 42 | | Once we have the application, we can handle the incoming request 43 | | through the kernel, and send the associated response back to 44 | | the client's browser allowing them to enjoy the creative 45 | | and wonderful application we have prepared for them. 46 | | 47 | */ 48 | 49 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 50 | 51 | $response = $kernel->handle( 52 | $request = Illuminate\Http\Request::capture() 53 | ); 54 | 55 | $response->send(); 56 | 57 | $kernel->terminate($request, $response); 58 | -------------------------------------------------------------------------------- /public/js/editable.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | 3 | $("body").tooltip({ 4 | selector: '[data-title]' 5 | }); 6 | 7 | $.fn.editable.defaults.mode = 'inline'; 8 | $.fn.editable.defaults.params = function (params) { 9 | params._token = $("#_token").data("token"); 10 | return params; 11 | }; 12 | $('.answer').editable({ 13 | url: '/answer/update', 14 | type: 'textarea', 15 | name: 'answer', 16 | rows: 10, 17 | send:'always', 18 | ajaxOptions: { 19 | dataType: 'json' 20 | } 21 | }); 22 | }) -------------------------------------------------------------------------------- /public/js/tags.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | var elt = $('#txtTags'); 3 | 4 | var tags = new Bloodhound({ 5 | datumTokenizer: Bloodhound.tokenizers.obj.whitespace('id'), 6 | queryTokenizer: Bloodhound.tokenizers.whitespace, 7 | remote: { 8 | url: '/api/find?keyword=%QUERY%', 9 | wildcard: '%QUERY%', 10 | } 11 | }); 12 | 13 | tags.initialize(); 14 | 15 | $('#txtTags').tagsinput({ 16 | itemValue : 'id', 17 | itemText : 'name', 18 | maxTags: 3, 19 | maxChars: 10, 20 | trimValue: true, 21 | allowDuplicates : false, 22 | freeInput: false, 23 | tagClass: function(item) { 24 | if(item.display) 25 | return 'label label-' + item.display; 26 | else 27 | return 'label label-default'; 28 | 29 | }, 30 | onTagExists: function(item, $tag) { 31 | $tag.hide().fadeIn(); 32 | }, 33 | typeaheadjs: [{ 34 | hint: false, 35 | highlight: true 36 | }, 37 | { 38 | name: 'tags', 39 | itemValue: 'id', 40 | displayKey: 'name', 41 | source: tags.ttAdapter(), 42 | templates: { 43 | empty: [ 44 | '' 45 | ], 46 | header: [ 47 | '