Add UUID instead of actual ID to identify contacts (#777)

Close #381
This commit is contained in:
Danny
2018-04-08 13:23:13 -05:00
committed by Régis Freyd
parent 04607f3eb5
commit 3ba96cf18b
61 changed files with 618 additions and 119 deletions
+5
View File
@@ -12,6 +12,11 @@ APP_DEBUG=false
# Use `php artisan key:generate` to generate a random key.
APP_KEY=ChangeMeBy32KeyLengthOrGenerated
# Prevent information leakage by referring to IDs with hashIds instead of
# the actual IDs used in the database.
HASH_SALT=ChangeMeBy20+KeyLength
HASH_LENGTH=18
# The URL of your application.
APP_URL=http://localhost
+2
View File
@@ -30,6 +30,8 @@ RUN apk update && apk upgrade; \
php7-mysqli php7-pdo_mysql \
#- pgsql
php7-pgsql php7-pdo_pgsql \
#- vinkla/hashids
php7-bcmath \
#- sentry/sentry
php7-curl; \
# Create apache2 dir needed for httpd
+2
View File
@@ -3,6 +3,7 @@
namespace App;
use Carbon\Carbon;
use App\Traits\Hasher;
use App\Traits\Journalable;
use Illuminate\Database\Eloquent\Model;
use App\Interfaces\IsJournalableInterface;
@@ -17,6 +18,7 @@ use App\Http\Resources\Contact\ContactShort as ContactShortResource;
class Activity extends Model implements IsJournalableInterface
{
use Journalable;
use Hasher;
/**
* The table associated with the model.
+2
View File
@@ -3,6 +3,7 @@
namespace App;
use DB;
use App\Traits\Hasher;
use App\Traits\Searchable;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
@@ -21,6 +22,7 @@ use App\Http\Resources\ContactField\ContactField as ContactFieldResource;
class Contact extends Model
{
use Searchable;
use Hasher;
protected $dates = [
'last_talked_to',
+2
View File
@@ -2,6 +2,7 @@
namespace App;
use App\Traits\Hasher;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
@@ -14,6 +15,7 @@ use Illuminate\Database\Eloquent\Builder;
*/
class Debt extends Model
{
use Hasher;
/**
* The attributes that aren't mass assignable.
*
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Helpers;
use Vinkla\Hashids\Facades\Hashids;
class IdHasher
{
/**
* Prefix for ids.
*
* @var string
*/
protected $prefix;
/**
* Create a new IdHasher.
*
* @param string|null $prefix
*/
public function __construct($prefix = null)
{
$this->prefix = $prefix ?? config('hashids.default_prefix');
}
public function encodeId($id)
{
return $this->prefix.Hashids::encode($id);
}
public function decodeId($hash)
{
if (starts_with($hash, $this->prefix)) {
$result = Hashids::decode(str_after($hash, $this->prefix));
return $result[0]; // result is always an array due to quirk in Hashids libary
} else {
return $hash;
}
}
}
@@ -68,7 +68,7 @@ class ActivitiesController extends Controller
// Log a journal entry
(new JournalEntry)->add($activity);
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.activities_add_success'));
}
@@ -153,7 +153,7 @@ class ActivitiesController extends Controller
$newContact->logEvent('activity', $activity->id, 'create');
}
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.activities_update_success'));
}
@@ -174,7 +174,7 @@ class ActivitiesController extends Controller
$contact->calculateActivitiesStatistics();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.activities_delete_success'));
}
}
@@ -32,7 +32,7 @@ class CallsController extends Controller
$contact->updateLastCalledInfo($call);
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.calls_add_success'));
}
@@ -58,7 +58,7 @@ class CallsController extends Controller
$contact->save();
}
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.call_delete_success'));
}
}
@@ -57,7 +57,7 @@ class DebtController extends Controller
$contact->logEvent('debt', $debt->id, 'create');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.debt_add_success'));
}
@@ -111,7 +111,7 @@ class DebtController extends Controller
$contact->logEvent('debt', $debt->id, 'update');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.debt_edit_success'));
}
@@ -128,7 +128,7 @@ class DebtController extends Controller
$contact->events()->forObject($debt)->get()->each->delete();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.debt_delete_success'));
}
}
@@ -23,6 +23,7 @@ class GiftsController extends Controller
foreach ($gifts as $gift) {
$data = [
'contact_hash' => $contact->hashID(),
'id' => $gift->id,
'name' => $gift->name,
'is_for' => $gift->recipient_name,
@@ -105,7 +106,7 @@ class GiftsController extends Controller
$contact->logEvent('gift', $gift->id, 'create');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.gifts_add_success'));
}
@@ -154,7 +155,7 @@ class GiftsController extends Controller
$contact->logEvent('gift', $gift->id, 'update');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.gifts_update_success'));
}
@@ -68,7 +68,7 @@ class IntroductionsController extends Controller
$contact->logEvent('contact', $contact->id, 'update');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.introductions_update_success'));
}
@@ -85,7 +85,7 @@ class IntroductionsController extends Controller
$contact->events()->forObject($gift)->get()->each->delete();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.gifts_delete_success'));
}
}
@@ -147,7 +147,7 @@ class RelationshipsController extends Controller
$partner->save();
}
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.relationship_form_add_success'));
}
@@ -265,7 +265,7 @@ class RelationshipsController extends Controller
$otherContact->save();
}
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.relationship_form_add_success'));
}
@@ -288,15 +288,13 @@ class RelationshipsController extends Controller
$type = $contact->getRelationshipNatureWith($otherContact);
$contact->deleteRelationship($otherContact, $type->relationship_type_id);
// the contact is partial - if the relationship is deleted, the partial
// contact has no reason to exist anymore
if ($otherContact->is_partial) {
$otherContact->deleteEverything();
}
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.relationship_form_deletion_success'));
}
}
@@ -58,7 +58,7 @@ class RemindersController extends Controller
$contact->logEvent('reminder', $reminder->id, 'create');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.reminders_create_success'));
}
@@ -114,7 +114,7 @@ class RemindersController extends Controller
$contact->logEvent('reminder', $reminder->id, 'update');
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.reminders_update_success'));
}
@@ -137,7 +137,7 @@ class RemindersController extends Controller
$contact->events()->forObject($reminder)->get()->each->delete();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.reminders_delete_success'));
}
}
+8 -4
View File
@@ -155,7 +155,7 @@ class ContactsController extends Controller
// Did the user press "Save" or "Submit and add another person"
if (! is_null($request->get('save'))) {
return redirect()->route('people.show', ['id' => $contact->id]);
return redirect()->route('people.show', ['id' => $contact->hashID()]);
} else {
return redirect()->route('people.create')
->with('status', trans('people.people_add_success', ['name' => $contact->getCompleteName(auth()->user()->name_order)]));
@@ -336,7 +336,7 @@ class ContactsController extends Controller
$contact->updateGravatar();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.information_edit_success'));
}
@@ -387,7 +387,7 @@ class ContactsController extends Controller
$contact->save();
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.work_edit_success'));
}
@@ -417,7 +417,7 @@ class ContactsController extends Controller
$contact->updateFoodPreferencies($food);
return redirect('/people/'.$contact->id)
return redirect('/people/'.$contact->hashID())
->with('success', trans('people.food_preferencies_add_success'));
}
@@ -461,6 +461,10 @@ class ContactsController extends Controller
}
if (count($results) !== 0) {
foreach ($results as $key => $result) {
$results[$key]->hash = $result->hashID();
}
return $results;
} else {
return ['noResults' => trans('people.people_search_no_results')];
+3 -3
View File
@@ -28,7 +28,7 @@ class DashboardController extends Controller
$lastUpdatedContacts = $account->contacts()->where('is_partial', false)->latest('updated_at')->limit(10)->get();
foreach ($lastUpdatedContacts as $contact) {
$data = [
'id' => $contact->id,
'id' => $contact->hashID(),
'has_avatar' => $contact->has_avatar,
'avatar_url' => $contact->getAvatarURL(110),
'initials' => $contact->getInitials(),
@@ -86,7 +86,7 @@ class DashboardController extends Controller
'id' => $call->id,
'called_at' => \App\Helpers\DateHelper::getShortDate($call->called_at),
'name' => $call->contact->getIncompleteName(),
'contact_id' => $call->contact->id,
'contact_id' => $call->contact->hashID(),
];
$callsCollection->push($data);
}
@@ -110,7 +110,7 @@ class DashboardController extends Controller
'created_at' => \App\Helpers\DateHelper::getShortDate($note->created_at),
'name' => $note->contact->getIncompleteName(),
'contact' => [
'id' => $note->contact->id,
'id' => $note->contact->hashID(),
'has_avatar' => $note->contact->has_avatar,
'avatar_url' => $note->contact->getAvatarURL(110),
'initials' => $note->contact->getInitials(),
@@ -16,6 +16,7 @@ class ContactShort extends Resource
{
return [
'id' => $this->id,
'hash_ID' => $this->hashID(),
'object' => 'contact',
'first_name' => $this->first_name,
'last_name' => $this->last_name,
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use App\Helpers\IdHasher;
use Illuminate\Support\ServiceProvider;
class IdHasherServiceProvider extends ServiceProvider
{
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['idhasher'];
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('idhasher', function ($app) {
return $app->make(IdHasher::class);
});
}
}
+13 -2
View File
@@ -16,6 +16,7 @@ use App\Reminder;
use App\ContactField;
use App\Relationship;
use App\ReminderRule;
use App\Helpers\IdHasher;
use Illuminate\Routing\Router;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
@@ -42,9 +43,11 @@ class RouteServiceProvider extends ServiceProvider
Route::bind('contact', function ($value) {
try {
$value = app('idhasher')->decodeId($value);
return Contact::where('account_id', auth()->user()->account_id)
->where('id', $value)
->firstOrFail();
->where('id', $value)
->firstOrFail();
} catch (ModelNotFoundException $ex) {
redirect('/people/notfound')->send();
}
@@ -58,12 +61,16 @@ class RouteServiceProvider extends ServiceProvider
});
Route::bind('activity', function ($value, $route) {
$value = app('idhasher')->decodeId($value);
return Activity::where('account_id', auth()->user()->account_id)
->where('id', $value)
->firstOrFail();
});
Route::bind('reminder', function ($value, $route) {
$value = app('idhasher')->decodeId($value);
return Reminder::where('account_id', auth()->user()->account_id)
->where('contact_id', $route->parameter('contact')->id)
->where('id', $value)
@@ -85,6 +92,8 @@ class RouteServiceProvider extends ServiceProvider
});
Route::bind('debt', function ($value, $route) {
$value = app('idhasher')->decodeId($value);
return Debt::where('account_id', auth()->user()->account_id)
->where('contact_id', $route->parameter('contact')->id)
->where('id', $value)
@@ -94,6 +103,8 @@ class RouteServiceProvider extends ServiceProvider
Route::bind('relationships', function ($value, $route) {
Contact::findOrFail($route->parameter('contact')->id);
$value = app('idhasher')->decodeId($value);
Relationship::where('account_id', auth()->user()->account_id)
->where('contact_is', $route->parameter('contact')->id)
->where('of_contact', $value)
+2
View File
@@ -4,6 +4,7 @@ namespace App;
use Auth;
use Carbon\Carbon;
use App\Traits\Hasher;
use App\Helpers\DateHelper;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -14,6 +15,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
*/
class Reminder extends Model
{
use Hasher;
/**
* The attributes that aren't mass assignable.
*
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Traits;
use App\Helpers\IdHasher;
trait Hasher
{
public function getRouteKey()
{
return app('idhasher')->encodeId(parent::getRouteKey());
}
public function resolveRouteBinding($value)
{
$value = app('idhasher')->decodeId($value);
return $this->where($this->getRouteKeyName(), $value)->first();
}
public function hashID()
{
return app('idhasher')->encodeId($this->id);
}
}
Regular → Executable
View File
+2
View File
@@ -7,6 +7,7 @@
"require": {
"php": "^7.1.3",
"ext-intl": "*",
"ext-bcmath": "*",
"bacon/bacon-qr-code": "^1.0",
"creativeorange/gravatar": "~1.0",
"doctrine/dbal": "^2.5",
@@ -28,6 +29,7 @@
"pragmarx/recovery": "^0.1",
"predis/predis": "^1.1",
"sabre/vobject": "^4.1",
"vinkla/hashids": "^5.0",
"sentry/sentry-laravel": "^0.8",
"symfony/translation": "^4.0",
"vluzrmos/language-detector": "^1.0"
Generated
+201 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "8fd932dbe676475bd8de110d27a3d944",
"content-hash": "e6c69e3938f031171825726a03d0d9bf",
"packages": [
{
"name": "aws/aws-sdk-php",
@@ -1085,6 +1085,66 @@
"homepage": "https://github.com/firebase/php-jwt",
"time": "2017-06-27T22:17:23+00:00"
},
{
"name": "graham-campbell/manager",
"version": "v4.0.0",
"source": {
"type": "git",
"url": "https://github.com/GrahamCampbell/Laravel-Manager.git",
"reference": "95b654ac39eae15299c6c7400249c204c8ae7bf0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/GrahamCampbell/Laravel-Manager/zipball/95b654ac39eae15299c6c7400249c204c8ae7bf0",
"reference": "95b654ac39eae15299c6c7400249c204c8ae7bf0",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.5.*|5.6.*",
"illuminate/support": "5.5.*|5.6.*",
"php": "^7.1.3"
},
"require-dev": {
"graham-campbell/analyzer": "^2.0",
"graham-campbell/testbench-core": "^3.0",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.5|^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"GrahamCampbell\\Manager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "graham@alt-three.com"
}
],
"description": "Manager Provides Some Manager Functionality For Laravel 5",
"keywords": [
"Graham Campbell",
"GrahamCampbell",
"Laravel Manager",
"Laravel-Manager",
"connector",
"framework",
"interface",
"laravel",
"manager"
],
"time": "2018-02-11T14:57:19+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.3.2",
@@ -1266,6 +1326,72 @@
],
"time": "2017-03-20T17:10:46+00:00"
},
{
"name": "hashids/hashids",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/ivanakimov/hashids.php.git",
"reference": "b6c61142bfe36d43740a5419d11c351dddac0458"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ivanakimov/hashids.php/zipball/b6c61142bfe36d43740a5419d11c351dddac0458",
"reference": "b6c61142bfe36d43740a5419d11c351dddac0458",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
},
"suggest": {
"ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).",
"ext-gmp": "Required to use GNU multiple precision mathematics (*)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Hashids\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ivan Akimov",
"email": "ivan@barreleye.com",
"homepage": "https://twitter.com/IvanAkimov"
},
{
"name": "Vincent Klaiber",
"email": "hello@vinkla.com",
"homepage": "https://vinkla.com"
}
],
"description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers",
"homepage": "http://hashids.org/php",
"keywords": [
"bitly",
"decode",
"encode",
"hash",
"hashid",
"hashids",
"ids",
"obfuscate",
"youtube"
],
"time": "2018-03-12T16:30:09+00:00"
},
{
"name": "intervention/image",
"version": "2.4.1",
@@ -4844,6 +4970,78 @@
"homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
"time": "2017-11-27T11:13:29+00:00"
},
{
"name": "vinkla/hashids",
"version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/vinkla/laravel-hashids.git",
"reference": "038e6bd44ce07225e89fee1cd52c00316bc4fec8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vinkla/laravel-hashids/zipball/038e6bd44ce07225e89fee1cd52c00316bc4fec8",
"reference": "038e6bd44ce07225e89fee1cd52c00316bc4fec8",
"shasum": ""
},
"require": {
"graham-campbell/manager": "^4.0",
"hashids/hashids": "^3.0",
"illuminate/contracts": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3"
},
"require-dev": {
"graham-campbell/analyzer": "^2.0",
"graham-campbell/testbench": "^5.0",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
},
"laravel": {
"providers": [
"Vinkla\\Hashids\\HashidsServiceProvider"
],
"aliases": {
"Hashids": "Vinkla\\Hashids\\Facades\\Hashids"
}
}
},
"autoload": {
"psr-4": {
"Vinkla\\Hashids\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Vincent Klaiber",
"email": "hello@vinkla.com",
"homepage": "https://vinkla.com"
}
],
"description": "A Hashids bridge for Laravel",
"keywords": [
"bitly",
"decrypt",
"encrypt",
"hash",
"hashid",
"hashids",
"ids",
"laravel",
"obfuscate",
"youtube"
],
"time": "2018-03-12T16:38:13+00:00"
},
{
"name": "vlucas/phpdotenv",
"version": "v2.4.0",
@@ -7405,7 +7603,8 @@
"prefer-lowest": false,
"platform": {
"php": "^7.1.3",
"ext-intl": "*"
"ext-intl": "*",
"ext-bcmath": "*"
},
"platform-dev": []
}
+1
View File
@@ -140,6 +140,7 @@ return [
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
Vluzrmos\LanguageDetector\Providers\LanguageDetectorServiceProvider::class,
App\Providers\IdHasherServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
+59
View File
@@ -0,0 +1,59 @@
<?php
/*
* This file is part of Laravel Hashids.
*
* (c) Vincent Klaiber <hello@vinkla.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Default Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the connections below you wish to use as
| your default connection for all work. Of course, you may use many
| connections at once using the manager class.
|
*/
'default' => 'main',
/*
|--------------------------------------------------------------------------
| Hashids Connections
|--------------------------------------------------------------------------
|
| Here are each of the connections setup for your application. Example
| configuration has been included, but you may add as many connections as
| you would like.
|
*/
'connections' => [
'main' => [
'salt' => env('HASH_SALT', 'your-salt-string'),
'length' => env('HASH_LENGTH', 18),
],
'alternative' => [
'salt' => 'your-salt-string',
'length' => 'your-length-integer',
],
],
/*
* Default prefix for ids
*/
'default_prefix' => 'h:',
];
+7
View File
@@ -166,6 +166,13 @@ $factory->define(App\Entry::class, function (Faker\Generator $faker) {
];
});
$factory->define(App\Debt::class, function (Faker\Generator $faker) {
return [
'account_id' => 1,
'contact_id' => 1,
];
});
$factory->define(App\Day::class, function (Faker\Generator $faker) {
return [
'account_id' => 1,
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap a986c15e259f9877fe3d"],"names":["parentJsonpFunction","window","chunkIds","moreModules","executeModules","moduleId","chunkId","result","i","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","call","modules","shift","__webpack_require__","s","installedModules","3","exports","module","l","m","c","d","name","getter","o","defineProperty","configurable","enumerable","get","n","__esModule","object","property","p","oe","err","console","error"],"mappings":"aACA,IAAAA,EAAAC,OAAA,aACAA,OAAA,sBAAAC,EAAAC,EAAAC,GAIA,IADA,IAAAC,EAAAC,EAAAC,EAAAC,EAAA,EAAAC,KACQD,EAAAN,EAAAQ,OAAoBF,IAC5BF,EAAAJ,EAAAM,GACAG,EAAAL,IACAG,EAAAG,KAAAD,EAAAL,GAAA,IAEAK,EAAAL,GAAA,EAEA,IAAAD,KAAAF,EACAU,OAAAC,UAAAC,eAAAC,KAAAb,EAAAE,KACAY,EAAAZ,GAAAF,EAAAE,IAIA,IADAL,KAAAE,EAAAC,EAAAC,GACAK,EAAAC,QACAD,EAAAS,OAAAT,GAEA,GAAAL,EACA,IAAAI,EAAA,EAAYA,EAAAJ,EAAAM,OAA2BF,IACvCD,EAAAY,IAAAC,EAAAhB,EAAAI,IAGA,OAAAD,GAIA,IAAAc,KAGAV,GACAW,EAAA,GAIA,SAAAH,EAAAd,GAGA,GAAAgB,EAAAhB,GACA,OAAAgB,EAAAhB,GAAAkB,QAGA,IAAAC,EAAAH,EAAAhB,IACAG,EAAAH,EACAoB,GAAA,EACAF,YAUA,OANAN,EAAAZ,GAAAW,KAAAQ,EAAAD,QAAAC,IAAAD,QAAAJ,GAGAK,EAAAC,GAAA,EAGAD,EAAAD,QAKAJ,EAAAO,EAAAT,EAGAE,EAAAQ,EAAAN,EAGAF,EAAAS,EAAA,SAAAL,EAAAM,EAAAC,GACAX,EAAAY,EAAAR,EAAAM,IACAhB,OAAAmB,eAAAT,EAAAM,GACAI,cAAA,EACAC,YAAA,EACAC,IAAAL,KAMAX,EAAAiB,EAAA,SAAAZ,GACA,IAAAM,EAAAN,KAAAa,WACA,WAA2B,OAAAb,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAL,EAAAS,EAAAE,EAAA,IAAAA,GACAA,GAIAX,EAAAY,EAAA,SAAAO,EAAAC,GAAsD,OAAA1B,OAAAC,UAAAC,eAAAC,KAAAsB,EAAAC,IAGtDpB,EAAAqB,EAAA,GAGArB,EAAAsB,GAAA,SAAAC,GAA8D,MAApBC,QAAAC,MAAAF,GAAoBA","file":"/js/manifest.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t3: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap a986c15e259f9877fe3d"],"sourceRoot":""}
{"version":3,"sources":["webpack:///webpack/bootstrap 5f6100c24e345e5edb51"],"names":["parentJsonpFunction","window","chunkIds","moreModules","executeModules","moduleId","chunkId","result","i","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","call","modules","shift","__webpack_require__","s","installedModules","3","exports","module","l","m","c","d","name","getter","o","defineProperty","configurable","enumerable","get","n","__esModule","object","property","p","oe","err","console","error"],"mappings":"aACA,IAAAA,EAAAC,OAAA,aACAA,OAAA,sBAAAC,EAAAC,EAAAC,GAIA,IADA,IAAAC,EAAAC,EAAAC,EAAAC,EAAA,EAAAC,KACQD,EAAAN,EAAAQ,OAAoBF,IAC5BF,EAAAJ,EAAAM,GACAG,EAAAL,IACAG,EAAAG,KAAAD,EAAAL,GAAA,IAEAK,EAAAL,GAAA,EAEA,IAAAD,KAAAF,EACAU,OAAAC,UAAAC,eAAAC,KAAAb,EAAAE,KACAY,EAAAZ,GAAAF,EAAAE,IAIA,IADAL,KAAAE,EAAAC,EAAAC,GACAK,EAAAC,QACAD,EAAAS,OAAAT,GAEA,GAAAL,EACA,IAAAI,EAAA,EAAYA,EAAAJ,EAAAM,OAA2BF,IACvCD,EAAAY,IAAAC,EAAAhB,EAAAI,IAGA,OAAAD,GAIA,IAAAc,KAGAV,GACAW,EAAA,GAIA,SAAAH,EAAAd,GAGA,GAAAgB,EAAAhB,GACA,OAAAgB,EAAAhB,GAAAkB,QAGA,IAAAC,EAAAH,EAAAhB,IACAG,EAAAH,EACAoB,GAAA,EACAF,YAUA,OANAN,EAAAZ,GAAAW,KAAAQ,EAAAD,QAAAC,IAAAD,QAAAJ,GAGAK,EAAAC,GAAA,EAGAD,EAAAD,QAKAJ,EAAAO,EAAAT,EAGAE,EAAAQ,EAAAN,EAGAF,EAAAS,EAAA,SAAAL,EAAAM,EAAAC,GACAX,EAAAY,EAAAR,EAAAM,IACAhB,OAAAmB,eAAAT,EAAAM,GACAI,cAAA,EACAC,YAAA,EACAC,IAAAL,KAMAX,EAAAiB,EAAA,SAAAZ,GACA,IAAAM,EAAAN,KAAAa,WACA,WAA2B,OAAAb,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAL,EAAAS,EAAAE,EAAA,IAAAA,GACAA,GAIAX,EAAAY,EAAA,SAAAO,EAAAC,GAAsD,OAAA1B,OAAAC,UAAAC,eAAAC,KAAAsB,EAAAC,IAGtDpB,EAAAqB,EAAA,GAGArB,EAAAsB,GAAA,SAAAC,GAA8D,MAApBC,QAAAC,MAAAF,GAAoBA","file":"/js/manifest.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t3: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 5f6100c24e345e5edb51"],"sourceRoot":""}
+3 -3
View File
@@ -1,8 +1,8 @@
{
"/js/app.js": "/js/app.js?id=0c241e313c1b5aa5dd76",
"/js/app.js": "/js/app.js?id=d3f36f7ed0808f5496d2",
"/css/app.css": "/css/app.css?id=ce61f35432352117b85f",
"/css/stripe.css": "/css/stripe.css?id=956554a2e96db30fafa3",
"/js/app.js.map": "/js/app.js.map?id=87fd25787c800e2519b2",
"/js/app.js.map": "/js/app.js.map?id=90fee6738c2866302e7b",
"/css/app.css.map": "/css/app.css.map?id=68f4f4b1e73b2fab974b",
"/css/stripe.css.map": "/css/stripe.css.map?id=80d7af9d49b0922d35e6",
"/js/vendor.js": "/js/vendor.js?id=a49a2fa050af3f4fa573",
@@ -10,5 +10,5 @@
"/js/stripe.js": "/js/stripe.js?id=53bdff9014c2f8618542",
"/js/stripe.js.map": "/js/stripe.js.map?id=f0f557c67621a3a7e628",
"/js/manifest.js": "/js/manifest.js?id=762d9e2e684fedba1433",
"/js/manifest.js.map": "/js/manifest.js.map?id=18fd950354f3892963ff"
"/js/manifest.js.map": "/js/manifest.js.map?id=e122f066058c5fa48c03"
}
@@ -131,7 +131,7 @@
},
redirect(attendee) {
window.location.href = "/people/" + attendee.id
window.location.href = "/people/" + attendee.hash_ID
}
}
}
@@ -199,7 +199,7 @@
this.prepareComponent();
},
props: ['contactId'],
props: ['hash'],
methods: {
/**
@@ -211,14 +211,14 @@
},
getAddresses() {
axios.get('/people/' + this.contactId + '/addresses')
axios.get('/people/' + this.hash + '/addresses')
.then(response => {
this.contactAddresses = response.data;
});
},
getCountries() {
axios.get('/people/' + this.contactId + '/countries')
axios.get('/people/' + this.hash + '/countries')
.then(response => {
this.countries = response.data;
});
@@ -251,7 +251,7 @@
store() {
this.persistClient(
'post', '/people/' + this.contactId + '/addresses',
'post', '/people/' + this.hash + '/addresses',
this.createForm
);
@@ -260,7 +260,7 @@
update(contactAddress) {
this.persistClient(
'put', '/people/' + this.contactId + '/addresses/' + contactAddress.id,
'put', '/people/' + this.hash + '/addresses/' + contactAddress.id,
this.updateForm
);
},
@@ -269,7 +269,7 @@
this.updateForm.id = contactAddress.id;
this.persistClient(
'delete', '/people/' + this.contactId + '/addresses/' + contactAddress.id,
'delete', '/people/' + this.hash + '/addresses/' + contactAddress.id,
this.updateForm
);
@@ -126,7 +126,7 @@
this.prepareComponent();
},
props: ['contactId'],
props: ['hash', 'contactId'],
methods: {
/**
@@ -138,14 +138,14 @@
},
getContactInformationData() {
axios.get('/people/' + this.contactId + '/contactfield')
axios.get('/people/' + this.hash + '/contactfield')
.then(response => {
this.contactInformationData = response.data;
});
},
getContactFieldTypes() {
axios.get('/people/' + this.contactId + '/contactfieldtypes')
axios.get('/people/' + this.hash + '/contactfieldtypes')
.then(response => {
this.contactFieldTypes = response.data;
});
@@ -153,7 +153,7 @@
store() {
this.persistClient(
'post', '/people/' + this.contactId + '/contactfield',
'post', '/people/' + this.hash + '/contactfield',
this.createForm
);
@@ -175,7 +175,7 @@
update(contactField) {
this.persistClient(
'put', '/people/' + this.contactId + '/contactfield/' + contactField.id,
'put', '/people/' + this.hash + '/contactfield/' + contactField.id,
this.updateForm
);
},
@@ -184,7 +184,7 @@
this.updateForm.id = contactField.id;
this.persistClient(
'delete', '/people/' + this.contactId + '/contactfield/' + contactField.id,
'delete', '/people/' + this.hash + '/contactfield/' + contactField.id,
this.updateForm
);
@@ -9,8 +9,13 @@
<div>
<img src="/img/people/gifts.svg" class="icon-section icon-tasks">
<h3>
Gifts
{{ $t('people.gifts_title') }}
<a :href="'/people/' + contactId + '/gifts/add'" class="btn fr f6 pt2">{{ $t('people.gifts_add_gift') }}</a>
<a :href="'/people/' + hash + '/gifts/add'" class="btn fr f6 pt2">{{ $t('people.gifts_add_gift') }}</a>
</h3>
</div>
@@ -50,7 +55,7 @@
</span>
<a v-if="gift.comment" @click="toggleComment(gift)" class="ml1 mr1 pointer">{{ $t('people.gifts_view_comment') }}</a>
<a @click="toggle(gift)" class="pointer mr1">{{ $t('people.gifts_mark_offered') }}</a>
<a :href="'/people/' + contactId + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a :href="'/people/' + hash + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a @click="showDeleteModal(gift)" class="mr1 pointer">{{ $t('app.delete') }}</a>
<div v-if="gift.show_comment" class="mb1 mt1">
{{ gift.comment }}
@@ -81,7 +86,7 @@
</span>
<a v-if="gift.comment" @click="toggleComment(gift)" class="ml1 mr1 pointer">{{ $t('people.gifts_view_comment') }}</a>
<a @click="toggle(gift)" class="pointer mr1">{{ $t('people.gifts_offered_as_an_idea') }}</a>
<a :href="'/people/' + contactId + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a :href="'/people/' + hash + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a @click="showDeleteModal(gift)" class="mr1 pointer">{{ $t('app.delete') }}</a>
<div v-if="gift.show_comment" class="mb1 mt1">
{{ gift.comment }}
@@ -109,7 +114,7 @@
<span class="ml1 mr1 black-50"></span>
</span>
<a v-if="gift.comment" @click="toggleComment(gift)" class="ml1 mr1 pointer">{{ $t('people.gifts_view_comment') }}</a>
<a :href="'/people/' + contactId + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a :href="'/people/' + hash + '/gifts/' + gift.id + '/edit'">{{ $t('app.edit') }}</a>
<a @click="showDeleteModal(gift)" class="mr1 pointer">{{ $t('app.delete') }}</a>
<div v-if="gift.show_comment" class="mb1 mt1">
{{ gift.comment }}
@@ -170,7 +175,7 @@
this.prepareComponent();
},
props: ['contactId', 'giftsActiveTab'],
props: ['hash', 'giftsActiveTab'],
computed: {
ideas: function () {
@@ -210,14 +215,14 @@
},
getGifts() {
axios.get('/people/' + this.contactId + '/gifts')
axios.get('/people/' + this.hash + '/gifts')
.then(response => {
this.gifts = response.data;
});
},
toggle(gift) {
axios.post('/people/' + this.contactId + '/gifts/' + gift.id + '/toggle')
axios.post('/people/' + this.hash + '/gifts/' + gift.id + '/toggle')
.then(response => {
Vue.set(gift, 'is_an_idea', response.data.is_an_idea);
Vue.set(gift, 'has_been_offered', response.data.has_been_offered);
@@ -230,7 +235,7 @@
},
trash(gift) {
axios.delete('/people/' + this.contactId + '/gifts/' + gift.id)
axios.delete('/people/' + this.hash + '/gifts/' + gift.id)
.then(response => {
this.gifts.splice(this.gifts.indexOf(gift), 1);
this.$refs.modal.close();
@@ -119,7 +119,7 @@
this.prepareComponent();
},
props: ['contactId'],
props: ['hash'],
computed: {
compiledMarkdown: function (text) {
@@ -159,14 +159,14 @@
},
getNotes() {
axios.get('/people/' + this.contactId + '/notes')
axios.get('/people/' + this.hash + '/notes')
.then(response => {
this.notes = response.data;
});
},
store() {
axios.post('/people/' + this.contactId + '/notes', this.newNote)
axios.post('/people/' + this.hash + '/notes', this.newNote)
.then(response => {
this.newNote.body = '';
this.getNotes();
@@ -182,14 +182,14 @@
},
toggleFavorite(note) {
axios.post('/people/' + this.contactId + '/notes/' + note.id + '/toggle')
axios.post('/people/' + this.hash + '/notes/' + note.id + '/toggle')
.then(response => {
this.getNotes();
});
},
update(note) {
axios.put('/people/' + this.contactId + '/notes/' + note.id, note)
axios.put('/people/' + this.hash + '/notes/' + note.id, note)
.then(response => {
Vue.set(note, 'edit', note.edit);
this.getNotes();
@@ -210,7 +210,7 @@
},
trash(note) {
axios.delete('/people/' + this.contactId + '/notes/' + note.id)
axios.delete('/people/' + this.hash + '/notes/' + note.id)
.then(response => {
this.getNotes();
@@ -140,7 +140,7 @@
this.prepareComponent();
},
props: ['contactId'],
props: ['hash'],
methods: {
/**
@@ -159,14 +159,14 @@
},
getPets() {
axios.get('/people/' + this.contactId + '/pets')
axios.get('/people/' + this.hash + '/pets')
.then(response => {
this.pets = response.data;
});
},
store() {
axios.post('/people/' + this.contactId + '/pet', this.createForm)
axios.post('/people/' + this.hash + '/pet', this.createForm)
.then(response => {
this.addMode = false;
this.pets.push(response.data);
@@ -195,7 +195,7 @@
},
update(pet) {
axios.put('/people/' + this.contactId + '/pet/' + pet.id, this.updateForm)
axios.put('/people/' + this.hash + '/pet/' + pet.id, this.updateForm)
.then(response => {
Vue.set(pet, 'edit', !pet.edit);
Vue.set(pet, 'name', response.data.name);
@@ -212,7 +212,7 @@
},
trash(pet) {
axios.delete('/people/' + this.contactId + '/pet/' + pet.id)
axios.delete('/people/' + this.hash + '/pet/' + pet.id)
.then(response => {
this.getPets();
@@ -142,7 +142,7 @@
this.prepareComponent();
},
props: ['contactId'],
props: ['hash'],
methods: {
/**
@@ -182,7 +182,7 @@
},
getTasks() {
axios.get('/people/' + this.contactId + '/tasks')
axios.get('/people/' + this.hash + '/tasks')
.then(response => {
this.tasks = response.data;
});
@@ -190,7 +190,7 @@
store() {
this.persistClient(
'post', '/people/' + this.contactId + '/tasks',
'post', '/people/' + this.hash + '/tasks',
this.createForm
);
@@ -198,7 +198,7 @@
},
toggleComplete(task) {
axios.post('/people/' + this.contactId + '/tasks/' + task.id + '/toggle')
axios.post('/people/' + this.hash + '/tasks/' + task.id + '/toggle')
.then(response => {
this.getTasks();
});
@@ -211,7 +211,7 @@
this.updateForm.completed = task.completed;
this.persistClient(
'put', '/people/' + this.contactId + '/tasks/' + task.id,
'put', '/people/' + this.hash + '/tasks/' + task.id,
this.updateForm
);
@@ -222,7 +222,7 @@
this.updateForm.id = task.id;
this.persistClient(
'delete', '/people/' + this.contactId + '/tasks/' + task.id,
'delete', '/people/' + this.hash + '/tasks/' + task.id,
this.updateForm
);
+1 -1
View File
@@ -33,7 +33,7 @@ function Search(form, input, resultsContainer, showResults) {
data.forEach(function (contact) {
let person = {};
person.id = contact.id;
person.url = `/people/${contact.id}`;
person.url = `/people/${contact.hash}`;
const middleName = contact.middle_name || '';
const lastName = contact.last_name || '';
@@ -8,11 +8,11 @@
@if ($reminder->contact->is_partial)
<a href="/people/{{ $reminder->contact->getRelatedRealContact()->id }}">{{ $reminder->contact->getRelatedRealContact()->getIncompleteName() }}</a>
<a href="/people/{{ $reminder->contact->getRelatedRealContact()->hashID() }}">{{ $reminder->contact->getRelatedRealContact()->getIncompleteName() }}</a>
@else
<a href="/people/{{ $reminder->contact->id }}">{{ $reminder->contact->getIncompleteName() }}</a>
<a href="/people/{{ $reminder->contact->hashID() }}">{{ $reminder->contact->getIncompleteName() }}</a>
@endif
</span>
@@ -17,4 +17,4 @@ COMMENT:
-------
{{ trans('mail.footer_contact_info') }}
{{ config('app.url') }}/people/{{ $contact->id }}
{{ config('app.url') }}/people/{{ $contact->hashID() }}
@@ -17,4 +17,4 @@ COMMENT:
-------
{{ trans('mail.footer_contact_info') }}
{{ config('app.url') }}/people/{{ $contact->id }}
{{ config('app.url') }}/people/{{ $contact->hashID() }}
+2 -2
View File
@@ -69,7 +69,7 @@
<li><a href="#" id="showTagForm">{{ trans('people.tag_edit') }}</a></li>
</ul>
<form method="POST" action="/people/{{ $contact->id }}/tags/update" id="tagsForm">
<form method="POST" action="/people/{{ $contact->hashID() }}/tags/update" id="tagsForm">
{{ csrf_field() }}
<input name="tags" id="tags" value="{{ $contact->getTagsAsString() }}" />
<div class="tagsFormActions">
@@ -80,7 +80,7 @@
<ul class="horizontal quick-actions">
<li>
<a href="/people/{{ $contact->id }}/edit" class="btn edit-information">{{ trans('people.edit_contact_information') }}</a>
<a href="/people/{{ $contact->hashID() }}/edit" class="btn edit-information">{{ trans('people.edit_contact_information') }}</a>
</li>
</ul>
</div>
@@ -7,7 +7,7 @@
</p>
<p class="sidebar-box-paragraph">
<a href="/people/{{ $contact->id }}/food">{{ trans('app.add') }}</a>
<a href="/people/{{ $contact->hashID() }}/food">{{ trans('app.add') }}</a>
</p>
@else
@@ -19,7 +19,7 @@
{{-- Information about the significant other --}}
<p class="sidebar-box-paragraph">
{{ $contact->food_preferencies }}
<a href="/people/{{ $contact->id }}/food" class="action-link">{{ trans('app.edit') }}</a>
<a href="/people/{{ $contact->hashID() }}/food" class="action-link">{{ trans('app.edit') }}</a>
</p>
@endif
@@ -1,11 +1,11 @@
{{-- Pets --}}
<pet v-bind:contact-id="{!! $contact->id !!}"></pet>
<pet hash={!! $contact->hashID() !!}></pet>
{{-- Contact information --}}
<contact-information v-bind:contact-id="{!! $contact->id !!}"></contact-information>
<contact-information hash={!! $contact->hashID() !!} ></contact-information>
{{-- Address --}}
<contact-address v-bind:contact-id="{!! $contact->id !!}"></contact-address>
<contact-address hash={!! $contact->hashID() !!}></contact-address>
{{-- Introductions --}}
@include('people.dashboard.introductions.index')
@@ -38,7 +38,7 @@
</ul>
<p class="sidebar-box-paragraph">
<a href="/people/{{ $contact->id }}/work/edit">{{ trans('people.work_add_cta') }}</a>
<a href="/people/{{ $contact->hashID() }}/work/edit">{{ trans('people.work_add_cta') }}</a>
</p>
</div>
+3 -3
View File
@@ -4,7 +4,7 @@
{{ trans('people.debt_title') }}
<span class="fr">
<a href="/people/{{ $contact->id }}/debt/add" class="btn">{{ trans('people.debt_add_cta') }}</a>
<a href="/people/{{ $contact->hashID() }}/debt/add" class="btn">{{ trans('people.debt_add_cta') }}</a>
</span>
</h3>
</div>
@@ -14,7 +14,7 @@
<div class="col-xs-12">
<div class="section-blank">
<h3>{{ trans('people.debts_blank_title', ['name' => $contact->first_name]) }}</h3>
<a href="/people/{{ $contact->id }}/debt/add">{{ trans('people.debt_add_cta') }}</a>
<a href="/people/{{ $contact->hashID() }}/debt/add">{{ trans('people.debt_add_cta') }}</a>
</div>
</div>
@@ -46,7 +46,7 @@
@endif
</div>
<div class="table-cell list-actions">
<a href="{{ route('people.debt.edit', ['people' => $contact->id, 'debtId' => $debt->id]) }}">
<a href="{{ route('people.debt.edit', [$contact, $debt]) }}">
<i class="fa fa-pencil" aria-hidden="true"></i>
</a>
<a href="#" onclick="if (confirm('{{ trans('people.debt_delete_confirmation') }}')) { $(this).closest('.table-row').find('.entry-delete-form').submit(); } return false;">
+2 -2
View File
@@ -5,7 +5,7 @@
{{-- Breadcrumb --}}
<div class="mt4 mw7 center mb3">
<p><a href="{{ url('/people/'.$contact->id) }}">< {{ $contact->getCompleteName() }}</a></p>
<p><a href="{{ url('/people/'.$contact->hashID()) }}">< {{ $contact->getCompleteName() }}</a></p>
<h3 class="f3 fw5">{{ trans('people.information_edit_title', ['name' => $contact->first_name]) }}</h3>
@if (! auth()->user()->account->hasLimitations())
@@ -142,7 +142,7 @@
<div class="ph4-ns ph3 pv3 bb b--gray-monica">
<div class="flex-ns justify-between">
<div class="">
<a href="{{ url('/people/'.$contact->id) }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
<a href="{{ url('/people/'.$contact->hashID()) }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
</div>
<div class="">
<button class="btn btn-primary w-auto-ns w-100 mb2 pb0-ns" name="save" type="submit">{{ trans('app.save') }}</button>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="col-xs-12 section-title">
<contact-gift v-bind:contact-id="{!! $contact->id !!}" v-bind:gifts-active-tab="'{!! auth()->user()->gifts_active_tab !!}'"></contact-gift>
<contact-gift hash={!! $contact->hashID() !!} v-bind:gifts-active-tab="'{!! auth()->user()->gifts_active_tab !!}'"></contact-gift>
</div>
@@ -14,8 +14,7 @@
<ul class="contacts">
<ul class="contacts-list">
@foreach ($activity->contacts as $contact)
<li class="pretty-tag"><a href="/people/{{ $contact->id }}">{{ $contact->first_name }} {{ $contact->last_name }}</a></li>
<input type="hidden" name="contacts[]" value="{{ $contact->id }}" />
<li class="pretty-tag"><a href="/people/{{ $contact->hashID() }}">{{ $contact->first_name }} {{ $contact->last_name }}</a></li>
@endforeach
</ul>
</ul>
@@ -9,7 +9,7 @@
</button>
</div>
<div class="modal-body">
<form method="POST" action="/people/{{ $contact->id }}/call/store">
<form method="POST" action="/people/{{ $contact->hashID() }}/call/store">
{{ csrf_field() }}
<div class="form-group">
+3 -3
View File
@@ -3,7 +3,7 @@
@section('title', $contact->getCompleteName(auth()->user()->name_order) )
@section('content')
<div class="people-show" data-contact-id="{{ $contact->id }}">
<div class="people-show" >
{{ csrf_field() }}
{{-- Breadcrumb --}}
@@ -43,7 +43,7 @@
@include('people.dashboard.index')
<p><a href="{{ url('/people/'.$contact->id.'/vcard') }}">{{ trans('people.people_export') }}</a></p>
<p><a href="{{ url('/people/'.$contact->hashID().'/vcard') }}">{{ trans('people.people_export') }}</a></p>
<p>
{{ trans('people.people_delete_message') }}
<a href="#" onclick="if (confirm('{{ trans('people.people_delete_confirmation') }}')) { $('#contact-delete-form').submit(); } return false;">{{ trans('people.people_delete_click_here') }}</a>.
@@ -57,7 +57,7 @@
<div class="col-xs-12 col-sm-9">
<div class="row section notes">
<div class="col-xs-12 section-title">
<contact-note v-bind:contact-id="{!! $contact->id !!}"></contact-note>
<contact-note hash={!! $contact->hashID() !!}></contact-note>
</div>
</div>
@@ -18,7 +18,7 @@
{{-- ACTIONS: EDIT/DELETE --}}
@if ($relationship->ofContact->is_partial)
<a href="{{ route('people.relationships.edit', [$contact, $relationship->ofContact]) }}" class="action-link {{ $contact->id }}-edit-relationship">
<a href="{{ route('people.relationships.edit', [$contact, $relationship->ofContact]) }}" class="action-link {{ $contact->hashID() }}-edit-relationship">
{{ trans('app.edit') }}
</a>
<a href="#" onclick="if (confirm('{{ trans('people.relationship_delete_confirmation') }}')) { $(this).closest('.sidebar-box-paragraph').find('.entry-delete-form').submit(); } return false;" class="action-link">
@@ -30,7 +30,7 @@
</a>
@endif
<form method="POST" action="/people/{{ $contact->id }}/relationships/{{ $relationship->ofContact->id }}" class="entry-delete-form hidden">
<form method="POST" action="/people/{{ $contact->hashID() }}/relationships/{{ $relationship->ofContact->hashID() }}" class="entry-delete-form hidden">
{{ method_field('DELETE') }}
{{ csrf_field() }}
</form>
@@ -6,7 +6,7 @@
{{-- Breadcrumb --}}
<div class="mt4 mw7 center mb3">
<p><a href="{{ url('/people/'.$contact->id) }}">< {{ $contact->getCompleteName() }}</a></p>
<p><a href="{{ url('/people/'.$contact->hashID()) }}">< {{ $contact->getCompleteName() }}</a></p>
<div class="mt4 mw7 center mb3">
<h3 class="f3 fw5">{{ trans('people.relationship_form_edit') }}</h3>
</div>
@@ -22,7 +22,7 @@
@include('partials.errors')
<form action="/people/{{ $contact->id }}/relationships/{{ $partner->id }}" method="POST">
<form action="/people/{{ $contact->hashID() }}/relationships/{{ $partner->hashID() }}" method="POST">
{{ csrf_field() }}
<input type="hidden" name="type" value="{{ $type }}">
@@ -130,7 +130,7 @@
<div class="ph4-ns ph3 pv3 bb b--gray-monica">
<div class="flex-ns justify-between">
<div class="">
<a href="/people/{{ $contact->id }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
<a href="/people/{{ $contact->hashID() }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
</div>
<div class="">
<button class="btn btn-primary w-auto-ns w-100 mb2 pb0-ns" v-if="global_relationship_form_new_contact" name="save" type="submit">{{ trans('app.save') }}</button>
@@ -7,8 +7,9 @@
@include('people.relationship._relationship', ['relationships' => $loveRelationships])
<p class="mb0">
<a href="/people/{{ $contact->id }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('partner')->id }}">{{ trans('app.add') }}</a>
<a href="/people/{{ $contact->hashID() }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('partner')->id }}">{{ trans('app.add') }}</a>
</p>
</div>
@@ -19,10 +20,11 @@
</div>
</div>
@include('people.relationship._relationship', ['relationships' => $familyRelationships])
<p class="mb0">
<a href="/people/{{ $contact->id }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('child')->id }}">{{ trans('app.add') }}</a>
<a href="/people/{{ $contact->hashID() }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('child')->id }}">{{ trans('app.add') }}</a>
</p>
</div>
@@ -38,6 +40,6 @@
@include('people.relationship._relationship', ['relationships' => $workRelationships])
<p class="mb0">
<a href="/people/{{ $contact->id }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('friend')->id }}">{{ trans('app.add') }}</a>
<a href="/people/{{ $contact->hashID() }}/relationships/new?type={{ $contact->account->getRelationshipTypeByType('friend')->id }}">{{ trans('app.add') }}</a>
</p>
</div>
@@ -6,7 +6,7 @@
{{-- Breadcrumb --}}
<div class="mt4 mw7 center mb3">
<p><a href="{{ url('/people/'.$contact->id) }}">< {{ $contact->getCompleteName() }}</a></p>
<p><a href="{{ url('/people/'.$contact->hashID()) }}">< {{ $contact->getCompleteName() }}</a></p>
<div class="mt4 mw7 center mb3">
<h3 class="f3 fw5">{{ trans('people.relationship_form_add') }}</h3>
</div>
@@ -22,7 +22,7 @@
@include('partials.errors')
<form action="/people/{{ $contact->id }}/relationships/store" method="POST">
<form action="/people/{{ $contact->hashID() }}/relationships/store" method="POST">
{{ csrf_field() }}
{{-- New contact / link existing --}}
@@ -158,7 +158,7 @@
<div class="ph4-ns ph3 pv3 bb b--gray-monica">
<div class="flex-ns justify-between">
<div class="">
<a href="/people/{{ $contact->id }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
<a href="/people/{{ $contact->hashID() }}" class="btn btn-secondary w-auto-ns w-100 mb2 pb0-ns">{{ trans('app.cancel') }}</a>
</div>
<div class="">
@if ($existingContacts->count() == 0)
@@ -4,7 +4,7 @@
{{ trans('people.section_personal_reminders') }}
<span class="fr">
<a href="/people/{{ $contact->id }}/reminders/add" class="btn">{{ trans('people.reminders_cta') }}</a>
<a href="/people/{{ $contact->hashID() }}/reminders/add" class="btn">{{ trans('people.reminders_cta') }}</a>
</span>
</h3>
</div>
@@ -15,7 +15,7 @@
<div class="col-xs-12">
<div class="section-blank">
<h3>{{ trans('people.reminders_blank_title', ['name' => $contact->first_name]) }}</h3>
<a href="/people/{{ $contact->id }}/reminders/add">{{ trans('people.reminders_blank_add_activity') }}</a>
<a href="/people/{{ $contact->hashID() }}/reminders/add">{{ trans('people.reminders_blank_add_activity') }}</a>
</div>
</div>
@@ -67,7 +67,7 @@
@endif
</div>
<form method="POST" action="/people/{{ $contact->id }}/reminders/{{ $reminder->id }}" class="entry-delete-form hidden">
<form method="POST" action="/people/{{ $contact->hashID() }}/reminders/{{ $reminder->id }}" class="entry-delete-form hidden">
{{ method_field('DELETE') }}
{{ csrf_field() }}
</form>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="col-xs-12 section-title">
<contact-task v-bind:contact-id="{!! $contact->id !!}"></contact-task>
<contact-task hash={!! $contact->hashID() !!}></contact-task>
</div>
+1 -1
View File
@@ -50,7 +50,7 @@ apt-get install -y curl php7.1-cli >/dev/null
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
echo -e "\n\033[4;32mInstalling packages for Monica\033[0;40m"
apt-get install -y php7.1-intl php7.1-simplexml php7.1-gd php7.1-mbstring php7.1-curl php7.1-zip php7.1-mysql >/dev/null
apt-get install -y php7.1-intl php7.1-simplexml php7.1-gd php7.1-mbstring php7.1-curl php7.1-zip php7.1-mysql php7.1-bcmath >/dev/null
echo -e "\n\033[4;32mGetting database ready\033[0;40m"
mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "CREATE DATABASE $MYSQL_DB_DATABASE;
+1 -1
View File
@@ -68,7 +68,7 @@ class ActivityTest extends FeatureTestCase
];
$response = $this->post('/activities/store/'.$contact->id, $params + ['contacts' => [$contact->id]]);
$response->assertRedirect('/people/'.$contact->id);
$response->assertRedirect('/people/'.$contact->hashID());
// Assert the activity has been added
$params['account_id'] = $user->account_id;
+2 -2
View File
@@ -70,7 +70,7 @@ class CallTest extends FeatureTestCase
];
$response = $this->post('/people/'.$contact->id.'/call/store', $params);
$response->assertRedirect('/people/'.$contact->id);
$response->assertRedirect('/people/'.$contact->hashID());
// Assert the call has been added for the correct user.
$params['account_id'] = $user->account_id;
@@ -102,7 +102,7 @@ class CallTest extends FeatureTestCase
];
$response = $this->post('/people/'.$contact->id.'/call/store', $params);
$response->assertRedirect('/people/'.$contact->id);
$response->assertRedirect('/people/'.$contact->hashID());
// Assert the call has been added for the correct user.
$params['account_id'] = $user->account_id;
+98
View File
@@ -0,0 +1,98 @@
<?php
namespace Tests\Unit;
use App\Debt;
use App\Contact;
use App\Activity;
use App\Reminder;
use Tests\TestCase;
use App\Helpers\IdHasher;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ID_hasherTest extends TestCase
{
use DatabaseTransactions;
public function testPrependH()
{
$ID_hasher = new IdHasher();
$test_id = rand();
$test_hash = $ID_hasher->encodeId($test_id);
$test_value = ('h' == substr($test_hash, 0, 1));
$this->assertTrue($test_value);
}
public function testGetIDback()
{
$ID_hasher = new IdHasher();
$test_id = rand();
$test_hash = $ID_hasher->encodeId($test_id);
$test_value = ($test_id == $ID_hasher->decodeId($test_hash));
$this->assertTrue($test_value);
$test_value = ($test_id == $ID_hasher->decodeId($test_id));
$this->assertTrue($test_value);
}
public function testHashIDContact()
{
$ID_hasher = new IdHasher();
$contact = factory(Contact::class)->create();
$test_hash = $contact->hashID();
$test_value = ($contact->id == $ID_hasher->decodeId($test_hash));
$this->assertTrue($test_value);
}
public function testHashIDActivity()
{
$ID_hasher = new IdHasher();
$activity = factory(Activity::class)->create();
$test_hash = $activity->hashID();
$test_value = ($activity->id == $ID_hasher->decodeId($test_hash));
$this->assertTrue($test_value);
}
public function testHashIDDebt()
{
$ID_hasher = new IdHasher();
$debt = factory(Debt::class)->create();
$test_hash = $debt->hashID();
$test_value = ($debt->id == $ID_hasher->decodeId($test_hash));
$this->assertTrue($test_value);
}
public function testHashIDReminder()
{
$ID_hasher = new IdHasher();
$reminder = factory(Reminder::class)->create();
$test_hash = $reminder->hashID();
$test_value = ($reminder->id == $ID_hasher->decodeId($test_hash));
$this->assertTrue($test_value);
}
}