Improved test code coverage, including necessary refactor
Squashed commit of the following: commit 18996bc4916e945e130ad4abb17149ea2d0afa93 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Dec 7 14:46:41 2017 +0000 Fixing styleci issue commit e5bfedfdede637d3090603b55946cc34aec8b52d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Dec 7 14:45:47 2017 +0000 The Micorpub controller istelf is basically refactored now commit 9eacc968c8bf9b0f5e746c38f04423c51f678d50 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Dec 7 14:16:23 2017 +0000 Add more tests, easily into 90% plus test coverage now commit 2dcbf94298841884083f752f17de46ef7809a369 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Dec 7 10:57:42 2017 +0000 Fix some styleci issues commit 6a989f61af412d59751281bc09ba0778597f09ec Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Dec 7 10:56:13 2017 +0000 First real attempt at refactoring micropub controller commit c10da3d630ca8e06b120122041bb6c64c1084325 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Dec 5 16:51:20 2017 +0000 Fix a styleci issue commit d7ee556fdebdd2160620e65d4bf3c67134f01187 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Dec 5 16:47:52 2017 +0000 Improve the code for the media endpoint and add tests commit bc81bbaff3fad8afcc2135d76f213bba8ba54534 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Dec 5 16:47:07 2017 +0000 Modify process image to process media, this allows for improvment within the micropub controller commit d13035cb2cbeff41d15ff017beb9a5b6bb41daee Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 15:14:18 2017 +0000 Better name the current tests commit 0a2ef16f74f3e322a945a8d6b239be3f97e8c5b8 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 14:08:13 2017 +0000 Reach 100% code coverage for webmentions commit 60f8b196a0fb4e6570b74d7577a9ff5f6c218613 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 13:35:03 2017 +0000 Fix a styleci issue commit e96be1869da909b8b080a38e4e33f94656b5b786 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 13:32:54 2017 +0000 Add tests for Notes Admin code commit 213319798bf5b3118034ab18a7c9eca5cf18296f Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 12:44:02 2017 +0000 Fix a styleci issue commit a614332c7664f66edcb78ef23db392a417c0deb0 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 12:43:02 2017 +0000 Fix a phpcs issue commit 6a2e445dbf87fb8b48a24b34ca0fc3518b4376b6 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 12:20:19 2017 +0000 Add some tests fopr editing places in the admin cp commit 7044f2555228ffd7df2823c0c19a4380ca886b5d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Dec 4 11:35:59 2017 +0000 Add tests for contacts admin code commit 280c4498dbe2cf2879a08ee45a90a0c9ff2f296a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Dec 2 13:45:27 2017 +0000 Improve admin related tests commit ee93a108d11053b1f2fe38f30f3219b3e96267fc Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Dec 2 00:01:42 2017 +0000 Measure coverage with coveralls commit 47c4f5088b1b12e4d183a72b9792e723bda64f77 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:57:32 2017 +0000 Remove un-used PhotosController commit 5737621dbc0ff7009896b483e1d004cdf2eb1523 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:47:08 2017 +0000 Remove the curl test that was used for debugging purposes commit b4d312b056df884eef7e4b0392b5dd1a3ae978bd Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:39:47 2017 +0000 We don’t want ports in the longurl/shorturl env vars commit 915370845448ef4e1be1ff5e7f4ef084c4200953 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:30:17 2017 +0000 Use the right port commit f9a3eac51063899fd003a8fa572dcf972d2f3a5c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:18:57 2017 +0000 I can’t get nginx listening on custom domains commit 3742a04cda5b5ae56ad839bf0ed74ddd9874e74c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:10:51 2017 +0000 Try naked domains, i.e. without .localhost commit d46040f86f32f0a70dae3bd1cf7c27465ee83a77 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 23:02:51 2017 +0000 Add some default values back for pid and error_log commit f15eb73b995f215e3b56243bbba49f23393beb5e Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:56:38 2017 +0000 Let pid be the default value commit 91048b96302b5f13c1eba4ae9ab226ff00859ea6 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:51:22 2017 +0000 Don’t try and run php-fpm and nginx on the same port commit 4203f7de976df9d0e832c09b18f15fff05837af7 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:36:26 2017 +0000 Can only have one default_server commit 6d117929d09707add7d687883d4cb6eba5881e96 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:10:35 2017 +0000 Try and get a long url and short url both working commit 995c7721e3dd96b01307cf75ae0f839fad96aaf9 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:01:14 2017 +0000 Test the remaining shorturl redirects commit d4c8a1a9c41c4e807d986b54c397b88a54292713 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 22:00:54 2017 +0000 Get rid of some of my legacy redirects commit 96d8c5b4cf576d66864a9e241cbef89b7bbe4597 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 21:46:42 2017 +0000 Try and fix which url is being replied to commit 692a7d0a2dcb3050f9c6da4afce2bb6c8ee72583 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 21:22:15 2017 +0000 Add tests and improve code for the search feature commit 442c26ff485a4d20710e1c38ab78bb1df212edda Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 20:04:00 2017 +0000 Add tests for saving css preference in the session commit e2180f0c40e4e8de293d2dd174816095affb0e3f Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 19:35:32 2017 +0000 Some styleci fixes commit a90bbe79c092ee4548f4fbad1399b99fddcb432c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 19:33:40 2017 +0000 Don’t consider un-used laravel middleware when calculating code coverage commit 15edeb0d0179d5a37648c454d316c99250ba9bea Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 19:27:42 2017 +0000 Add some tests for the process webmention job commit a354c63945c582196990823845b57c7e51ff182d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 17:55:47 2017 +0000 Add tests for save profile image job commit 0230102bafddbccd81512c37330be0e2fcb39a53 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 15:05:30 2017 +0000 Test sending webmentions commit e664e911c5fcca7fc884eda39253b503970a8bc2 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 15:04:44 2017 +0000 Fix typo in test name commit 391d1aa8f584b9e8bd8a7154b68447a2098ddc1a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 12:04:05 2017 +0000 Add tests for syndication jobs commit 16d8215c09ff235c5b8253189055ad6c17f2f009 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Dec 1 11:49:05 2017 +0000 Fix issue with scope date and month being 12 the int or 12 the string commit 0d9aaaa178b088a6856a70f4338fffea0ad8a0f3 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 30 19:00:39 2017 +0000 Improve Bookmark processing code and test coverage commit 93d4419b37af7d0fcf8fe48cb855c1290512b30c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 30 18:59:10 2017 +0000 Improve Like processing code and test coverage commit 1ccb42c48a4760daf9cf0bed744740aa931a6a89 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 30 14:12:07 2017 +0000 Try and install nginx natively, given its listed in travis-ci/apt-package-whitelist commit 126a3c4c9639eae1a986674a952923dd4e1384cc Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 30 12:09:47 2017 +0000 Test the download webmention job commit 2889e95c1526796684613d7fbb0998f654dbef28 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 30 12:08:56 2017 +0000 Test the add client job commit 4054a24e93ffe5dd68c2ab211bf6a88b114c3f10 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 21:21:09 2017 +0000 Ignore code coverage for such a trivial command commit 5bda55d401fa677a84d334b6200d7ce045e23a90 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 18:22:18 2017 +0000 For now don’t analyse laravel’s exception handler commit bb21e2ffc620cf22c14b49f2f292616f0d1bcc77 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 18:21:55 2017 +0000 test coverage commit 2980127778d5be8dee7dd119cc6eb20b7a9f5e52 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 16:30:44 2017 +0000 phpcs fixes commit 6e802bf78a93e5886a38007177d54d33ed85b31b Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 16:28:47 2017 +0000 Increase and improve tests for bookmarks commit 1f6ffbacb86be86faa2cd37022d50e41f9582d59 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 27 13:04:11 2017 +0000 Increase test coverage for token generation/validation commit 66d866fdbfd1dcd0f161d4d30c7fb79fbb4a7250 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sun Nov 26 16:58:30 2017 +0000 Increase test coverage for Place relasted code commit 6774d5c837ccc8c7d9f1cd80607dd40ffb5257f5 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sun Nov 26 16:57:42 2017 +0000 Increase test coverage for Like relasted code commit 4e055527276499eca721cf9be64473d91b30e1d9 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sun Nov 26 10:21:21 2017 +0000 Ignore code that can’t be tested from coverage analysis commit fbe7a88ab2319a3dcf4d441bd6db7be49e6445c5 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sun Nov 26 10:20:48 2017 +0000 Increase test coverages for note creation/deletion commit cae9bce276372a4870b0cbe7ebd561ef49d1b131 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 15:16:52 2017 +0000 Test a single bookmark page commit e23cf9846ae5bb28554d7665aee92826e237dc38 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 15:16:34 2017 +0000 Test login route for admin page commit 9e2902f2048edac949edd0cc73e1abbf84a4f224 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 14:11:46 2017 +0000 Improve articles controller to redirect outdated links, add tests commit 49bfaaf615461149a06bcfb74fd7a676eb3d49f8 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 13:57:03 2017 +0000 Remove Auth controllers we don’t use commit 5cebbc45aa72d24fc729c314c4f6ef1fc99c16d3 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 13:36:11 2017 +0000 More testing, looking at middleware being applied commit 2e5c9dd77143d3b23b3461decd5d1cda1375c510 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 24 13:12:56 2017 +0000 Tweak reply webmentions and re-parsing them, as well as add tests commit 766739f42fe8432daa10172ae7fcff84fe29d78d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 23 21:18:56 2017 +0000 Test redownload webmentions command dispatches the job commit 6a25e99af4bad4ea3070a1ac4277542a52f6b465 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 23 20:24:18 2017 +0000 Fixing and increasing test coverage for notes, still some work left to do commit 1e10fffb344b50a4665060d42e94cb564a8404e7 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 23 15:16:11 2017 +0000 Increase test coverage for places commit 0b40ccedd285262b57be2414dfa2fd637e80ef2b Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 23 11:54:08 2017 +0000 Tweak of code and increased test coverage commit 64dc03b381fb79046e57ba2c623cb3a667adc345 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Nov 22 15:38:17 2017 +0000 Increase text coverage for Tags commit 62bdb775ec5ec2c06595fc4d427703c683ae81a7 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Nov 22 15:25:33 2017 +0000 Increase test coverage for media-client code commit 6bcf4cb909048e94aed7b7807bbe380833c258a1 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Nov 22 15:25:05 2017 +0000 Incurease test coverage for media commit 89ede0fd1c9d7ee66b1af8be2b4d75b03b4bd8b9 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Nov 22 15:24:36 2017 +0000 Fix some issues with notes and increase test coverage commit 1ad7c952703e9098bd80c2024eeec0a0937c9db3 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:40:33 2017 +0000 Improve bookmarks test coverage commit 5a3cb440edeb9c63e9c447a36b3000dcb0b0ec7a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:40:05 2017 +0000 Add Like tests commit 8481e367ea74b081269a99ee97175f49d71176b8 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:08:38 2017 +0000 Add a another Like to the db without content and with an auhtor_url commit 4053dcf8ec02e8b3618eb3ad2b875870368eab49 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:07:32 2017 +0000 Don’t show the url instead of content, just leave blank commit 8e12a125b927efd327323044e5f86beef6ccef8c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:05:36 2017 +0000 Add tests for Article model commit d827d3399a1ed9513c4bac05e5078345f2768081 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:05:14 2017 +0000 Make sure year and month are cast to ints for scopeDate commit db747d95bc80e521604b4b3487bed6c7fd46b8fe Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 21 14:04:26 2017 +0000 Remove un-needed webmentions method, change scopeDate to use integers for month
This commit is contained in:
parent
6e02e31f52
commit
a4f07e510e
117 changed files with 3336 additions and 1330 deletions
|
@ -1,9 +1,9 @@
|
||||||
APP_ENV=testing
|
APP_ENV=testing
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_KEY=base64:6DJhvZLVjE6dD4Cqrteh+6Z5vZlG+v/soCKcDHLOAH0=
|
APP_KEY=base64:6DJhvZLVjE6dD4Cqrteh+6Z5vZlG+v/soCKcDHLOAH0=
|
||||||
APP_URL=http://localhost:8000
|
APP_URL=http://jonnybarnes.localhost:8000
|
||||||
APP_LONGURL=localhost
|
APP_LONGURL=jonnybarnes.localhost
|
||||||
APP_SHORTURL=local
|
APP_SHORTURL=jmb.localhost
|
||||||
|
|
||||||
DB_CONNECTION=travis
|
DB_CONNECTION=travis
|
||||||
|
|
||||||
|
|
16
.travis.yml
16
.travis.yml
|
@ -7,12 +7,13 @@ cache:
|
||||||
- apt
|
- apt
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
|
hosts:
|
||||||
|
- jmb.localhost
|
||||||
|
- jonnybarnes.localhost
|
||||||
postgresql: "9.6"
|
postgresql: "9.6"
|
||||||
apt:
|
apt:
|
||||||
sources:
|
|
||||||
- sourceline: 'deb http://ppa.launchpad.net/nginx/development/ubuntu trusty main'
|
|
||||||
packages:
|
packages:
|
||||||
- nginx
|
- nginx-full
|
||||||
- realpath
|
- realpath
|
||||||
- postgresql-9.6-postgis-2.3
|
- postgresql-9.6-postgis-2.3
|
||||||
- imagemagick
|
- imagemagick
|
||||||
|
@ -36,10 +37,6 @@ php:
|
||||||
- 7.1
|
- 7.1
|
||||||
- 7.2
|
- 7.2
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- php: 7.2
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- printf "\n" | pecl install imagick
|
- printf "\n" | pecl install imagick
|
||||||
- cp .env.travis .env
|
- cp .env.travis .env
|
||||||
|
@ -67,7 +64,10 @@ before_script:
|
||||||
#- sleep 5
|
#- sleep 5
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- php vendor/bin/phpunit --coverage-text
|
- php vendor/bin/phpunit --coverage-clover build/logs/clover.xml
|
||||||
- phpcs
|
- phpcs
|
||||||
#- php artisan dusk
|
#- php artisan dusk
|
||||||
- php vendor/bin/security-checker security:check --end-point=http://security.sensiolabs.org/check_lock
|
- php vendor/bin/security-checker security:check --end-point=http://security.sensiolabs.org/check_lock
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- travis_retry php vendor/bin/coveralls
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Article extends Model
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The database table used by the model.
|
* The database table used by the model.
|
||||||
|
@ -40,16 +40,6 @@ class Article extends Model
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the relationship with webmentions.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public function webmentions()
|
|
||||||
{
|
|
||||||
return $this->morphMany('App\WebMention', 'commentable');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We shall set a blacklist of non-modifiable model attributes.
|
* We shall set a blacklist of non-modifiable model attributes.
|
||||||
*
|
*
|
||||||
|
@ -66,7 +56,7 @@ class Article extends Model
|
||||||
{
|
{
|
||||||
$markdown = new CommonMarkConverter();
|
$markdown = new CommonMarkConverter();
|
||||||
$html = $markdown->convertToHtml($this->main);
|
$html = $markdown->convertToHtml($this->main);
|
||||||
//change <pre><code>[lang] ~> <pre><code data-language="lang">
|
// changes <pre><code>[lang] ~> <pre><code data-language="lang">
|
||||||
$match = '/<pre><code>\[(.*)\]\n/';
|
$match = '/<pre><code>\[(.*)\]\n/';
|
||||||
$replace = '<pre><code class="language-$1">';
|
$replace = '<pre><code class="language-$1">';
|
||||||
$text = preg_replace($match, $replace, $html);
|
$text = preg_replace($match, $replace, $html);
|
||||||
|
@ -130,20 +120,20 @@ class Article extends Model
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
public function scopeDate($query, $year = null, $month = null)
|
public function scopeDate($query, int $year = null, int $month = null)
|
||||||
{
|
{
|
||||||
if ($year == null) {
|
if ($year == null) {
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
$start = $year . '-01-01 00:00:00';
|
$start = $year . '-01-01 00:00:00';
|
||||||
$end = ($year + 1) . '-01-01 00:00:00';
|
$end = ($year + 1) . '-01-01 00:00:00';
|
||||||
if (($month !== null) && ($month !== '12')) {
|
if (($month !== null) && ($month !== 12)) {
|
||||||
$start = $year . '-' . $month . '-01 00:00:00';
|
$start = $year . '-' . $month . '-01 00:00:00';
|
||||||
$end = $year . '-' . ($month + 1) . '-01 00:00:00';
|
$end = $year . '-' . ($month + 1) . '-01 00:00:00';
|
||||||
}
|
}
|
||||||
if ($month === '12') {
|
if ($month === 12) {
|
||||||
$start = $year . '-12-01 00:00:00';
|
$start = $year . '-12-01 00:00:00';
|
||||||
//$end as above
|
$end = ($year + 1) . '-01-01 00:00:00';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->where([
|
return $query->where([
|
||||||
|
|
|
@ -5,6 +5,9 @@ namespace App\Console\Commands;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use SensioLabs\Security\SecurityChecker;
|
use SensioLabs\Security\SecurityChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
class SecurityCheck extends Command
|
class SecurityCheck extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,9 @@ use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Session\TokenMismatchException;
|
use Illuminate\Session\TokenMismatchException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Exceptions;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class InternetArchiveErrorSavingException extends Exception
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
7
app/Exceptions/InternetArchiveException.php
Normal file
7
app/Exceptions/InternetArchiveException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
class InternetArchiveException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ namespace App\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class RemoteContentNotFound extends Exception
|
class RemoteContentNotFoundException extends Exception
|
||||||
{
|
{
|
||||||
//used when guzzle can’t find the remote content
|
//used when guzzle can’t find the remote content
|
||||||
}
|
}
|
|
@ -86,9 +86,9 @@ class ClientsController extends Controller
|
||||||
* @param string The client id
|
* @param string The client id
|
||||||
* @return redirect
|
* @return redirect
|
||||||
*/
|
*/
|
||||||
public function destroy($articleId)
|
public function destroy($clientId)
|
||||||
{
|
{
|
||||||
MicropubClient::where('id', $articleId)->delete();
|
MicropubClient::where('id', $clientId)->delete();
|
||||||
|
|
||||||
return redirect('/admin/clients');
|
return redirect('/admin/clients');
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,16 +83,14 @@ class ContactsController extends Controller
|
||||||
$contact->facebook = $request->input('facebook');
|
$contact->facebook = $request->input('facebook');
|
||||||
$contact->save();
|
$contact->save();
|
||||||
|
|
||||||
if ($request->hasFile('avatar')) {
|
if ($request->hasFile('avatar') && ($request->input('homepage') != '')) {
|
||||||
if ($request->input('homepage') != '') {
|
$dir = parse_url($request->input('homepage'), PHP_URL_HOST);
|
||||||
$dir = parse_url($request->input('homepage'))['host'];
|
$destination = public_path() . '/assets/profile-images/' . $dir;
|
||||||
$destination = public_path() . '/assets/profile-images/' . $dir;
|
$filesystem = new Filesystem();
|
||||||
$filesystem = new Filesystem();
|
if ($filesystem->isDirectory($destination) === false) {
|
||||||
if ($filesystem->isDirectory($destination) === false) {
|
$filesystem->makeDirectory($destination);
|
||||||
$filesystem->makeDirectory($destination);
|
|
||||||
}
|
|
||||||
$request->file('avatar')->move($destination, 'image');
|
|
||||||
}
|
}
|
||||||
|
$request->file('avatar')->move($destination, 'image');
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect('/admin/contacts');
|
return redirect('/admin/contacts');
|
||||||
|
@ -123,37 +121,47 @@ class ContactsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function getAvatar($contactId)
|
public function getAvatar($contactId)
|
||||||
{
|
{
|
||||||
|
// Initialising
|
||||||
|
$avatarURL = null;
|
||||||
|
$avatar = null;
|
||||||
$contact = Contact::findOrFail($contactId);
|
$contact = Contact::findOrFail($contactId);
|
||||||
$homepage = $contact->homepage;
|
if (mb_strlen($contact->homepage !== null) !== 0) {
|
||||||
if (($homepage !== null) && ($homepage !== '')) {
|
$client = resolve(Client::class);
|
||||||
$client = new Client();
|
|
||||||
try {
|
try {
|
||||||
$response = $client->get($homepage);
|
$response = $client->get($contact->homepage);
|
||||||
$html = (string) $response->getBody();
|
|
||||||
$mf2 = \Mf2\parse($html, $homepage);
|
|
||||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
return "Bad Response from $homepage";
|
return redirect('/admin/contacts/' . $contactId . '/edit')
|
||||||
|
->with('error', 'Bad resposne from contact’s homepage');
|
||||||
}
|
}
|
||||||
$avatarURL = null; // Initialising
|
$mf2 = \Mf2\parse((string) $response->getBody(), $contact->homepage);
|
||||||
foreach ($mf2['items'] as $microformat) {
|
foreach ($mf2['items'] as $microformat) {
|
||||||
if ($microformat['type'][0] == 'h-card') {
|
if (array_get($microformat, 'type.0') == 'h-card') {
|
||||||
$avatarURL = $microformat['properties']['photo'][0];
|
$avatarURL = array_get($microformat, 'properties.photo.0');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
if ($avatarURL !== null) {
|
||||||
$avatar = $client->get($avatarURL);
|
try {
|
||||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
$avatar = $client->get($avatarURL);
|
||||||
return "Unable to get $avatarURL";
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
|
return redirect('/admin/contacts/' . $contactId . '/edit')
|
||||||
|
->with('error', 'Unable to download avatar');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$directory = public_path() . '/assets/profile-images/' . parse_url($homepage)['host'];
|
if ($avatar !== null) {
|
||||||
$filesystem = new Filesystem();
|
$directory = public_path() . '/assets/profile-images/' . parse_url($contact->homepage, PHP_URL_HOST);
|
||||||
if ($filesystem->isDirectory($directory) === false) {
|
$filesystem = new Filesystem();
|
||||||
$filesystem->makeDirectory($directory);
|
if ($filesystem->isDirectory($directory) === false) {
|
||||||
}
|
$filesystem->makeDirectory($directory);
|
||||||
$filesystem->put($directory . '/image', $avatar->getBody());
|
}
|
||||||
|
$filesystem->put($directory . '/image', $avatar->getBody());
|
||||||
|
|
||||||
return view('admin.contacts.getavatarsuccess', ['homepage' => parse_url($homepage)['host']]);
|
return view('admin.contacts.getavatarsuccess', [
|
||||||
|
'homepage' => parse_url($contact->homepage, PHP_URL_HOST),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return redirect('/admin/contacts/' . $contactId . '/edit');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,12 @@
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Note;
|
use App\Note;
|
||||||
use Validator;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Jobs\SendWebMentions;
|
use App\Jobs\SendWebMentions;
|
||||||
use App\Services\NoteService;
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
class NotesController extends Controller
|
class NotesController extends Controller
|
||||||
{
|
{
|
||||||
protected $noteService;
|
|
||||||
|
|
||||||
public function __construct(NoteService $noteService)
|
|
||||||
{
|
|
||||||
$this->noteService = $noteService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List the notes that can be edited.
|
* List the notes that can be edited.
|
||||||
*
|
*
|
||||||
|
@ -51,30 +42,10 @@ class NotesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$validator = Validator::make(
|
Note::create([
|
||||||
$request->all(),
|
'in-reply-to' => $request->input('in-reply-to'),
|
||||||
['photo' => 'photosize'],
|
'note' => $request->input('content'),
|
||||||
['photosize' => 'At least one uploaded file exceeds size limit of 5MB']
|
]);
|
||||||
);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect('/admin/notes/create')
|
|
||||||
->withErrors($validator)
|
|
||||||
->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
$data['content'] = $request->input('content');
|
|
||||||
$data['in-reply-to'] = $request->input('in-reply-to');
|
|
||||||
$data['location'] = $request->input('location');
|
|
||||||
$data['syndicate'] = [];
|
|
||||||
if ($request->input('twitter')) {
|
|
||||||
$data['syndicate'][] = 'twitter';
|
|
||||||
}
|
|
||||||
if ($request->input('facebook')) {
|
|
||||||
$data['syndicate'][] = 'facebook';
|
|
||||||
}
|
|
||||||
|
|
||||||
$note = $this->noteService->createNote($data);
|
|
||||||
|
|
||||||
return redirect('/admin/notes');
|
return redirect('/admin/notes');
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,11 +47,7 @@ class PlacesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = $request->only(['name', 'description', 'latitude', 'longitude']);
|
||||||
$data['name'] = $request->name;
|
|
||||||
$data['description'] = $request->description;
|
|
||||||
$data['latitude'] = $request->latitude;
|
|
||||||
$data['longitude'] = $request->longitude;
|
|
||||||
$place = $this->placeService->createPlace($data);
|
$place = $this->placeService->createPlace($data);
|
||||||
|
|
||||||
return redirect('/admin/places');
|
return redirect('/admin/places');
|
||||||
|
@ -67,14 +63,7 @@ class PlacesController extends Controller
|
||||||
{
|
{
|
||||||
$place = Place::findOrFail($placeId);
|
$place = Place::findOrFail($placeId);
|
||||||
|
|
||||||
return view('admin.places.edit', [
|
return view('admin.places.edit', compact('place'));
|
||||||
'id' => $placeId,
|
|
||||||
'name' => $place->name,
|
|
||||||
'description' => $place->description,
|
|
||||||
'latitude' => $place->latitude,
|
|
||||||
'longitude' => $place->longitude,
|
|
||||||
'icon' => $place->icon ?? 'marker',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,7 +15,7 @@ class ArticlesController extends Controller
|
||||||
public function index($year = null, $month = null)
|
public function index($year = null, $month = null)
|
||||||
{
|
{
|
||||||
$articles = Article::where('published', '1')
|
$articles = Article::where('published', '1')
|
||||||
->date($year, $month)
|
->date((int) $year, (int) $month)
|
||||||
->orderBy('updated_at', 'desc')
|
->orderBy('updated_at', 'desc')
|
||||||
->simplePaginate(5);
|
->simplePaginate(5);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class ArticlesController extends Controller
|
||||||
{
|
{
|
||||||
$article = Article::where('titleurl', $slug)->firstOrFail();
|
$article = Article::where('titleurl', $slug)->firstOrFail();
|
||||||
if ($article->updated_at->year != $year || $article->updated_at->month != $month) {
|
if ($article->updated_at->year != $year || $article->updated_at->month != $month) {
|
||||||
throw new \Exception;
|
return redirect('/blog/' . $article->updated_at->year . '/' . $article->updated_at->month .'/' . $slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('articles.show', compact('article'));
|
return view('articles.show', compact('article'));
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
|
||||||
|
|
||||||
class ForgotPasswordController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Password Reset Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller is responsible for handling password reset emails and
|
|
||||||
| includes a trait which assists in sending these notifications from
|
|
||||||
| your application to your users. Feel free to explore this trait.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use SendsPasswordResetEmails;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
|
||||||
|
|
||||||
class LoginController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Login Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles authenticating users for the application and
|
|
||||||
| redirecting them to your home screen. The controller uses a trait
|
|
||||||
| to conveniently provide its functionality to your applications.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use AuthenticatesUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $redirectTo = '/home';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest')->except('logout');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\User;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
|
||||||
|
|
||||||
class RegisterController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Register Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles the registration of new users as well as their
|
|
||||||
| validation and creation. By default this controller uses a trait to
|
|
||||||
| provide this functionality without requiring any additional code.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use RegistersUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after registration.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $redirectTo = '/home';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a validator for an incoming registration request.
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return \Illuminate\Contracts\Validation\Validator
|
|
||||||
*/
|
|
||||||
protected function validator(array $data)
|
|
||||||
{
|
|
||||||
return Validator::make($data, [
|
|
||||||
'name' => 'required|string|max:255',
|
|
||||||
'email' => 'required|string|email|max:255|unique:users',
|
|
||||||
'password' => 'required|string|min:6|confirmed',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new user instance after a valid registration.
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return \App\User
|
|
||||||
*/
|
|
||||||
protected function create(array $data)
|
|
||||||
{
|
|
||||||
return User::create([
|
|
||||||
'name' => $data['name'],
|
|
||||||
'email' => $data['email'],
|
|
||||||
'password' => bcrypt($data['password']),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Password Reset Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller is responsible for handling password reset requests
|
|
||||||
| and uses a simple trait to include this behavior. You're free to
|
|
||||||
| explore this trait and override any methods you wish to tweak.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use ResetsPasswords;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after resetting their password.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $redirectTo = '/home';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,47 +5,41 @@ namespace App\Http\Controllers;
|
||||||
use Storage;
|
use Storage;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use App\Jobs\ProcessImage;
|
use App\Jobs\ProcessMedia;
|
||||||
use App\Services\LikeService;
|
use Illuminate\Http\UploadedFile;
|
||||||
use App\Services\BookmarkService;
|
|
||||||
use Monolog\Handler\StreamHandler;
|
use Monolog\Handler\StreamHandler;
|
||||||
use App\{Like, Media, Note, Place};
|
use App\{Like, Media, Note, Place};
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use Illuminate\Http\{Request, Response};
|
use Illuminate\Http\{Request, Response};
|
||||||
use App\Exceptions\InvalidTokenException;
|
use App\Exceptions\InvalidTokenException;
|
||||||
use Phaza\LaravelPostgis\Geometries\Point;
|
use Phaza\LaravelPostgis\Geometries\Point;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Intervention\Image\Exception\NotReadableException;
|
||||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
|
||||||
use App\Services\{NoteService, PlaceService, TokenService};
|
use App\Services\{NoteService, PlaceService, TokenService};
|
||||||
|
use App\Services\Micropub\{HCardService, HEntryService, UpdateService};
|
||||||
|
|
||||||
class MicropubController extends Controller
|
class MicropubController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The Token service container.
|
|
||||||
*/
|
|
||||||
protected $tokenService;
|
protected $tokenService;
|
||||||
|
|
||||||
/**
|
|
||||||
* The Note service container.
|
|
||||||
*/
|
|
||||||
protected $noteService;
|
protected $noteService;
|
||||||
|
|
||||||
/**
|
|
||||||
* The Place service container.
|
|
||||||
*/
|
|
||||||
protected $placeService;
|
protected $placeService;
|
||||||
|
protected $hentryService;
|
||||||
|
protected $hcardService;
|
||||||
|
protected $updateService;
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject the dependencies.
|
|
||||||
*/
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TokenService $tokenService,
|
TokenService $tokenService,
|
||||||
NoteService $noteService,
|
NoteService $noteService,
|
||||||
PlaceService $placeService
|
PlaceService $placeService,
|
||||||
|
HEntryService $hentryService,
|
||||||
|
HCardService $hcardService,
|
||||||
|
UpdateService $updateService
|
||||||
) {
|
) {
|
||||||
$this->tokenService = $tokenService;
|
$this->tokenService = $tokenService;
|
||||||
$this->noteService = $noteService;
|
$this->noteService = $noteService;
|
||||||
$this->placeService = $placeService;
|
$this->placeService = $placeService;
|
||||||
|
$this->hentryService = $hentryService;
|
||||||
|
$this->hcardService = $hcardService;
|
||||||
|
$this->updateService = $updateService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,262 +54,46 @@ class MicropubController extends Controller
|
||||||
try {
|
try {
|
||||||
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
} catch (InvalidTokenException $e) {
|
} catch (InvalidTokenException $e) {
|
||||||
|
return $this->invalidTokenResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tokenData->hasClaim('scope') === false) {
|
||||||
|
return $this->tokenHasNoScopeResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logMicropubRequest($request);
|
||||||
|
|
||||||
|
if (($request->input('h') == 'entry') || ($request->input('type.0') == 'h-entry')) {
|
||||||
|
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
||||||
|
return $this->insufficientScopeResponse();
|
||||||
|
}
|
||||||
|
$location = $this->hentryService->process($request);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'created',
|
||||||
'error' => 'invalid_token',
|
'location' => $location,
|
||||||
'error_description' => 'The provided token did not pass validation',
|
], 201)->header('Location', $location);
|
||||||
], 400);
|
|
||||||
}
|
|
||||||
// Log the request
|
|
||||||
$logger = new Logger('micropub');
|
|
||||||
$logger->pushHandler(new StreamHandler(storage_path('logs/micropub.log')), Logger::DEBUG);
|
|
||||||
$logger->debug('MicropubLog', $request->all());
|
|
||||||
if ($tokenData->hasClaim('scope')) {
|
|
||||||
if (($request->input('h') == 'entry') || ($request->input('type.0') == 'h-entry')) {
|
|
||||||
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
|
||||||
return $this->returnInsufficientScopeResponse();
|
|
||||||
}
|
|
||||||
if ($request->has('properties.like-of') || $request->has('like-of')) {
|
|
||||||
$like = (new LikeService())->createLike($request);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'created',
|
|
||||||
'location' => config('app.url') . "/likes/$like->id",
|
|
||||||
], 201)->header('Location', config('app.url') . "/likes/$like->id");
|
|
||||||
}
|
|
||||||
if ($request->has('properties.bookmark-of') || $request->has('bookmark-of')) {
|
|
||||||
$bookmark = (new BookmarkService())->createBookmark($request);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'created',
|
|
||||||
'location' => config('app.url') . "/bookmarks/$bookmark->id",
|
|
||||||
], 201)->header('Location', config('app.url') . "/bookmarks/$bookmark->id");
|
|
||||||
}
|
|
||||||
$data = [];
|
|
||||||
$data['client-id'] = $tokenData->getClaim('client_id');
|
|
||||||
if ($request->header('Content-Type') == 'application/json') {
|
|
||||||
if (is_string($request->input('properties.content.0'))) {
|
|
||||||
$data['content'] = $request->input('properties.content.0'); //plaintext content
|
|
||||||
}
|
|
||||||
if (is_array($request->input('properties.content.0'))
|
|
||||||
&& array_key_exists('html', $request->input('properties.content.0'))
|
|
||||||
) {
|
|
||||||
$data['content'] = $request->input('properties.content.0.html');
|
|
||||||
}
|
|
||||||
$data['in-reply-to'] = $request->input('properties.in-reply-to.0');
|
|
||||||
// check location is geo: string
|
|
||||||
if (is_string($request->input('properties.location.0'))) {
|
|
||||||
$data['location'] = $request->input('properties.location.0');
|
|
||||||
}
|
|
||||||
// check location is h-card
|
|
||||||
if (is_array($request->input('properties.location.0'))) {
|
|
||||||
if ($request->input('properties.location.0.type.0' === 'h-card')) {
|
|
||||||
try {
|
|
||||||
$place = $this->placeService->createPlaceFromCheckin(
|
|
||||||
$request->input('properties.location.0')
|
|
||||||
);
|
|
||||||
$data['checkin'] = $place->longurl;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$data['published'] = $request->input('properties.published.0');
|
|
||||||
//create checkin place
|
|
||||||
if (array_key_exists('checkin', $request->input('properties'))) {
|
|
||||||
$data['swarm-url'] = $request->input('properties.syndication.0');
|
|
||||||
try {
|
|
||||||
$place = $this->placeService->createPlaceFromCheckin(
|
|
||||||
$request->input('properties.checkin.0')
|
|
||||||
);
|
|
||||||
$data['checkin'] = $place->longurl;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$data['checkin'] = null;
|
|
||||||
$data['swarm-url'] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$data['content'] = $request->input('content');
|
|
||||||
$data['in-reply-to'] = $request->input('in-reply-to');
|
|
||||||
$data['location'] = $request->input('location');
|
|
||||||
$data['published'] = $request->input('published');
|
|
||||||
}
|
|
||||||
$data['syndicate'] = [];
|
|
||||||
$targets = array_pluck(config('syndication.targets'), 'uid', 'service.name');
|
|
||||||
$mpSyndicateTo = null;
|
|
||||||
if ($request->has('mp-syndicate-to')) {
|
|
||||||
$mpSyndicateTo = $request->input('mp-syndicate-to');
|
|
||||||
}
|
|
||||||
if ($request->has('properties.mp-syndicate-to')) {
|
|
||||||
$mpSyndicateTo = $request->input('properties.mp-syndicate-to');
|
|
||||||
}
|
|
||||||
if (is_string($mpSyndicateTo)) {
|
|
||||||
$service = array_search($mpSyndicateTo, $targets);
|
|
||||||
if ($service == 'Twitter') {
|
|
||||||
$data['syndicate'][] = 'twitter';
|
|
||||||
}
|
|
||||||
if ($service == 'Facebook') {
|
|
||||||
$data['syndicate'][] = 'facebook';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_array($mpSyndicateTo)) {
|
|
||||||
foreach ($mpSyndicateTo as $uid) {
|
|
||||||
$service = array_search($uid, $targets);
|
|
||||||
if ($service == 'Twitter') {
|
|
||||||
$data['syndicate'][] = 'twitter';
|
|
||||||
}
|
|
||||||
if ($service == 'Facebook') {
|
|
||||||
$data['syndicate'][] = 'facebook';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$data['photo'] = [];
|
|
||||||
$photos = null;
|
|
||||||
if ($request->has('photo')) {
|
|
||||||
$photos = $request->input('photo');
|
|
||||||
}
|
|
||||||
if ($request->has('properties.photo')) {
|
|
||||||
$photos = $request->input('properties.photo');
|
|
||||||
}
|
|
||||||
if ($photos !== null) {
|
|
||||||
foreach ($photos as $photo) {
|
|
||||||
if (is_string($photo)) {
|
|
||||||
//only supporting media URLs for now
|
|
||||||
$data['photo'][] = $photo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (starts_with($request->input('properties.syndication.0'), 'https://www.instagram.com')) {
|
|
||||||
$data['instagram-url'] = $request->input('properties.syndication.0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$note = $this->noteService->createNote($data);
|
|
||||||
} catch (\Exception $exception) {
|
|
||||||
return response()->json(['error' => true], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'created',
|
|
||||||
'location' => $note->longurl,
|
|
||||||
], 201)->header('Location', $note->longurl);
|
|
||||||
}
|
|
||||||
if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') {
|
|
||||||
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
|
||||||
return $this->returnInsufficientScopeResponse();
|
|
||||||
}
|
|
||||||
$data = [];
|
|
||||||
if ($request->header('Content-Type') == 'application/json') {
|
|
||||||
$data['name'] = $request->input('properties.name');
|
|
||||||
$data['description'] = $request->input('properties.description') ?? null;
|
|
||||||
if ($request->has('properties.geo')) {
|
|
||||||
$data['geo'] = $request->input('properties.geo');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$data['name'] = $request->input('name');
|
|
||||||
$data['description'] = $request->input('description');
|
|
||||||
if ($request->has('geo')) {
|
|
||||||
$data['geo'] = $request->input('geo');
|
|
||||||
}
|
|
||||||
if ($request->has('latitude')) {
|
|
||||||
$data['latitude'] = $request->input('latitude');
|
|
||||||
$data['longitude'] = $request->input('longitude');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$place = $this->placeService->createPlace($data);
|
|
||||||
} catch (\Exception $exception) {
|
|
||||||
return response()->json(['error' => true], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'created',
|
|
||||||
'location' => $place->longurl,
|
|
||||||
], 201)->header('Location', $place->longurl);
|
|
||||||
}
|
|
||||||
if ($request->input('action') == 'update') {
|
|
||||||
if (stristr($tokenData->getClaim('scope'), 'update') === false) {
|
|
||||||
return $this->returnInsufficientScopeResponse();
|
|
||||||
}
|
|
||||||
$urlPath = parse_url($request->input('url'), PHP_URL_PATH);
|
|
||||||
//is it a note we are updating?
|
|
||||||
if (mb_substr($urlPath, 1, 5) === 'notes') {
|
|
||||||
try {
|
|
||||||
$note = Note::nb60(basename($urlPath))->firstOrFail();
|
|
||||||
} catch (ModelNotFoundException $exception) {
|
|
||||||
return response()->json([
|
|
||||||
'error' => 'invalid_request',
|
|
||||||
'error_description' => 'No known note with given ID',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
//got the note, are we dealing with a “replace” request?
|
|
||||||
if ($request->has('replace')) {
|
|
||||||
foreach ($request->input('replace') as $property => $value) {
|
|
||||||
if ($property == 'content') {
|
|
||||||
$note->note = $value[0];
|
|
||||||
}
|
|
||||||
if ($property == 'syndication') {
|
|
||||||
foreach ($value as $syndicationURL) {
|
|
||||||
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
|
||||||
$note->facebook_url = $syndicationURL;
|
|
||||||
}
|
|
||||||
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
|
||||||
$note->swarm_url = $syndicationURL;
|
|
||||||
}
|
|
||||||
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
|
||||||
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$note->save();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'updated',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
//how about “add”
|
|
||||||
if ($request->has('add')) {
|
|
||||||
foreach ($request->input('add') as $property => $value) {
|
|
||||||
if ($property == 'syndication') {
|
|
||||||
foreach ($value as $syndicationURL) {
|
|
||||||
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
|
||||||
$note->facebook_url = $syndicationURL;
|
|
||||||
}
|
|
||||||
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
|
||||||
$note->swarm_url = $syndicationURL;
|
|
||||||
}
|
|
||||||
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
|
||||||
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($property == 'photo') {
|
|
||||||
foreach ($value as $photoURL) {
|
|
||||||
if (start_with($photo, 'https://')) {
|
|
||||||
$media = new Media();
|
|
||||||
$media->path = $photoURL;
|
|
||||||
$media->type = 'image';
|
|
||||||
$media->save();
|
|
||||||
$note->media()->save($media);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$note->save();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'updated',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') {
|
||||||
'response' => 'error',
|
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
||||||
'error' => 'forbidden',
|
return $this->insufficientScopeResponse();
|
||||||
'error_description' => 'The token has no scopes',
|
}
|
||||||
], 403);
|
$location = $this->hcardService->process($request);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'created',
|
||||||
|
'location' => $location,
|
||||||
|
], 201)->header('Location', $location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->input('action') == 'update') {
|
||||||
|
if (stristr($tokenData->getClaim('scope'), 'update') === false) {
|
||||||
|
return $this->returnInsufficientScopeResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->updateService->process($request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -332,20 +110,15 @@ class MicropubController extends Controller
|
||||||
try {
|
try {
|
||||||
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
} catch (InvalidTokenException $e) {
|
} catch (InvalidTokenException $e) {
|
||||||
return response()->json([
|
return $this->invalidTokenResponse();
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'invalid_token',
|
|
||||||
'error_description' => 'The provided token did not pass validation',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
//we have a valid token, is `syndicate-to` set?
|
|
||||||
if ($request->input('q') === 'syndicate-to') {
|
if ($request->input('q') === 'syndicate-to') {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'syndicate-to' => config('syndication.targets'),
|
'syndicate-to' => config('syndication.targets'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nope, how about a config query?
|
|
||||||
if ($request->input('q') == 'config') {
|
if ($request->input('q') == 'config') {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'syndicate-to' => config('syndication.targets'),
|
'syndicate-to' => config('syndication.targets'),
|
||||||
|
@ -353,7 +126,6 @@ class MicropubController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nope, how about a geo URL?
|
|
||||||
if (substr($request->input('q'), 0, 4) === 'geo:') {
|
if (substr($request->input('q'), 0, 4) === 'geo:') {
|
||||||
preg_match_all(
|
preg_match_all(
|
||||||
'/([0-9\.\-]+)/',
|
'/([0-9\.\-]+)/',
|
||||||
|
@ -362,9 +134,6 @@ class MicropubController extends Controller
|
||||||
);
|
);
|
||||||
$distance = (count($matches[0]) == 3) ? 100 * $matches[0][2] : 1000;
|
$distance = (count($matches[0]) == 3) ? 100 * $matches[0][2] : 1000;
|
||||||
$places = Place::near(new Point($matches[0][0], $matches[0][1]))->get();
|
$places = Place::near(new Point($matches[0][0], $matches[0][1]))->get();
|
||||||
foreach ($places as $place) {
|
|
||||||
$place->uri = config('app.url') . '/places/' . $place->slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'places',
|
'response' => 'places',
|
||||||
|
@ -372,7 +141,7 @@ class MicropubController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nope, just return the token
|
// default response is just to return the token data
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'token',
|
'response' => 'token',
|
||||||
'token' => [
|
'token' => [
|
||||||
|
@ -394,69 +163,18 @@ class MicropubController extends Controller
|
||||||
try {
|
try {
|
||||||
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
} catch (InvalidTokenException $e) {
|
} catch (InvalidTokenException $e) {
|
||||||
return response()->json([
|
return $this->invalidTokenResponse();
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'invalid_token',
|
|
||||||
'error_description' => 'The provided token did not pass validation',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = new Logger('micropub');
|
if ($tokenData->hasClaim('scope') === false) {
|
||||||
$logger->pushHandler(new StreamHandler(storage_path('logs/micropub.log')), Logger::DEBUG);
|
return $this->tokenHasNoScopeResponse();
|
||||||
$logger->debug('MicropubMediaLog', $request->all());
|
}
|
||||||
//check post scope
|
|
||||||
if ($tokenData->hasClaim('scope')) {
|
|
||||||
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
|
||||||
return $this->returnInsufficientScopeResponse();
|
|
||||||
}
|
|
||||||
//check media valid
|
|
||||||
if ($request->hasFile('file') && $request->file('file')->isValid()) {
|
|
||||||
try {
|
|
||||||
$filename = Uuid::uuid4() . '.' . $request->file('file')->extension();
|
|
||||||
} catch (UnsatisfiedDependencyException $e) {
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'internal_server_error',
|
|
||||||
'error_description' => 'A problem occured handling your request',
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
$size = $request->file('file')->getClientSize();
|
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
||||||
Storage::disk('local')->put($filename, $request->file('file')->openFile()->fread($size));
|
return $this->insufficientScopeResponse();
|
||||||
try {
|
}
|
||||||
Storage::disk('s3')->put('media/' . $filename, $request->file('file')->openFile()->fread($size));
|
|
||||||
} catch (Exception $e) { // which exception?
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'service_unavailable',
|
|
||||||
'error_description' => 'Unable to save media to S3',
|
|
||||||
], 503);
|
|
||||||
}
|
|
||||||
|
|
||||||
$manager = app()->make(ImageManager::class);
|
|
||||||
try {
|
|
||||||
$image = $manager->make($request->file('file'));
|
|
||||||
$width = $image->width();
|
|
||||||
} catch (\Intervention\Image\Exception\NotReadableException $exception) {
|
|
||||||
// not an image
|
|
||||||
$width = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$media = new Media();
|
|
||||||
$media->token = $request->bearerToken();
|
|
||||||
$media->path = 'media/' . $filename;
|
|
||||||
$media->type = $this->getFileTypeFromMimeType($request->file('file')->getMimeType());
|
|
||||||
$media->image_widths = $width;
|
|
||||||
$media->save();
|
|
||||||
|
|
||||||
dispatch(new ProcessImage($filename));
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'created',
|
|
||||||
'location' => $media->url,
|
|
||||||
], 201)->header('Location', $media->url);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (($request->hasFile('file') && $request->file('file')->isValid()) === false) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'invalid_request',
|
'error' => 'invalid_request',
|
||||||
|
@ -464,11 +182,32 @@ class MicropubController extends Controller
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logMicropubRequest($request);
|
||||||
|
|
||||||
|
$filename = $this->saveFile($request->file('file'));
|
||||||
|
|
||||||
|
$manager = resolve(ImageManager::class);
|
||||||
|
try {
|
||||||
|
$image = $manager->make($request->file('file'));
|
||||||
|
$width = $image->width();
|
||||||
|
} catch (NotReadableException $exception) {
|
||||||
|
// not an image
|
||||||
|
$width = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$media = Media::create([
|
||||||
|
'token' => $request->bearerToken(),
|
||||||
|
'path' => 'media/' . $filename,
|
||||||
|
'type' => $this->getFileTypeFromMimeType($request->file('file')->getMimeType()),
|
||||||
|
'image_widths' => $width,
|
||||||
|
]);
|
||||||
|
|
||||||
|
ProcessMedia::dispatch($filename);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'created',
|
||||||
'error' => 'invalid_request',
|
'location' => $media->url,
|
||||||
'error_description' => 'The provided token has no scopes',
|
], 201)->header('Location', $media->url);
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -515,7 +254,23 @@ class MicropubController extends Controller
|
||||||
return 'download';
|
return 'download';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function returnInsufficientScopeResponse()
|
private function logMicropubRequest(Request $request)
|
||||||
|
{
|
||||||
|
$logger = new Logger('micropub');
|
||||||
|
$logger->pushHandler(new StreamHandler(storage_path('logs/micropub.log')), Logger::DEBUG);
|
||||||
|
$logger->debug('MicropubLog', $request->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveFile(UploadedFile $file)
|
||||||
|
{
|
||||||
|
$filename = Uuid::uuid4() . '.' . $file->extension();
|
||||||
|
$size = $file->getClientSize();
|
||||||
|
Storage::disk('local')->put($filename, $file->openFile()->fread($size));
|
||||||
|
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insufficientScopeResponse()
|
||||||
{
|
{
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
|
@ -523,4 +278,22 @@ class MicropubController extends Controller
|
||||||
'error_description' => 'The token’s scope does not have the necessary requirements.',
|
'error_description' => 'The token’s scope does not have the necessary requirements.',
|
||||||
], 401);
|
], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function invalidTokenResponse()
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'error',
|
||||||
|
'error' => 'invalid_token',
|
||||||
|
'error_description' => 'The provided token did not pass validation',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function tokenHasNoScopeResponse()
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'error',
|
||||||
|
'error' => 'invalid_request',
|
||||||
|
'error_description' => 'The provided token has no scopes',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Note;
|
|
||||||
use Imagine\Image\Box;
|
|
||||||
use Imagine\Gd\Imagine;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Filesystem\Filesystem;
|
|
||||||
|
|
||||||
class PhotosController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Image box size limit for resizing photos.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->imageResizeLimit = 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save an uploaded photo to the image folder.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param string The associated note’s nb60 ID
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function saveImage(Request $request, $nb60id)
|
|
||||||
{
|
|
||||||
if ($request->hasFile('photo') !== true) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$photoFilename = 'note-' . $nb60id;
|
|
||||||
$path = public_path() . '/assets/img/notes/';
|
|
||||||
$ext = $request->file('photo')->getClientOriginalExtension();
|
|
||||||
$photoFilename .= '.' . $ext;
|
|
||||||
$request->file('photo')->move($path, $photoFilename);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare a photo for posting to twitter.
|
|
||||||
*
|
|
||||||
* @param string photo fileanme
|
|
||||||
* @return string small photo filename, or null
|
|
||||||
*/
|
|
||||||
public function makeSmallPhotoForTwitter($photoFilename)
|
|
||||||
{
|
|
||||||
$imagine = new Imagine();
|
|
||||||
$orig = $imagine->open(public_path() . '/assets/img/notes/' . $photoFilename);
|
|
||||||
$size = [$orig->getSize()->getWidth(), $orig->getSize()->getHeight()];
|
|
||||||
if ($size[0] > $this->imageResizeLimit || $size[1] > $this->imageResizeLimit) {
|
|
||||||
$filenameParts = explode('.', $photoFilename);
|
|
||||||
$preExt = count($filenameParts) - 2;
|
|
||||||
$filenameParts[$preExt] .= '-small';
|
|
||||||
$photoFilenameSmall = implode('.', $filenameParts);
|
|
||||||
$aspectRatio = $size[0] / $size[1];
|
|
||||||
$box = ($aspectRatio >= 1) ?
|
|
||||||
[$this->imageResizeLimit, (int) round($this->imageResizeLimit / $aspectRatio)]
|
|
||||||
:
|
|
||||||
[(int) round($this->imageResizeLimit * $aspectRatio), $this->imageResizeLimit];
|
|
||||||
$orig->resize(new Box($box[0], $box[1]))
|
|
||||||
->save(public_path() . '/assets/img/notes/' . $photoFilenameSmall);
|
|
||||||
|
|
||||||
return $photoFilenameSmall;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the image path for a note.
|
|
||||||
*
|
|
||||||
* @param string $nb60id
|
|
||||||
* @return string | null
|
|
||||||
*/
|
|
||||||
public function getPhotoPath($nb60id)
|
|
||||||
{
|
|
||||||
$filesystem = new Filesystem();
|
|
||||||
$photoDir = public_path() . '/assets/img/notes';
|
|
||||||
$files = $filesystem->files($photoDir);
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$parts = explode('.', $file);
|
|
||||||
$name = $parts[0];
|
|
||||||
$dirs = explode('/', $name);
|
|
||||||
$actualname = last($dirs);
|
|
||||||
if ($actualname == 'note-' . $nb60id) {
|
|
||||||
$ext = $parts[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($ext)) {
|
|
||||||
return '/assets/img/notes/note-' . $nb60id . '.' . $ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,16 +10,6 @@ class SearchController extends Controller
|
||||||
public function search(Request $request)
|
public function search(Request $request)
|
||||||
{
|
{
|
||||||
$notes = Note::search($request->terms)->paginate(10);
|
$notes = Note::search($request->terms)->paginate(10);
|
||||||
foreach ($notes as $note) {
|
|
||||||
$note->iso8601_time = $note->updated_at->toISO8601String();
|
|
||||||
$note->human_time = $note->updated_at->diffForHumans();
|
|
||||||
$photoURLs = [];
|
|
||||||
$photos = $note->getMedia();
|
|
||||||
foreach ($photos as $photo) {
|
|
||||||
$photoURLs[] = $photo->getUrl();
|
|
||||||
}
|
|
||||||
$note->photoURLs = $photoURLs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('search', compact('notes'));
|
return view('search', compact('notes'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\ShortURL;
|
|
||||||
use Jonnybanres\IndieWeb\Numbers;
|
|
||||||
|
|
||||||
class ShortURLsController extends Controller
|
class ShortURLsController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -41,21 +38,11 @@ class ShortURLsController extends Controller
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||||
*/
|
*/
|
||||||
public function googlePLus()
|
public function googlePlus()
|
||||||
{
|
{
|
||||||
return redirect('https://plus.google.com/u/0/117317270900655269082/about');
|
return redirect('https://plus.google.com/u/0/117317270900655269082/about');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect from '/α' to an App.net profile.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Routing\Redirector redirect
|
|
||||||
*/
|
|
||||||
public function appNet()
|
|
||||||
{
|
|
||||||
return redirect('https://alpha.app.net/jonnybarnes');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirect a short url of this site out to a long one based on post type.
|
* Redirect a short url of this site out to a long one based on post type.
|
||||||
* Further redirects may happen.
|
* Further redirects may happen.
|
||||||
|
@ -75,46 +62,4 @@ class ShortURLsController extends Controller
|
||||||
|
|
||||||
return redirect(config('app.url') . '/' . $type . '/' . $postId);
|
return redirect(config('app.url') . '/' . $type . '/' . $postId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect a saved short URL, this is generic.
|
|
||||||
*
|
|
||||||
* @param string The short URL id
|
|
||||||
* @return \Illuminate\Routing\Redirector redirect
|
|
||||||
*/
|
|
||||||
public function redirect($shortURLId)
|
|
||||||
{
|
|
||||||
$numbers = new Numbers();
|
|
||||||
$num = $numbers->b60tonum($shortURLId);
|
|
||||||
$shorturl = ShortURL::find($num);
|
|
||||||
$redirect = $shorturl->redirect;
|
|
||||||
|
|
||||||
return redirect($redirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I had an old redirect systme breifly, but cool URLs should still work.
|
|
||||||
*
|
|
||||||
* @param string URL ID
|
|
||||||
* @return \Illuminate\Routing\Redirector redirect
|
|
||||||
*/
|
|
||||||
public function oldRedirect($shortURLId)
|
|
||||||
{
|
|
||||||
$filename = base_path() . '/public/assets/old-shorturls.json';
|
|
||||||
$handle = fopen($filename, 'r');
|
|
||||||
$contents = fread($handle, filesize($filename));
|
|
||||||
$object = json_decode($contents);
|
|
||||||
|
|
||||||
foreach ($object as $key => $val) {
|
|
||||||
if ($shortURLId == $key) {
|
|
||||||
return redirect($val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'This id was never used.
|
|
||||||
Old redirects are located at
|
|
||||||
<code>
|
|
||||||
<a href="https://jonnybarnes.net/assets/old-shorturls.json">old-shorturls.json</a>
|
|
||||||
</code>.';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,35 +36,32 @@ class WebMentionsController extends Controller
|
||||||
$path = parse_url($request->input('target'), PHP_URL_PATH);
|
$path = parse_url($request->input('target'), PHP_URL_PATH);
|
||||||
$pathParts = explode('/', $path);
|
$pathParts = explode('/', $path);
|
||||||
|
|
||||||
switch ($pathParts[1]) {
|
if ($pathParts[1] == 'notes') {
|
||||||
case 'notes':
|
//we have a note
|
||||||
//we have a note
|
$noteId = $pathParts[2];
|
||||||
$noteId = $pathParts[2];
|
$numbers = new Numbers();
|
||||||
$numbers = new Numbers();
|
try {
|
||||||
try {
|
$note = Note::findOrFail($numbers->b60tonum($noteId));
|
||||||
$note = Note::findOrFail($numbers->b60tonum($noteId));
|
dispatch(new ProcessWebMention($note, $request->input('source')));
|
||||||
dispatch(new ProcessWebMention($note, $request->input('source')));
|
} catch (ModelNotFoundException $e) {
|
||||||
} catch (ModelNotFoundException $e) {
|
return new Response('This note doesn’t exist.', 400);
|
||||||
return new Response('This note doesn’t exist.', 400);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
'Webmention received, it will be processed shortly',
|
'Webmention received, it will be processed shortly',
|
||||||
202
|
202
|
||||||
);
|
);
|
||||||
break;
|
|
||||||
case 'blog':
|
|
||||||
return new Response(
|
|
||||||
'I don’t accept webmentions for blog posts yet.',
|
|
||||||
501
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return new Response(
|
|
||||||
'Invalid request',
|
|
||||||
400
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if ($pathParts[1] == 'blog') {
|
||||||
|
return new Response(
|
||||||
|
'I don’t accept webmentions for blog posts yet.',
|
||||||
|
501
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
'Invalid request',
|
||||||
|
400
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ class Kernel extends HttpKernel
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\App\Http\Middleware\LinkHeadersMiddleware::class,
|
\App\Http\Middleware\LinkHeadersMiddleware::class,
|
||||||
//\App\Http\Middleware\DevTokenMiddleware::class,
|
|
||||||
\App\Http\Middleware\LocalhostSessionMiddleware::class,
|
\App\Http\Middleware\LocalhostSessionMiddleware::class,
|
||||||
\App\Http\Middleware\ActivityStreamLinks::class,
|
\App\Http\Middleware\ActivityStreamLinks::class,
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class DevTokenMiddleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure $next
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
|
||||||
if (config('app.env') !== 'production') {
|
|
||||||
session(['me' => config('app.url')]);
|
|
||||||
if (Storage::exists('dev-token')) {
|
|
||||||
session(['token' => Storage::get('dev-token')]);
|
|
||||||
} else {
|
|
||||||
$data = [
|
|
||||||
'me' => config('app.url'),
|
|
||||||
'client_id' => route('micropub-client'),
|
|
||||||
'scope' => 'post',
|
|
||||||
];
|
|
||||||
$tokenService = new \App\Services\TokenService();
|
|
||||||
session(['token' => $tokenService->getNewToken($data)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,9 @@ namespace App\Http\Middleware;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
class RedirectIfAuthenticated
|
class RedirectIfAuthenticated
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,7 +41,7 @@ class DownloadWebMention implements ShouldQueue
|
||||||
//Laravel should catch and retry these automatically.
|
//Laravel should catch and retry these automatically.
|
||||||
if ($response->getStatusCode() == '200') {
|
if ($response->getStatusCode() == '200') {
|
||||||
$filesystem = new \Illuminate\FileSystem\FileSystem();
|
$filesystem = new \Illuminate\FileSystem\FileSystem();
|
||||||
$filename = storage_path() . '/HTML/' . $this->createFilenameFromURL($this->source);
|
$filename = storage_path('HTML') . '/' . $this->createFilenameFromURL($this->source);
|
||||||
//backup file first
|
//backup file first
|
||||||
$filenameBackup = $filename . '.' . date('Y-m-d') . '.backup';
|
$filenameBackup = $filename . '.' . date('Y-m-d') . '.backup';
|
||||||
if ($filesystem->exists($filename)) {
|
if ($filesystem->exists($filename)) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use App\Exceptions\InternetArchiveErrorSavingException;
|
use App\Exceptions\InternetArchiveException;
|
||||||
|
|
||||||
class ProcessBookmark implements ShouldQueue
|
class ProcessBookmark implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
@ -34,12 +34,12 @@ class ProcessBookmark implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$uuid = (new BookmarkService())->saveScreenshot($this->bookmark->url);
|
$uuid = (resolve(BookmarkService::class))->saveScreenshot($this->bookmark->url);
|
||||||
$this->bookmark->screenshot = $uuid;
|
$this->bookmark->screenshot = $uuid;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$archiveLink = (new BookmarkService())->getArchiveLink($this->bookmark->url);
|
$archiveLink = (resolve(BookmarkService::class))->getArchiveLink($this->bookmark->url);
|
||||||
} catch (InternetArchiveErrorSavingException $e) {
|
} catch (InternetArchiveException $e) {
|
||||||
$archiveLink = null;
|
$archiveLink = null;
|
||||||
}
|
}
|
||||||
$this->bookmark->archive = $archiveLink;
|
$this->bookmark->archive = $archiveLink;
|
||||||
|
|
|
@ -44,8 +44,8 @@ class ProcessLike implements ShouldQueue
|
||||||
try {
|
try {
|
||||||
$author = $authorship->findAuthor($mf2);
|
$author = $authorship->findAuthor($mf2);
|
||||||
if (is_array($author)) {
|
if (is_array($author)) {
|
||||||
$this->like->author_name = $author['name'];
|
$this->like->author_name = array_get($author, 'properties.name.0');
|
||||||
$this->like->author_url = $author['url'];
|
$this->like->author_url = array_get($author, 'properties.url.0');
|
||||||
}
|
}
|
||||||
if (is_string($author) && $author !== '') {
|
if (is_string($author) && $author !== '') {
|
||||||
$this->like->author_name = $author;
|
$this->like->author_name = $author;
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use Storage;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Intervention\Image\Exception\NotReadableException;
|
use Intervention\Image\Exception\NotReadableException;
|
||||||
|
|
||||||
class ProcessImage implements ShouldQueue
|
class ProcessMedia implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
@ -34,6 +34,10 @@ class ProcessImage implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle(ImageManager $manager)
|
public function handle(ImageManager $manager)
|
||||||
{
|
{
|
||||||
|
Storage::disk('s3')->put(
|
||||||
|
'media/' . $this->filename,
|
||||||
|
storage_path('app') . '/' . $this->filename
|
||||||
|
);
|
||||||
//open file
|
//open file
|
||||||
try {
|
try {
|
||||||
$image = $manager->make(storage_path('app') . '/' . $this->filename);
|
$image = $manager->make(storage_path('app') . '/' . $this->filename);
|
|
@ -41,23 +41,25 @@ class ProcessWebMention implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle(Parser $parser, Client $guzzle)
|
public function handle(Parser $parser, Client $guzzle)
|
||||||
{
|
{
|
||||||
$remoteContent = $this->getRemoteContent($this->source, $guzzle);
|
try {
|
||||||
if ($remoteContent === null) {
|
$response = $guzzle->request('GET', $this->source);
|
||||||
|
} catch (RequestException $e) {
|
||||||
throw new RemoteContentNotFoundException;
|
throw new RemoteContentNotFoundException;
|
||||||
}
|
}
|
||||||
$microformats = Mf2\parse($remoteContent, $this->source);
|
$this->saveRemoteContent((string) $response->getBody(), $this->source);
|
||||||
|
$microformats = Mf2\parse((string) $response->getBody(), $this->source);
|
||||||
$webmentions = WebMention::where('source', $this->source)->get();
|
$webmentions = WebMention::where('source', $this->source)->get();
|
||||||
foreach ($webmentions as $webmention) {
|
foreach ($webmentions as $webmention) {
|
||||||
//check webmention still references target
|
// check webmention still references target
|
||||||
//we try each type of mention (reply/like/repost)
|
// we try each type of mention (reply/like/repost)
|
||||||
if ($webmention->type == 'in-reply-to') {
|
if ($webmention->type == 'in-reply-to') {
|
||||||
if ($parser->checkInReplyTo($microformats, $this->note->longurl) == false) {
|
if ($parser->checkInReplyTo($microformats, $this->note->longurl) == false) {
|
||||||
//it doesn't so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//webmenion is still a reply, so update content
|
// webmenion is still a reply, so update content
|
||||||
dispatch(new SaveProfileImage($microformats));
|
dispatch(new SaveProfileImage($microformats));
|
||||||
$webmention->mf2 = json_encode($microformats);
|
$webmention->mf2 = json_encode($microformats);
|
||||||
$webmention->save();
|
$webmention->save();
|
||||||
|
@ -66,25 +68,25 @@ class ProcessWebMention implements ShouldQueue
|
||||||
}
|
}
|
||||||
if ($webmention->type == 'like-of') {
|
if ($webmention->type == 'like-of') {
|
||||||
if ($parser->checkLikeOf($microformats, $note->longurl) == false) {
|
if ($parser->checkLikeOf($microformats, $note->longurl) == false) {
|
||||||
//it doesn't so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} //note we don't need to do anything if it still is a like
|
} // note we don’t need to do anything if it still is a like
|
||||||
}
|
}
|
||||||
if ($webmention->type == 'repost-of') {
|
if ($webmention->type == 'repost-of') {
|
||||||
if ($parser->checkRepostOf($microformats, $note->longurl) == false) {
|
if ($parser->checkRepostOf($microformats, $note->longurl) == false) {
|
||||||
//it doesn't so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} //again, we don't need to do anything if it still is a repost
|
} // again, we don’t need to do anything if it still is a repost
|
||||||
}
|
}
|
||||||
}//foreach
|
}// foreach
|
||||||
|
|
||||||
//no wemention in db so create new one
|
// no webmention in the db so create new one
|
||||||
$webmention = new WebMention();
|
$webmention = new WebMention();
|
||||||
$type = $parser->getMentionType($microformats); //throw error here?
|
$type = $parser->getMentionType($microformats); // throw error here?
|
||||||
dispatch(new SaveProfileImage($microformats));
|
dispatch(new SaveProfileImage($microformats));
|
||||||
$webmention->source = $this->source;
|
$webmention->source = $this->source;
|
||||||
$webmention->target = $this->note->longurl;
|
$webmention->target = $this->note->longurl;
|
||||||
|
@ -96,21 +98,23 @@ class ProcessWebMention implements ShouldQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreive the remote content from a URL, and caches the result.
|
* Save the HTML of a webmention for future use.
|
||||||
*
|
*
|
||||||
|
* @param string $html
|
||||||
* @param string $url
|
* @param string $url
|
||||||
* @param GuzzleHttp\client $guzzle
|
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
private function getRemoteContent($url, Client $guzzle)
|
private function saveRemoteContent($html, $url)
|
||||||
{
|
{
|
||||||
try {
|
$filenameFromURL = str_replace(
|
||||||
$response = $guzzle->request('GET', $url);
|
['https://', 'http://'],
|
||||||
} catch (RequestException $e) {
|
['https/', 'http/'],
|
||||||
return;
|
$url
|
||||||
|
);
|
||||||
|
if (substr($url, -1) == '/') {
|
||||||
|
$filenameFromURL .= 'index.html';
|
||||||
}
|
}
|
||||||
$html = (string) $response->getBody();
|
$path = storage_path() . '/HTML/' . $filenameFromURL;
|
||||||
$path = storage_path() . '/HTML/' . $this->createFilenameFromURL($url);
|
|
||||||
$parts = explode('/', $path);
|
$parts = explode('/', $path);
|
||||||
$name = array_pop($parts);
|
$name = array_pop($parts);
|
||||||
$dir = implode('/', $parts);
|
$dir = implode('/', $parts);
|
||||||
|
@ -118,24 +122,5 @@ class ProcessWebMention implements ShouldQueue
|
||||||
mkdir($dir, 0755, true);
|
mkdir($dir, 0755, true);
|
||||||
}
|
}
|
||||||
file_put_contents("$dir/$name", $html);
|
file_put_contents("$dir/$name", $html);
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a file path from a URL. This is used when caching the HTML
|
|
||||||
* response.
|
|
||||||
*
|
|
||||||
* @param string The URL
|
|
||||||
* @return string The path name
|
|
||||||
*/
|
|
||||||
private function createFilenameFromURL($url)
|
|
||||||
{
|
|
||||||
$url = str_replace(['https://', 'http://'], ['https/', 'http/'], $url);
|
|
||||||
if (substr($url, -1) == '/') {
|
|
||||||
$url = $url . 'index.html';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ class SaveProfileImage implements ShouldQueue
|
||||||
//dont save pbs.twimg.com links
|
//dont save pbs.twimg.com links
|
||||||
if (parse_url($photo, PHP_URL_HOST) != 'pbs.twimg.com'
|
if (parse_url($photo, PHP_URL_HOST) != 'pbs.twimg.com'
|
||||||
&& parse_url($photo, PHP_URL_HOST) != 'twitter.com') {
|
&& parse_url($photo, PHP_URL_HOST) != 'twitter.com') {
|
||||||
$client = new Client();
|
$client = resolve(Client::class);
|
||||||
try {
|
try {
|
||||||
$response = $client->get($photo);
|
$response = $client->get($photo);
|
||||||
$image = $response->getBody(true);
|
$image = $response->getBody(true);
|
||||||
|
|
|
@ -29,18 +29,18 @@ class SendWebMentions implements ShouldQueue
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*
|
*
|
||||||
* @param \GuzzleHttp\Client $guzzle
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle(Client $guzzle)
|
public function handle()
|
||||||
{
|
{
|
||||||
//grab the URLs
|
//grab the URLs
|
||||||
$urlsInReplyTo = explode(' ', $this->note->in_reply_to);
|
$urlsInReplyTo = explode(' ', $this->note->in_reply_to);
|
||||||
$urlsNote = $this->getLinks($this->note->note);
|
$urlsNote = $this->getLinks($this->note->note);
|
||||||
$urls = array_filter(array_merge($urlsInReplyTo, $urlsNote)); //filter out none URLs
|
$urls = array_filter(array_merge($urlsInReplyTo, $urlsNote)); //filter out none URLs
|
||||||
foreach ($urls as $url) {
|
foreach ($urls as $url) {
|
||||||
$endpoint = $this->discoverWebmentionEndpoint($url, $guzzle);
|
$endpoint = $this->discoverWebmentionEndpoint($url);
|
||||||
if ($endpoint) {
|
if ($endpoint !== null) {
|
||||||
|
$guzzle = resolve(Client::class);
|
||||||
$guzzle->post($endpoint, [
|
$guzzle->post($endpoint, [
|
||||||
'form_params' => [
|
'form_params' => [
|
||||||
'source' => $this->note->longurl,
|
'source' => $this->note->longurl,
|
||||||
|
@ -55,21 +55,21 @@ class SendWebMentions implements ShouldQueue
|
||||||
* Discover if a URL has a webmention endpoint.
|
* Discover if a URL has a webmention endpoint.
|
||||||
*
|
*
|
||||||
* @param string The URL
|
* @param string The URL
|
||||||
* @param \GuzzleHttp\Client $guzzle
|
|
||||||
* @return string The webmention endpoint URL
|
* @return string The webmention endpoint URL
|
||||||
*/
|
*/
|
||||||
public function discoverWebmentionEndpoint($url, $guzzle)
|
public function discoverWebmentionEndpoint($url)
|
||||||
{
|
{
|
||||||
//let’s not send webmentions to myself
|
//let’s not send webmentions to myself
|
||||||
if (parse_url($url, PHP_URL_HOST) == config('app.longurl')) {
|
if (parse_url($url, PHP_URL_HOST) == config('app.longurl')) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (starts_with($url, '/notes/tagged/')) {
|
if (starts_with($url, '/notes/tagged/')) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$endpoint = null;
|
$endpoint = null;
|
||||||
|
|
||||||
|
$guzzle = resolve(Client::class);
|
||||||
$response = $guzzle->get($url);
|
$response = $guzzle->get($url);
|
||||||
//check HTTP Headers for webmention endpoint
|
//check HTTP Headers for webmention endpoint
|
||||||
$links = \GuzzleHttp\Psr7\parse_header($response->getHeader('Link'));
|
$links = \GuzzleHttp\Psr7\parse_header($response->getHeader('Link'));
|
||||||
|
@ -92,8 +92,6 @@ class SendWebMentions implements ShouldQueue
|
||||||
if ($endpoint) {
|
if ($endpoint) {
|
||||||
return $this->resolveUri($endpoint, $url);
|
return $this->resolveUri($endpoint, $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,10 +8,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
class SyndicateBookmarkToFacebook implements ShouldQueue
|
class SyndicateBookmarkToFacebook implements ShouldQueue
|
||||||
{
|
{
|
||||||
use InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
protected $bookmark;
|
protected $bookmark;
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
class SyndicateBookmarkToTwitter implements ShouldQueue
|
class SyndicateBookmarkToTwitter implements ShouldQueue
|
||||||
{
|
{
|
||||||
use InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
protected $bookmark;
|
protected $bookmark;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Like extends Model
|
||||||
public function getContentAttribute($value)
|
public function getContentAttribute($value)
|
||||||
{
|
{
|
||||||
if ($value === null) {
|
if ($value === null) {
|
||||||
return $this->url;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$mf2 = Mf2\parse($value, $this->url);
|
$mf2 = Mf2\parse($value, $this->url);
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Media extends Model
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['path'];
|
protected $fillable = ['token', 'path', 'type', 'image_widths'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the note that owns this media.
|
* Get the note that owns this media.
|
||||||
|
@ -70,10 +70,10 @@ class Media extends Model
|
||||||
|
|
||||||
public function getBasename($path)
|
public function getBasename($path)
|
||||||
{
|
{
|
||||||
$filenameParts = explode('.', $path);
|
|
||||||
|
|
||||||
// the following achieves this data flow
|
// the following achieves this data flow
|
||||||
// foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar
|
// foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar
|
||||||
|
$filenameParts = explode('.', $path);
|
||||||
|
array_pop($filenameParts);
|
||||||
$basename = ltrim(array_reduce($filenameParts, function ($carry, $item) {
|
$basename = ltrim(array_reduce($filenameParts, function ($carry, $item) {
|
||||||
return $carry . '.' . $item;
|
return $carry . '.' . $item;
|
||||||
}, ''), '.');
|
}, ''), '.');
|
||||||
|
|
63
app/Note.php
63
app/Note.php
|
@ -146,9 +146,9 @@ class Note extends Model
|
||||||
$emoji = new EmojiModifier();
|
$emoji = new EmojiModifier();
|
||||||
|
|
||||||
$hcards = $this->makeHCards($value);
|
$hcards = $this->makeHCards($value);
|
||||||
$html = $this->convertMarkdown($hcards);
|
$hashtags = $this->autoLinkHashtag($hcards);
|
||||||
$hashtags = $this->autoLinkHashtag($html);
|
$html = $this->convertMarkdown($hashtags);
|
||||||
$modified = $emoji->makeEmojiAccessible($hashtags);
|
$modified = $emoji->makeEmojiAccessible($html);
|
||||||
|
|
||||||
return $modified;
|
return $modified;
|
||||||
}
|
}
|
||||||
|
@ -223,9 +223,7 @@ class Note extends Model
|
||||||
public function getLatitudeAttribute()
|
public function getLatitudeAttribute()
|
||||||
{
|
{
|
||||||
if ($this->place !== null) {
|
if ($this->place !== null) {
|
||||||
$lnglat = explode(' ', $this->place->location);
|
return $this->place->location->getLat();
|
||||||
|
|
||||||
return $lnglat[1];
|
|
||||||
}
|
}
|
||||||
if ($this->location !== null) {
|
if ($this->location !== null) {
|
||||||
$pieces = explode(':', $this->location);
|
$pieces = explode(':', $this->location);
|
||||||
|
@ -243,9 +241,7 @@ class Note extends Model
|
||||||
public function getLongitudeAttribute()
|
public function getLongitudeAttribute()
|
||||||
{
|
{
|
||||||
if ($this->place !== null) {
|
if ($this->place !== null) {
|
||||||
$lnglat = explode(' ', $this->place->location);
|
return $this->place->location->getLng();
|
||||||
|
|
||||||
return $lnglat[1];
|
|
||||||
}
|
}
|
||||||
if ($this->location !== null) {
|
if ($this->location !== null) {
|
||||||
$pieces = explode(':', $this->location);
|
$pieces = explode(':', $this->location);
|
||||||
|
@ -281,12 +277,13 @@ class Note extends Model
|
||||||
if (Cache::has($tweetId)) {
|
if (Cache::has($tweetId)) {
|
||||||
return Cache::get($tweetId);
|
return Cache::get($tweetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$oEmbed = Twitter::getOembed([
|
$oEmbed = Twitter::getOembed([
|
||||||
'id' => $tweetId,
|
'url' => $this->in_reply_to,
|
||||||
'dnt' => true,
|
'dnt' => true,
|
||||||
'align' => 'center',
|
'align' => 'center',
|
||||||
'maxwidth' => 550,
|
'maxwidth' => 512,
|
||||||
]);
|
]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return;
|
return;
|
||||||
|
@ -408,10 +405,10 @@ class Note extends Model
|
||||||
|
|
||||||
$contact = $this->contacts[$matches[1]]; // easier to read the following code
|
$contact = $this->contacts[$matches[1]]; // easier to read the following code
|
||||||
$host = parse_url($contact->homepage, PHP_URL_HOST);
|
$host = parse_url($contact->homepage, PHP_URL_HOST);
|
||||||
$contact->photo = (file_exists(public_path() . '/assets/profile-images/' . $host . '/image')) ?
|
$contact->photo = '/assets/profile-images/default-image';
|
||||||
'/assets/profile-images/' . $host . '/image'
|
if (file_exists(public_path() . '/assets/profile-images/' . $host . '/image')) {
|
||||||
:
|
$contact->photo = '/assets/profile-images/' . $host . '/image';
|
||||||
'/assets/profile-images/default-image';
|
}
|
||||||
|
|
||||||
return trim(view('templates.mini-hcard', ['contact' => $contact])->render());
|
return trim(view('templates.mini-hcard', ['contact' => $contact])->render());
|
||||||
},
|
},
|
||||||
|
@ -450,31 +447,17 @@ class Note extends Model
|
||||||
* @param string The note
|
* @param string The note
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function autoLinkHashtag($text)
|
public function autoLinkHashtag($text)
|
||||||
{
|
{
|
||||||
// $replacements = ["#tag" => "<a rel="tag" href="/tags/tag">#tag</a>]
|
return preg_replace_callback(
|
||||||
$replacements = [];
|
'/#([^\s]*)\b/',
|
||||||
$matches = [];
|
function ($matches) {
|
||||||
|
return '<a rel="tag" class="p-category" href="/notes/tagged/'
|
||||||
if (preg_match_all('/(?<=^|\s)\#([a-zA-Z0-9\-\_]+)/i', $text, $matches, PREG_PATTERN_ORDER)) {
|
. Tag::normalize($matches[1]) . '">#'
|
||||||
// Look up #tags, get Full name and URL
|
. Tag::normalize($matches[1]) . '</a>';
|
||||||
foreach ($matches[0] as $name) {
|
},
|
||||||
$name = str_replace('#', '', $name);
|
$text
|
||||||
$replacements[$name] =
|
);
|
||||||
'<a rel="tag" class="p-category" href="/notes/tagged/'
|
|
||||||
. Tag::normalize($name)
|
|
||||||
. '">#'
|
|
||||||
. $name
|
|
||||||
. '</a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace #tags with valid microformat-enabled link
|
|
||||||
foreach ($replacements as $name => $replacement) {
|
|
||||||
$text = str_replace('#' . $name, $replacement, $text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function convertMarkdown($text)
|
private function convertMarkdown($text)
|
||||||
|
@ -536,7 +519,7 @@ class Note extends Model
|
||||||
|
|
||||||
return $address;
|
return $address;
|
||||||
}
|
}
|
||||||
$adress = '<span class="p-country-name">' . $json->address->country . '</span>';
|
$address = '<span class="p-country-name">' . $json->address->country . '</span>';
|
||||||
Cache::forever($latlng, $address);
|
Cache::forever($latlng, $address);
|
||||||
|
|
||||||
return $address;
|
return $address;
|
||||||
|
|
|
@ -21,12 +21,10 @@ class NoteObserver
|
||||||
}
|
}
|
||||||
|
|
||||||
$tags->transform(function ($tag) {
|
$tags->transform(function ($tag) {
|
||||||
return Tag::firstOrCreate(['tag' => $tag]);
|
return Tag::firstOrCreate(['tag' => $tag])->id;
|
||||||
});
|
})->toArray();
|
||||||
|
|
||||||
$note->tags()->attach($tags->map(function ($tag) {
|
$note->tags()->attach($tags);
|
||||||
return $tag->id;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,9 +63,6 @@ class NoteObserver
|
||||||
public function getTagsFromNote($note)
|
public function getTagsFromNote($note)
|
||||||
{
|
{
|
||||||
preg_match_all('/#([^\s<>]+)\b/', $note, $tags);
|
preg_match_all('/#([^\s<>]+)\b/', $note, $tags);
|
||||||
if (array_get($tags, '1') === null) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return collect($tags[1])->map(function ($tag) {
|
return collect($tags[1])->map(function ($tag) {
|
||||||
return Tag::normalize($tag);
|
return Tag::normalize($tag);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Cviebrock\EloquentSluggable\Sluggable;
|
use Cviebrock\EloquentSluggable\Sluggable;
|
||||||
|
@ -79,15 +79,8 @@ class Place extends Model
|
||||||
|
|
||||||
public function scopeWhereExternalURL(Builder $query, string $url)
|
public function scopeWhereExternalURL(Builder $query, string $url)
|
||||||
{
|
{
|
||||||
$type = $this->getType($url);
|
|
||||||
if ($type === null) {
|
|
||||||
// we haven’t set a type, therefore result must be empty set
|
|
||||||
// id can’t be null, so this will return empty set
|
|
||||||
return $query->whereNull('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->where('external_urls', '@>', json_encode([
|
return $query->where('external_urls', '@>', json_encode([
|
||||||
$type => $url,
|
$this->getType($url) => $url,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,12 +124,19 @@ class Place extends Model
|
||||||
return config('app.shorturl') . '/places/' . $this->slug;
|
return config('app.shorturl') . '/places/' . $this->slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is an alternative for `longurl`.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUriAttribute()
|
||||||
|
{
|
||||||
|
return $this->longurl;
|
||||||
|
}
|
||||||
|
|
||||||
public function setExternalUrlsAttribute($url)
|
public function setExternalUrlsAttribute($url)
|
||||||
{
|
{
|
||||||
$type = $this->getType($url);
|
$type = $this->getType($url);
|
||||||
if ($type === null) {
|
|
||||||
throw new \Exception('Unkown external url type ' . $url);
|
|
||||||
}
|
|
||||||
$already = [];
|
$already = [];
|
||||||
if (array_key_exists('external_urls', $this->attributes)) {
|
if (array_key_exists('external_urls', $this->attributes)) {
|
||||||
$already = json_decode($this->attributes['external_urls'], true);
|
$already = json_decode($this->attributes['external_urls'], true);
|
||||||
|
@ -155,6 +155,6 @@ class Place extends Model
|
||||||
return 'osm';
|
return 'osm';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return 'default';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ namespace App\Providers;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Illuminate\Support\Facades\Broadcast;
|
use Illuminate\Support\Facades\Broadcast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
class BroadcastServiceProvider extends ServiceProvider
|
class BroadcastServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,9 @@ use Illuminate\Http\Request;
|
||||||
use Laravel\Horizon\Horizon;
|
use Laravel\Horizon\Horizon;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
class HorizonServiceProvider extends ServiceProvider
|
class HorizonServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,8 @@ use App\Jobs\ProcessBookmark;
|
||||||
use Spatie\Browsershot\Browsershot;
|
use Spatie\Browsershot\Browsershot;
|
||||||
use App\Jobs\SyndicateBookmarkToTwitter;
|
use App\Jobs\SyndicateBookmarkToTwitter;
|
||||||
use App\Jobs\SyndicateBookmarkToFacebook;
|
use App\Jobs\SyndicateBookmarkToFacebook;
|
||||||
use App\Exceptions\InternetArchiveErrorSavingException;
|
use GuzzleHttp\Exception\ClientException;
|
||||||
|
use App\Exceptions\InternetArchiveException;
|
||||||
|
|
||||||
class BookmarkService
|
class BookmarkService
|
||||||
{
|
{
|
||||||
|
@ -103,20 +104,20 @@ class BookmarkService
|
||||||
|
|
||||||
public function getArchiveLink(string $url): string
|
public function getArchiveLink(string $url): string
|
||||||
{
|
{
|
||||||
$client = new Client();
|
$client = resolve(Client::class);
|
||||||
|
try {
|
||||||
$response = $client->request('GET', 'https://web.archive.org/save/' . $url);
|
$response = $client->request('GET', 'https://web.archive.org/save/' . $url);
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
//throw an exception to be caught
|
||||||
|
throw new InternetArchiveException;
|
||||||
|
}
|
||||||
if ($response->hasHeader('Content-Location')) {
|
if ($response->hasHeader('Content-Location')) {
|
||||||
if (starts_with($response->getHeader('Content-Location')[0], '/web')) {
|
if (starts_with(array_get($response->getHeader('Content-Location'), 0), '/web')) {
|
||||||
return $response->getHeader('Content-Location')[0];
|
return $response->getHeader('Content-Location')[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (starts_with(array_get($response->getHeader('Content-Location'), 0), '/web')) {
|
|
||||||
return $response->getHeader('Content-Location')[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
//throw an exception to be caught
|
//throw an exception to be caught
|
||||||
throw new InternetArchiveErrorSavingException;
|
throw new InternetArchiveException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class LikeService
|
||||||
//micropub request
|
//micropub request
|
||||||
$url = normalize_url($request->input('properties.like-of.0'));
|
$url = normalize_url($request->input('properties.like-of.0'));
|
||||||
}
|
}
|
||||||
if (($request->header('Content-Type') == 'x-www-url-formencoded')
|
if (($request->header('Content-Type') == 'application/x-www-form-urlencoded')
|
||||||
||
|
||
|
||||||
($request->header('Content-Type') == 'multipart/form-data')
|
($request->header('Content-Type') == 'multipart/form-data')
|
||||||
) {
|
) {
|
||||||
|
|
34
app/Services/Micropub/HCardService.php
Normal file
34
app/Services/Micropub/HCardService.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Micropub;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\PlaceService;
|
||||||
|
|
||||||
|
class HCardService
|
||||||
|
{
|
||||||
|
public function process(Request $request)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
if ($request->header('Content-Type') == 'application/json') {
|
||||||
|
$data['name'] = $request->input('properties.name');
|
||||||
|
$data['description'] = $request->input('properties.description') ?? null;
|
||||||
|
if ($request->has('properties.geo')) {
|
||||||
|
$data['geo'] = $request->input('properties.geo');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['name'] = $request->input('name');
|
||||||
|
$data['description'] = $request->input('description');
|
||||||
|
if ($request->has('geo')) {
|
||||||
|
$data['geo'] = $request->input('geo');
|
||||||
|
}
|
||||||
|
if ($request->has('latitude')) {
|
||||||
|
$data['latitude'] = $request->input('latitude');
|
||||||
|
$data['longitude'] = $request->input('longitude');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$place = resolve(PlaceService::class)->createPlace($data);
|
||||||
|
|
||||||
|
return $place->longurl;
|
||||||
|
}
|
||||||
|
}
|
28
app/Services/Micropub/HEntryService.php
Normal file
28
app/Services/Micropub/HEntryService.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Micropub;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\{BookmarkService, LikeService, NoteService};
|
||||||
|
|
||||||
|
class HEntryService
|
||||||
|
{
|
||||||
|
public function process(Request $request)
|
||||||
|
{
|
||||||
|
if ($request->has('properties.like-of') || $request->has('like-of')) {
|
||||||
|
$like = resolve(LikeService::class)->createLike($request);
|
||||||
|
|
||||||
|
return $like->longurl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('properties.bookmark-of') || $request->has('bookmark-of')) {
|
||||||
|
$bookmark = resolve(BookmarkService::class)->createBookmark($request);
|
||||||
|
|
||||||
|
return $bookmark->longurl;
|
||||||
|
}
|
||||||
|
|
||||||
|
$note = resolve(NoteService::class)->createNote($request);
|
||||||
|
|
||||||
|
return $note->longurl;
|
||||||
|
}
|
||||||
|
}
|
95
app/Services/Micropub/UpdateService.php
Normal file
95
app/Services/Micropub/UpdateService.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Micropub;
|
||||||
|
|
||||||
|
use App\Note;
|
||||||
|
use App\Media;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
|
||||||
|
class UpdateService
|
||||||
|
{
|
||||||
|
public function process(Request $request)
|
||||||
|
{
|
||||||
|
$urlPath = parse_url($request->input('url'), PHP_URL_PATH);
|
||||||
|
|
||||||
|
//is it a note we are updating?
|
||||||
|
if (mb_substr($urlPath, 1, 5) !== 'notes') {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'invalid',
|
||||||
|
'error_description' => 'This implementation currently only support the updating of notes',
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$note = Note::nb60(basename($urlPath))->firstOrFail();
|
||||||
|
} catch (ModelNotFoundException $exception) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'invalid_request',
|
||||||
|
'error_description' => 'No known note with given ID',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
//got the note, are we dealing with a “replace” request?
|
||||||
|
if ($request->has('replace')) {
|
||||||
|
foreach ($request->input('replace') as $property => $value) {
|
||||||
|
if ($property == 'content') {
|
||||||
|
$note->note = $value[0];
|
||||||
|
}
|
||||||
|
if ($property == 'syndication') {
|
||||||
|
foreach ($value as $syndicationURL) {
|
||||||
|
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
||||||
|
$note->facebook_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
||||||
|
$note->swarm_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
||||||
|
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$note->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'updated',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//how about “add”
|
||||||
|
if ($request->has('add')) {
|
||||||
|
foreach ($request->input('add') as $property => $value) {
|
||||||
|
if ($property == 'syndication') {
|
||||||
|
foreach ($value as $syndicationURL) {
|
||||||
|
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
||||||
|
$note->facebook_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
||||||
|
$note->swarm_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
||||||
|
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($property == 'photo') {
|
||||||
|
foreach ($value as $photoURL) {
|
||||||
|
if (start_with($photo, 'https://')) {
|
||||||
|
$media = new Media();
|
||||||
|
$media->path = $photoURL;
|
||||||
|
$media->type = 'image';
|
||||||
|
$media->save();
|
||||||
|
$note->media()->save($media);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$note->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'updated',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use App\{Media, Note, Place};
|
use App\{Media, Note, Place};
|
||||||
use App\Jobs\{SendWebMentions, SyndicateNoteToFacebook, SyndicateNoteToTwitter};
|
use App\Jobs\{SendWebMentions, SyndicateNoteToFacebook, SyndicateNoteToTwitter};
|
||||||
|
|
||||||
|
@ -12,12 +13,111 @@ class NoteService
|
||||||
/**
|
/**
|
||||||
* Create a new note.
|
* Create a new note.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \App\Note $note
|
* @return \App\Note $note
|
||||||
*/
|
*/
|
||||||
public function createNote(array $data): Note
|
public function createNote(Request $request): Note
|
||||||
{
|
{
|
||||||
|
//move the request to data code here before refactor
|
||||||
|
$data = [];
|
||||||
|
$data['client-id'] = resolve(TokenService::class)
|
||||||
|
->validateToken($request->bearerToken())
|
||||||
|
->getClaim('client_id');
|
||||||
|
if ($request->header('Content-Type') == 'application/json') {
|
||||||
|
if (is_string($request->input('properties.content.0'))) {
|
||||||
|
$data['content'] = $request->input('properties.content.0'); //plaintext content
|
||||||
|
}
|
||||||
|
if (is_array($request->input('properties.content.0'))
|
||||||
|
&& array_key_exists('html', $request->input('properties.content.0'))
|
||||||
|
) {
|
||||||
|
$data['content'] = $request->input('properties.content.0.html');
|
||||||
|
}
|
||||||
|
$data['in-reply-to'] = $request->input('properties.in-reply-to.0');
|
||||||
|
// check location is geo: string
|
||||||
|
if (is_string($request->input('properties.location.0'))) {
|
||||||
|
$data['location'] = $request->input('properties.location.0');
|
||||||
|
}
|
||||||
|
// check location is h-card
|
||||||
|
if (is_array($request->input('properties.location.0'))) {
|
||||||
|
if ($request->input('properties.location.0.type.0' === 'h-card')) {
|
||||||
|
try {
|
||||||
|
$place = resolve(PlaceService::class)->createPlaceFromCheckin(
|
||||||
|
$request->input('properties.location.0')
|
||||||
|
);
|
||||||
|
$data['checkin'] = $place->longurl;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['published'] = $request->input('properties.published.0');
|
||||||
|
//create checkin place
|
||||||
|
if (array_key_exists('checkin', $request->input('properties'))) {
|
||||||
|
$data['swarm-url'] = $request->input('properties.syndication.0');
|
||||||
|
try {
|
||||||
|
$place = resolve(PlaceService::class)->createPlaceFromCheckin(
|
||||||
|
$request->input('properties.checkin.0')
|
||||||
|
);
|
||||||
|
$data['checkin'] = $place->longurl;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$data['checkin'] = null;
|
||||||
|
$data['swarm-url'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['content'] = $request->input('content');
|
||||||
|
$data['in-reply-to'] = $request->input('in-reply-to');
|
||||||
|
$data['location'] = $request->input('location');
|
||||||
|
$data['published'] = $request->input('published');
|
||||||
|
}
|
||||||
|
$data['syndicate'] = [];
|
||||||
|
$targets = array_pluck(config('syndication.targets'), 'uid', 'service.name');
|
||||||
|
$mpSyndicateTo = null;
|
||||||
|
if ($request->has('mp-syndicate-to')) {
|
||||||
|
$mpSyndicateTo = $request->input('mp-syndicate-to');
|
||||||
|
}
|
||||||
|
if ($request->has('properties.mp-syndicate-to')) {
|
||||||
|
$mpSyndicateTo = $request->input('properties.mp-syndicate-to');
|
||||||
|
}
|
||||||
|
if (is_string($mpSyndicateTo)) {
|
||||||
|
$service = array_search($mpSyndicateTo, $targets);
|
||||||
|
if ($service == 'Twitter') {
|
||||||
|
$data['syndicate'][] = 'twitter';
|
||||||
|
}
|
||||||
|
if ($service == 'Facebook') {
|
||||||
|
$data['syndicate'][] = 'facebook';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_array($mpSyndicateTo)) {
|
||||||
|
foreach ($mpSyndicateTo as $uid) {
|
||||||
|
$service = array_search($uid, $targets);
|
||||||
|
if ($service == 'Twitter') {
|
||||||
|
$data['syndicate'][] = 'twitter';
|
||||||
|
}
|
||||||
|
if ($service == 'Facebook') {
|
||||||
|
$data['syndicate'][] = 'facebook';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['photo'] = [];
|
||||||
|
$photos = null;
|
||||||
|
if ($request->has('photo')) {
|
||||||
|
$photos = $request->input('photo');
|
||||||
|
}
|
||||||
|
if ($request->has('properties.photo')) {
|
||||||
|
$photos = $request->input('properties.photo');
|
||||||
|
}
|
||||||
|
if ($photos !== null) {
|
||||||
|
foreach ($photos as $photo) {
|
||||||
|
if (is_string($photo)) {
|
||||||
|
//only supporting media URLs for now
|
||||||
|
$data['photo'][] = $photo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (starts_with($request->input('properties.syndication.0'), 'https://www.instagram.com')) {
|
||||||
|
$data['instagram-url'] = $request->input('properties.syndication.0');
|
||||||
|
}
|
||||||
|
}
|
||||||
//check the input
|
//check the input
|
||||||
if (array_key_exists('content', $data) === false) {
|
if (array_key_exists('content', $data) === false) {
|
||||||
$data['content'] = null;
|
$data['content'] = null;
|
||||||
|
@ -37,8 +137,8 @@ class NoteService
|
||||||
);
|
);
|
||||||
|
|
||||||
if (array_key_exists('published', $data) && empty($data['published']) === false) {
|
if (array_key_exists('published', $data) && empty($data['published']) === false) {
|
||||||
$carbon = carbon($data['published']);
|
$note->created_at = $note->updated_at = carbon($data['published'])
|
||||||
$note->created_at = $note->updated_at = $carbon->toDateTimeString();
|
->toDateTimeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('location', $data) && $data['location'] !== null && $data['location'] !== 'no-location') {
|
if (array_key_exists('location', $data) && $data['location'] !== null && $data['location'] !== 'no-location') {
|
||||||
|
@ -81,7 +181,7 @@ class NoteService
|
||||||
*/
|
*/
|
||||||
//add support for media uploaded as URLs
|
//add support for media uploaded as URLs
|
||||||
if (array_key_exists('photo', $data)) {
|
if (array_key_exists('photo', $data)) {
|
||||||
foreach ($data['photo'] as $photo) {
|
foreach ((array) $data['photo'] as $photo) {
|
||||||
// check the media was uploaded to my endpoint, and use path
|
// check the media was uploaded to my endpoint, and use path
|
||||||
if (starts_with($photo, config('filesystems.disks.s3.url'))) {
|
if (starts_with($photo, config('filesystems.disks.s3.url'))) {
|
||||||
$path = substr($photo, strlen(config('filesystems.disks.s3.url')));
|
$path = substr($photo, strlen(config('filesystems.disks.s3.url')));
|
||||||
|
@ -104,11 +204,13 @@ class NoteService
|
||||||
dispatch(new SendWebMentions($note));
|
dispatch(new SendWebMentions($note));
|
||||||
|
|
||||||
//syndication targets
|
//syndication targets
|
||||||
if (in_array('twitter', $data['syndicate'])) {
|
if (array_key_exists('syndicate', $data)) {
|
||||||
dispatch(new SyndicateNoteToTwitter($note));
|
if (in_array('twitter', $data['syndicate'])) {
|
||||||
}
|
dispatch(new SyndicateNoteToTwitter($note));
|
||||||
if (in_array('facebook', $data['syndicate'])) {
|
}
|
||||||
dispatch(new SyndicateNoteToFacebook($note));
|
if (in_array('facebook', $data['syndicate'])) {
|
||||||
|
dispatch(new SyndicateNoteToFacebook($note));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $note;
|
return $note;
|
||||||
|
|
|
@ -46,16 +46,16 @@ class PlaceService
|
||||||
public function createPlaceFromCheckin(array $checkin): Place
|
public function createPlaceFromCheckin(array $checkin): Place
|
||||||
{
|
{
|
||||||
//check if the place exists if from swarm
|
//check if the place exists if from swarm
|
||||||
if (array_key_exists('url', $checkin['properties'])) {
|
if (array_has($checkin, 'properties.url')) {
|
||||||
$place = Place::whereExternalURL($checkin['properties']['url'][0])->get();
|
$place = Place::whereExternalURL($checkin['properties']['url'][0])->get();
|
||||||
if (count($place) === 1) {
|
if (count($place) === 1) {
|
||||||
return $place->first();
|
return $place->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (array_key_exists('name', $checkin['properties']) === false) {
|
if (array_has($checkin, 'properties.name') === false) {
|
||||||
throw new \InvalidArgumentException('Missing required name');
|
throw new \InvalidArgumentException('Missing required name');
|
||||||
}
|
}
|
||||||
if (array_key_exists('latitude', $checkin['properties']) === false) {
|
if (array_has($checkin, 'properties.latitude') === false) {
|
||||||
throw new \InvalidArgumentException('Missing required longitude/latitude');
|
throw new \InvalidArgumentException('Missing required longitude/latitude');
|
||||||
}
|
}
|
||||||
$place = new Place();
|
$place = new Place();
|
||||||
|
|
|
@ -38,7 +38,7 @@ class TokenService
|
||||||
* @param string The token
|
* @param string The token
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function validateToken(string $bearerToken): ?Token
|
public function validateToken(string $bearerToken): Token
|
||||||
{
|
{
|
||||||
$signer = new Sha256();
|
$signer = new Sha256();
|
||||||
try {
|
try {
|
||||||
|
@ -47,7 +47,7 @@ class TokenService
|
||||||
throw new InvalidTokenException('Token could not be parsed');
|
throw new InvalidTokenException('Token could not be parsed');
|
||||||
}
|
}
|
||||||
if (! $token->verify($signer, config('app.key'))) {
|
if (! $token->verify($signer, config('app.key'))) {
|
||||||
throw new InvalidTokenException('Token failed verification');
|
throw new InvalidTokenException('Token failed validation');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
|
|
14
app/Tag.php
14
app/Tag.php
|
@ -6,6 +6,13 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Tag extends Model
|
class Tag extends Model
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* We shall set a blacklist of non-modifiable model attributes.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the relationship with tags.
|
* Define the relationship with tags.
|
||||||
*
|
*
|
||||||
|
@ -24,13 +31,6 @@ class Tag extends Model
|
||||||
return $this->belongsToMany('App\Bookmark');
|
return $this->belongsToMany('App\Bookmark');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We shall set a blacklist of non-modifiable model attributes.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $guarded = ['id'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize tags so they’re lowercase and fancy diatrics are removed.
|
* Normalize tags so they’re lowercase and fancy diatrics are removed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,6 +19,13 @@ class WebMention extends Model
|
||||||
*/
|
*/
|
||||||
protected $table = 'webmentions';
|
protected $table = 'webmentions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We shall set a blacklist of non-modifiable model attributes.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the relationship.
|
* Define the relationship.
|
||||||
*
|
*
|
||||||
|
@ -29,13 +36,6 @@ class WebMention extends Model
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We shall set a blacklist of non-modifiable model attributes.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $guarded = ['id'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the author of the webmention.
|
* Get the author of the webmention.
|
||||||
*
|
*
|
||||||
|
@ -78,9 +78,9 @@ class WebMention extends Model
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the filteres HTML of a reply.
|
* Get the filtered HTML of a reply.
|
||||||
*
|
*
|
||||||
* @return strin|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getReplyAttribute()
|
public function getReplyAttribute()
|
||||||
{
|
{
|
||||||
|
@ -108,14 +108,10 @@ class WebMention extends Model
|
||||||
if (Cache::has($url)) {
|
if (Cache::has($url)) {
|
||||||
return Cache::get($url);
|
return Cache::get($url);
|
||||||
}
|
}
|
||||||
$username = parse_url($url, PHP_URL_PATH);
|
$username = ltrim(parse_url($url, PHP_URL_PATH), '/');
|
||||||
try {
|
$info = Twitter::getUsers(['screen_name' => $username]);
|
||||||
$info = Twitter::getUsers(['screen_name' => $username]);
|
$profile_image = $info->profile_image_url_https;
|
||||||
$profile_image = $info->profile_image_url_https;
|
Cache::put($url, $profile_image, 10080); //1 week
|
||||||
Cache::put($url, $profile_image, 10080); //1 week
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return $url; //not sure here
|
|
||||||
}
|
|
||||||
|
|
||||||
return $profile_image;
|
return $profile_image;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"laravel/dusk": "^2.0",
|
"laravel/dusk": "^2.0",
|
||||||
"mockery/mockery": "0.9.*",
|
"mockery/mockery": "0.9.*",
|
||||||
"nunomaduro/collision": "^1.1",
|
"nunomaduro/collision": "^1.1",
|
||||||
|
"php-coveralls/php-coveralls": "^1.0",
|
||||||
"phpunit/phpunit": "~6.0",
|
"phpunit/phpunit": "~6.0",
|
||||||
"sebastian/phpcpd": "^3.0"
|
"sebastian/phpcpd": "^3.0"
|
||||||
},
|
},
|
||||||
|
|
316
composer.lock
generated
316
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "f669c85a04a86625c32349be0ef1fc16",
|
"content-hash": "5b3735b76d6821f7de296da60f7cceca",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
|
@ -5019,6 +5019,99 @@
|
||||||
],
|
],
|
||||||
"time": "2017-08-15T16:48:10+00:00"
|
"time": "2017-08-15T16:48:10+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "guzzle/guzzle",
|
||||||
|
"version": "v3.8.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
|
"reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
|
||||||
|
"reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"php": ">=5.3.3",
|
||||||
|
"symfony/event-dispatcher": ">=2.1"
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"guzzle/batch": "self.version",
|
||||||
|
"guzzle/cache": "self.version",
|
||||||
|
"guzzle/common": "self.version",
|
||||||
|
"guzzle/http": "self.version",
|
||||||
|
"guzzle/inflection": "self.version",
|
||||||
|
"guzzle/iterator": "self.version",
|
||||||
|
"guzzle/log": "self.version",
|
||||||
|
"guzzle/parser": "self.version",
|
||||||
|
"guzzle/plugin": "self.version",
|
||||||
|
"guzzle/plugin-async": "self.version",
|
||||||
|
"guzzle/plugin-backoff": "self.version",
|
||||||
|
"guzzle/plugin-cache": "self.version",
|
||||||
|
"guzzle/plugin-cookie": "self.version",
|
||||||
|
"guzzle/plugin-curlauth": "self.version",
|
||||||
|
"guzzle/plugin-error-response": "self.version",
|
||||||
|
"guzzle/plugin-history": "self.version",
|
||||||
|
"guzzle/plugin-log": "self.version",
|
||||||
|
"guzzle/plugin-md5": "self.version",
|
||||||
|
"guzzle/plugin-mock": "self.version",
|
||||||
|
"guzzle/plugin-oauth": "self.version",
|
||||||
|
"guzzle/service": "self.version",
|
||||||
|
"guzzle/stream": "self.version"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/cache": "*",
|
||||||
|
"monolog/monolog": "1.*",
|
||||||
|
"phpunit/phpunit": "3.7.*",
|
||||||
|
"psr/log": "1.0.*",
|
||||||
|
"symfony/class-loader": "*",
|
||||||
|
"zendframework/zend-cache": "<2.3",
|
||||||
|
"zendframework/zend-log": "<2.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.8-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Guzzle": "src/",
|
||||||
|
"Guzzle\\Tests": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guzzle Community",
|
||||||
|
"homepage": "https://github.com/guzzle/guzzle/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
|
||||||
|
"homepage": "http://guzzlephp.org/",
|
||||||
|
"keywords": [
|
||||||
|
"client",
|
||||||
|
"curl",
|
||||||
|
"framework",
|
||||||
|
"http",
|
||||||
|
"http client",
|
||||||
|
"rest",
|
||||||
|
"web service"
|
||||||
|
],
|
||||||
|
"abandoned": "guzzlehttp/guzzle",
|
||||||
|
"time": "2014-01-28T22:29:15+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "hamcrest/hamcrest-php",
|
"name": "hamcrest/hamcrest-php",
|
||||||
"version": "v1.2.2",
|
"version": "v1.2.2",
|
||||||
|
@ -5502,6 +5595,67 @@
|
||||||
"description": "Library for handling version information and constraints",
|
"description": "Library for handling version information and constraints",
|
||||||
"time": "2017-03-05T17:38:23+00:00"
|
"time": "2017-03-05T17:38:23+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "php-coveralls/php-coveralls",
|
||||||
|
"version": "v1.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-coveralls/php-coveralls.git",
|
||||||
|
"reference": "9c07b63acbc9709344948b6fd4f63a32b2ef4127"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/9c07b63acbc9709344948b6fd4f63a32b2ef4127",
|
||||||
|
"reference": "9c07b63acbc9709344948b6fd4f63a32b2ef4127",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"guzzle/guzzle": "^2.8 || ^3.0",
|
||||||
|
"php": "^5.3.3 || ^7.0",
|
||||||
|
"psr/log": "^1.0",
|
||||||
|
"symfony/config": "^2.1 || ^3.0 || ^4.0",
|
||||||
|
"symfony/console": "^2.1 || ^3.0 || ^4.0",
|
||||||
|
"symfony/stopwatch": "^2.0 || ^3.0 || ^4.0",
|
||||||
|
"symfony/yaml": "^2.0 || ^3.0 || ^4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/http-kernel": "Allows Symfony integration"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/coveralls"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Satooshi\\": "src/Satooshi/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Kitamura Satoshi",
|
||||||
|
"email": "with.no.parachute@gmail.com",
|
||||||
|
"homepage": "https://www.facebook.com/satooshi.jp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP client library for Coveralls API",
|
||||||
|
"homepage": "https://github.com/php-coveralls/php-coveralls",
|
||||||
|
"keywords": [
|
||||||
|
"ci",
|
||||||
|
"coverage",
|
||||||
|
"github",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"time": "2017-10-14T23:15:34+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -6752,6 +6906,166 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/version",
|
"homepage": "https://github.com/sebastianbergmann/version",
|
||||||
"time": "2016-10-03T07:35:21+00:00"
|
"time": "2016-10-03T07:35:21+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/config",
|
||||||
|
"version": "v3.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/config.git",
|
||||||
|
"reference": "1de51a6c76359897ab32c309934b93d036bccb60"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/config/zipball/1de51a6c76359897ab32c309934b93d036bccb60",
|
||||||
|
"reference": "1de51a6c76359897ab32c309934b93d036bccb60",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.5.9|>=7.0.8",
|
||||||
|
"symfony/filesystem": "~2.8|~3.0|~4.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/dependency-injection": "<3.3",
|
||||||
|
"symfony/finder": "<3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/dependency-injection": "~3.3|~4.0",
|
||||||
|
"symfony/finder": "~3.3|~4.0",
|
||||||
|
"symfony/yaml": "~3.0|~4.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/yaml": "To use the yaml reference dumper"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.4-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Config\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Config Component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"time": "2017-11-19T20:09:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/filesystem",
|
||||||
|
"version": "v4.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/filesystem.git",
|
||||||
|
"reference": "c9d4a26759ff75a077e4e334315cb632739b661a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/filesystem/zipball/c9d4a26759ff75a077e4e334315cb632739b661a",
|
||||||
|
"reference": "c9d4a26759ff75a077e4e334315cb632739b661a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Filesystem\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Filesystem Component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"time": "2017-11-21T14:14:53+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/stopwatch",
|
||||||
|
"version": "v4.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/stopwatch.git",
|
||||||
|
"reference": "ac0e49150555c703fef6b696d8eaba1db7a3ca03"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/ac0e49150555c703fef6b696d8eaba1db7a3ca03",
|
||||||
|
"reference": "ac0e49150555c703fef6b696d8eaba1db7a3ca03",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Stopwatch\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Stopwatch Component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"time": "2017-11-09T12:45:29+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v3.3.13",
|
"version": "v3.3.13",
|
||||||
|
|
|
@ -22,7 +22,6 @@ class ContactsTableSeeder extends Seeder
|
||||||
'nick' => 'aaron',
|
'nick' => 'aaron',
|
||||||
'name' => 'Aaron Parecki',
|
'name' => 'Aaron Parecki',
|
||||||
'homepage' => 'https://aaronparecki.com',
|
'homepage' => 'https://aaronparecki.com',
|
||||||
'twitter' => 'aaronpk',
|
|
||||||
'facebook' => '123456',
|
'facebook' => '123456',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,15 @@ class LikesTableSeeder extends Seeder
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
factory(App\Like::class, 10)->create();
|
factory(App\Like::class, 10)->create();
|
||||||
|
|
||||||
|
$faker = new \Faker\Generator();
|
||||||
|
$faker->addProvider(new \Faker\Provider\en_US\Person($faker));
|
||||||
|
$faker->addProvider(new \Faker\Provider\Lorem($faker));
|
||||||
|
$faker->addProvider(new \Faker\Provider\Internet($faker));
|
||||||
|
App\Like::create([
|
||||||
|
'url' => $faker->url,
|
||||||
|
'author_url' => $faker->url,
|
||||||
|
'author_name' => $faker->name,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ class NotesTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
factory(App\Note::class, 10)->create();
|
factory(App\Note::class, 10)->create();
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
$noteTwitterReply = App\Note::create([
|
||||||
|
'note' => 'What does this even mean?',
|
||||||
|
'in_reply_to' => 'https://twitter.com/realDonaldTrump/status/933662564587855877',
|
||||||
|
]);
|
||||||
|
sleep(1);
|
||||||
$noteWithPlace = App\Note::create([
|
$noteWithPlace = App\Note::create([
|
||||||
'note' => 'Having a #beer at the local. 🍺',
|
'note' => 'Having a #beer at the local. 🍺',
|
||||||
]);
|
]);
|
||||||
|
@ -42,11 +47,29 @@ class NotesTableSeeder extends Seeder
|
||||||
copy(base_path() . '/tests/aaron.png', public_path() . '/assets/profile-images/aaronparecki.com/image');
|
copy(base_path() . '/tests/aaron.png', public_path() . '/assets/profile-images/aaronparecki.com/image');
|
||||||
}
|
}
|
||||||
$noteWithCoords = App\Note::create([
|
$noteWithCoords = App\Note::create([
|
||||||
'note' => 'Note from somehwere',
|
'note' => 'Note from a town',
|
||||||
]);
|
]);
|
||||||
$noteWithCoords->location = '53.499,-2.379';
|
$noteWithCoords->location = '53.499,-2.379';
|
||||||
$noteWithCoords->save();
|
$noteWithCoords->save();
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
$noteWithCoords2 = App\Note::create([
|
||||||
|
'note' => 'Note from a city',
|
||||||
|
]);
|
||||||
|
$noteWithCoords2->location = '53.9026894,-2.42250444118781';
|
||||||
|
$noteWithCoords2->save();
|
||||||
|
sleep(1);
|
||||||
|
$noteWithCoords3 = App\Note::create([
|
||||||
|
'note' => 'Note from a county',
|
||||||
|
]);
|
||||||
|
$noteWithCoords3->location = '57.5066357,-5.0038367';
|
||||||
|
$noteWithCoords3->save();
|
||||||
|
sleep(1);
|
||||||
|
$noteWithCoords4 = App\Note::create([
|
||||||
|
'note' => 'Note from a country',
|
||||||
|
]);
|
||||||
|
$noteWithCoords4->location = '63.000147,-136.002502';
|
||||||
|
$noteWithCoords4->save();
|
||||||
|
sleep(1);
|
||||||
$noteSyndicated = App\Note::create([
|
$noteSyndicated = App\Note::create([
|
||||||
'note' => 'This note has all the syndication targets',
|
'note' => 'This note has all the syndication targets',
|
||||||
]);
|
]);
|
||||||
|
@ -59,5 +82,26 @@ class NotesTableSeeder extends Seeder
|
||||||
$noteWithTextLinkandEmoji = App\Note::create([
|
$noteWithTextLinkandEmoji = App\Note::create([
|
||||||
'note' => 'I love https://duckduckgo.com 💕' // theres a two-heart emoji at the end of this
|
'note' => 'I love https://duckduckgo.com 💕' // theres a two-heart emoji at the end of this
|
||||||
]);
|
]);
|
||||||
|
sleep(1);
|
||||||
|
$media = new App\Media();
|
||||||
|
$media->path = 'media/f1bc8faa-1a8f-45b8-a9b1-57282fa73f87.jpg';
|
||||||
|
$media->type = 'image';
|
||||||
|
$media->image_widths = '3648';
|
||||||
|
$media->save();
|
||||||
|
$noteWithImage = App\Note::create([
|
||||||
|
'note' => 'A lovely waterfall',
|
||||||
|
]);
|
||||||
|
$noteWithImage->media()->save($media);
|
||||||
|
sleep(1);
|
||||||
|
$noteFromInstagram = App\Note::create([
|
||||||
|
'note' => 'Lovely #wedding #weddingfavour',
|
||||||
|
]);
|
||||||
|
$noteFromInstagram->instagram_url = 'https://www.instagram.com/p/Bbo22MHhE_0';
|
||||||
|
$noteFromInstagram->save();
|
||||||
|
$mediaInstagram = new App\Media();
|
||||||
|
$mediaInstagram->path = 'https://scontent-lhr3-1.cdninstagram.com/t51.2885-15/e35/23734479_149605352435937_400133507076063232_n.jpg';
|
||||||
|
$mediaInstagram->type = 'image';
|
||||||
|
$mediaInstagram->save();
|
||||||
|
$noteFromInstagram->media()->save($mediaInstagram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,21 @@ class WebMentionsTableSeeder extends Seeder
|
||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$webmention = WebMention::create([
|
$webmentionAaron = WebMention::create([
|
||||||
'source' => 'https://aaornpk.localhost/reply/1',
|
'source' => 'https://aaronpk.localhost/reply/1',
|
||||||
'target' => 'https://jonnybarnes.localhost/notes/D',
|
'target' => config('app.url') . '/notes/E',
|
||||||
|
'commentable_id' => '14',
|
||||||
|
'commentable_type' => 'App\Note',
|
||||||
|
'type' => 'in-reply-to',
|
||||||
|
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"url": ["https://aaronpk.localhost/reply/1"], "name": ["Hi too"], "author": [{"type": ["h-card"], "value": "Aaron Parecki", "properties": {"url": ["https://aaronpk.localhost"], "name": ["Aaron Parecki"], "photo": ["https://aaronparecki.com/images/profile.jpg"]}}], "content": [{"html": "Hi too", "value": "Hi too"}], "published": ["' . date(DATE_W3C) . '"], "in-reply-to": ["https://aaronpk.loclahost/reply/1", "' . config('app.url') .'/notes/E"]}}]}'
|
||||||
|
]);
|
||||||
|
$webmentionTantek = WebMention::create([
|
||||||
|
'source' => 'http://tantek.com/',
|
||||||
|
'target' => config('app.url') . '/notes/D',
|
||||||
'commentable_id' => '13',
|
'commentable_id' => '13',
|
||||||
'commentable_type' => 'App\Note',
|
'commentable_type' => 'App\Note',
|
||||||
'type' => 'in-reply-to',
|
'type' => 'in-reply-to',
|
||||||
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"url": ["https://aaronpk.localhost/reply/1"], "name": ["Hi too"], "author": [{"type": ["h-card"], "value": "Aaron Parecki", "properties": {"url": ["https://aaronpk.localhost"], "name": ["Aaron Parecki"], "photo": ["https://aaronparecki.com/images/profile.jpg"]}}], "content": [{"html": "Hi too", "value": "Hi too"}], "published": ["' . date(DATE_W3C) . '"], "in-reply-to": ["https://aaronpk.loclahost/reply/1", "https://jonnybarnes.uk/notes/D"]}}]}'
|
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"url": ["http://tantek.com/"], "name": ["KUTGW"], "author": [{"type": ["h-card"], "value": "Tantek Celik", "properties": {"url": ["http://tantek.com/"], "name": ["Tantek Celik"]}}], "content": [{"html": "kutgw", "value": "kutgw"}], "published": ["' . date(DATE_W3C) . '"], "in-reply-to": ["' . config('app.url') . '/notes/D"]}}]}'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"RbrS": "https://jonnybarnes.net/note/1",
|
|
||||||
"pfua": "https://jonnybarnes.net/note/2",
|
|
||||||
"HQ8X": "https://jonnybarnes.net/note/3",
|
|
||||||
"7Duc": "https://jonnybarnes.net/note/4",
|
|
||||||
"m0vZ": "https://jonnybarnes.net/note/5",
|
|
||||||
"uB95": "https://jonnybarnes.net/note/6",
|
|
||||||
"yUx8": "https://jonnybarnes.net/note/7",
|
|
||||||
"tMLB": "https://jonnybarnes.net/note/8",
|
|
||||||
"a1HU": "https://jonnybarnes.net/note/9",
|
|
||||||
"rx3e": "https://jonnybarnes.net/note/10",
|
|
||||||
"dW3p": "https://jonnybarnes.net/note/11",
|
|
||||||
"_6za": "https://jonnybarnes.net/note/12",
|
|
||||||
"eTvB": "https://jonnybarnes.net/note/13",
|
|
||||||
"6kMh": "https://jonnybarnes.net/note/14",
|
|
||||||
"T72f": "https://jonnybarnes.net/note/15",
|
|
||||||
"enot": "https://jonnybarnes.net/note/16",
|
|
||||||
"QCDv": "https://jonnybarnes.net/note/17"
|
|
||||||
}
|
|
|
@ -12,12 +12,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@include('templates.new-note-form', [
|
<form action="/admin/notes" method="post" accept-charset="utf-8">
|
||||||
'micropub' => false,
|
|
||||||
'action' => '/admin/note',
|
|
||||||
'id' => 'newnote-admin'
|
|
||||||
])
|
|
||||||
<form action="{{ $action }}" method="post" enctype="multipart/form-data" accept-charset="utf-8"@if($micropub) name="micropub"@endif>
|
|
||||||
{{ csrf_field() }}
|
{{ csrf_field() }}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>New Note</legend>
|
<legend>New Note</legend>
|
||||||
|
@ -27,7 +22,6 @@
|
||||||
name="in-reply-to"
|
name="in-reply-to"
|
||||||
id="in-reply-to"
|
id="in-reply-to"
|
||||||
placeholder="in-reply-to-1 in-reply-to-2 …"
|
placeholder="in-reply-to-1 in-reply-to-2 …"
|
||||||
value="{{ old('in-reply-to') }}"
|
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -40,23 +34,7 @@
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="photo" accesskey="p">Photo: </label>
|
|
||||||
<input type="file"
|
|
||||||
accept="image/*"
|
|
||||||
value="Upload"
|
|
||||||
name="photo[]"
|
|
||||||
id="photo"
|
|
||||||
multiple
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label for="locate" accesskey="l"></label>
|
|
||||||
<button type="button"
|
|
||||||
name="locate"
|
|
||||||
id="locate"
|
|
||||||
value="Locate"
|
|
||||||
disabled
|
|
||||||
>Locate</button>
|
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
name="submit"
|
name="submit"
|
||||||
id="submit"
|
id="submit"
|
||||||
|
@ -66,11 +44,3 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('scripts')
|
|
||||||
@include('templates.mapbox-links')
|
|
||||||
|
|
||||||
<script src="/assets/js/newnote.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/assets/frontend/alertify.css">
|
|
||||||
@stop
|
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
{{ method_field('DELETE') }}
|
{{ method_field('DELETE') }}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Delete Note</legend>
|
<legend>Delete Note</legend>
|
||||||
<label for"delete" accesskey="d">Delete: </label><input type="checkbox" name="delete" id="delete" checked="checked">
|
<label for="kludge"></label><input type="submit" value="Delete" id="kludge">
|
||||||
<label for="kludge"></label><input type="submit" value="Submit" id="kludge">
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
@ -4,121 +4,121 @@
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<h1>Edit Place</h1>
|
<h1>Edit Place</h1>
|
||||||
<form action="/admin/places/{{ $id }}" method="post" accept-charset="utf-8">
|
<form action="/admin/places/{{ $place->id }}" method="post" accept-charset="utf-8">
|
||||||
{{ csrf_field() }}
|
{{ csrf_field() }}
|
||||||
{{ method_field('PUT') }}
|
{{ method_field('PUT') }}
|
||||||
<p>Name</p>
|
<p>Name</p>
|
||||||
<input type="text" name="name" id="name" value="{{ $name }}"><br>
|
<input type="text" name="name" id="name" value="{{ $place->name }}"><br>
|
||||||
<p>Description</p>
|
<p>Description</p>
|
||||||
<textarea name="description" id="description">{{ $description }}</textarea><br>
|
<textarea name="description" id="description">{{ $place->description }}</textarea><br>
|
||||||
<p>Location</p>
|
<p>Location</p>
|
||||||
<div class="map" data-latitude="{{ $latitude }}" data-longitude="{{ $longitude }}" data-id="{{ $id }}"></div>
|
<div class="map" data-latitude="{{ $place->latitude }}" data-longitude="{{ $place->longitude }}" data-id="{{ $place->id }}"></div>
|
||||||
<script>
|
<script>
|
||||||
var geojson{{ $id }} = {
|
var geojson{{ $place->id }} = {
|
||||||
"type": "FeatureCollection",
|
"type": "FeatureCollection",
|
||||||
"features": [{
|
"features": [{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Point",
|
"type": "Point",
|
||||||
"coordinates": [{{ $longitude }}, {{ $latitude }}]
|
"coordinates": [{{ $place->longitude }}, {{ $place->latitude }}]
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"title": "{{ $name }}",
|
"title": "{{ $place->name }}",
|
||||||
"icon": "{{ $icon }}"
|
"icon": "{{ $place->icon ?? 'marker' }}"
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<input type="text" name="latitude" id="latitude" value="{{ $latitude }}"><br>
|
<input type="text" name="latitude" id="latitude" value="{{ $place->latitude }}"><br>
|
||||||
<input type="text" name="longitude" id="longitude" value="{{ $longitude }}"><br>
|
<input type="text" name="longitude" id="longitude" value="{{ $place->longitude }}"><br>
|
||||||
<p>Map Icon</p>
|
<p>Map Icon</p>
|
||||||
<select name="icon" id="icon">
|
<select name="icon" id="icon">
|
||||||
<option value="airfield"@if($icon == 'airfield')selected @endif>airfield</option>
|
<option value="airfield"@if($place->icon == 'airfield')selected @endif>airfield</option>
|
||||||
<option value="airport"@if($icon == 'airport')selected @endif>airport</option>
|
<option value="airport"@if($place->icon == 'airport')selected @endif>airport</option>
|
||||||
<option value="alcohol-shop"@if($icon == 'alcohol-shop')selected @endif>alcohol-shop</option>
|
<option value="alcohol-shop"@if($place->icon == 'alcohol-shop')selected @endif>alcohol-shop</option>
|
||||||
<option value="amusement-park"@if($icon == 'amusement-park')selected @endif>amusement-park</option>
|
<option value="amusement-park"@if($place->icon == 'amusement-park')selected @endif>amusement-park</option>
|
||||||
<option value="aquarium"@if($icon == 'aquarium')selected @endif>aquarium</option>
|
<option value="aquarium"@if($place->icon == 'aquarium')selected @endif>aquarium</option>
|
||||||
<option value="art-gallery"@if($icon == 'art-gallery')selected @endif>art-gallery</option>
|
<option value="art-gallery"@if($place->icon == 'art-gallery')selected @endif>art-gallery</option>
|
||||||
<option value="attraction"@if($icon == 'attraction')selected @endif>attraction</option>
|
<option value="attraction"@if($place->icon == 'attraction')selected @endif>attraction</option>
|
||||||
<option value="bakery"@if($icon == 'bakery')selected @endif>bakery</option>
|
<option value="bakery"@if($place->icon == 'bakery')selected @endif>bakery</option>
|
||||||
<option value="bank"@if($icon == 'bank')selected @endif>bank</option>
|
<option value="bank"@if($place->icon == 'bank')selected @endif>bank</option>
|
||||||
<option value="bar"@if($icon == 'bar')selected @endif>bar</option>
|
<option value="bar"@if($place->icon == 'bar')selected @endif>bar</option>
|
||||||
<option value="beer"@if($icon == 'beer')selected @endif>beer</option>
|
<option value="beer"@if($place->icon == 'beer')selected @endif>beer</option>
|
||||||
<option value="bicycle"@if($icon == 'bicycle')selected @endif>bicycle</option>
|
<option value="bicycle"@if($place->icon == 'bicycle')selected @endif>bicycle</option>
|
||||||
<option value="bicycle-share"@if($icon == 'bicycle-share')selected @endif>bicycle-share</option>
|
<option value="bicycle-share"@if($place->icon == 'bicycle-share')selected @endif>bicycle-share</option>
|
||||||
<option value="bus"@if($icon == 'bus')selected @endif>bus</option>
|
<option value="bus"@if($place->icon == 'bus')selected @endif>bus</option>
|
||||||
<option value="cafe"@if($icon == 'cafe')selected @endif>cafe</option>
|
<option value="cafe"@if($place->icon == 'cafe')selected @endif>cafe</option>
|
||||||
<option value="campsite"@if($icon == 'campsite')selected @endif>campsite</option>
|
<option value="campsite"@if($place->icon == 'campsite')selected @endif>campsite</option>
|
||||||
<option value="car"@if($icon == 'car')selected @endif>car</option>
|
<option value="car"@if($place->icon == 'car')selected @endif>car</option>
|
||||||
<option value="castle"@if($icon == 'castle')selected @endif>castle</option>
|
<option value="castle"@if($place->icon == 'castle')selected @endif>castle</option>
|
||||||
<option value="cemetery"@if($icon == 'cemetery')selected @endif>cemetery</option>
|
<option value="cemetery"@if($place->icon == 'cemetery')selected @endif>cemetery</option>
|
||||||
<option value="cinema"@if($icon == 'cinema')selected @endif>cinema</option>
|
<option value="cinema"@if($place->icon == 'cinema')selected @endif>cinema</option>
|
||||||
<option value="circle"@if($icon == 'circle')selected @endif>circle</option>
|
<option value="circle"@if($place->icon == 'circle')selected @endif>circle</option>
|
||||||
<option value="circle-stroked"@if($icon == 'circle-stroked')selected @endif>circle-stroked</option>
|
<option value="circle-stroked"@if($place->icon == 'circle-stroked')selected @endif>circle-stroked</option>
|
||||||
<option value="clothing-store"@if($icon == 'clothing-store')selected @endif>clothing-store</option>
|
<option value="clothing-store"@if($place->icon == 'clothing-store')selected @endif>clothing-store</option>
|
||||||
<option value="college"@if($icon == 'college')selected @endif>college</option>
|
<option value="college"@if($place->icon == 'college')selected @endif>college</option>
|
||||||
<option value="dentist"@if($icon == 'dentist')selected @endif>dentist</option>
|
<option value="dentist"@if($place->icon == 'dentist')selected @endif>dentist</option>
|
||||||
<option value="doctor"@if($icon == 'doctor')selected @endif>doctor</option>
|
<option value="doctor"@if($place->icon == 'doctor')selected @endif>doctor</option>
|
||||||
<option value="dog-park"@if($icon == 'dog-park')selected @endif>dog-park</option>
|
<option value="dog-park"@if($place->icon == 'dog-park')selected @endif>dog-park</option>
|
||||||
<option value="drinking-water"@if($icon == 'drinking-water')selected @endif>drinking-water</option>
|
<option value="drinking-water"@if($place->icon == 'drinking-water')selected @endif>drinking-water</option>
|
||||||
<option value="embassy"@if($icon == 'embassy')selected @endif>embassy</option>
|
<option value="embassy"@if($place->icon == 'embassy')selected @endif>embassy</option>
|
||||||
<option value="entrance"@if($icon == 'entrance')selected @endif>entrance</option>
|
<option value="entrance"@if($place->icon == 'entrance')selected @endif>entrance</option>
|
||||||
<option value="fast-food"@if($icon == 'fast-food')selected @endif>fast-food</option>
|
<option value="fast-food"@if($place->icon == 'fast-food')selected @endif>fast-food</option>
|
||||||
<option value="ferry"@if($icon == 'ferry')selected @endif>ferry</option>
|
<option value="ferry"@if($place->icon == 'ferry')selected @endif>ferry</option>
|
||||||
<option value="fire-station"@if($icon == 'fire-station')selected @endif>fire-station</option>
|
<option value="fire-station"@if($place->icon == 'fire-station')selected @endif>fire-station</option>
|
||||||
<option value="fuel"@if($icon == 'fuel')selected @endif>fuel</option>
|
<option value="fuel"@if($place->icon == 'fuel')selected @endif>fuel</option>
|
||||||
<option value="garden"@if($icon == 'garden')selected @endif>garden</option>
|
<option value="garden"@if($place->icon == 'garden')selected @endif>garden</option>
|
||||||
<option value="golf"@if($icon == 'golf')selected @endif>golf</option>
|
<option value="golf"@if($place->icon == 'golf')selected @endif>golf</option>
|
||||||
<option value="grocery"@if($icon == 'grocery')selected @endif>grocery</option>
|
<option value="grocery"@if($place->icon == 'grocery')selected @endif>grocery</option>
|
||||||
<option value="harbor"@if($icon == 'harbor')selected @endif>harbor</option>
|
<option value="harbor"@if($place->icon == 'harbor')selected @endif>harbor</option>
|
||||||
<option value="heliport"@if($icon == 'heliport')selected @endif>heliport</option>
|
<option value="heliport"@if($place->icon == 'heliport')selected @endif>heliport</option>
|
||||||
<option value="hospital"@if($icon == 'hospital')selected @endif>hospital</option>
|
<option value="hospital"@if($place->icon == 'hospital')selected @endif>hospital</option>
|
||||||
<option value="ice-cream"@if($icon == 'ice-cream')selected @endif>ice-cream</option>
|
<option value="ice-cream"@if($place->icon == 'ice-cream')selected @endif>ice-cream</option>
|
||||||
<option value="information"@if($icon == 'information')selected @endif>information</option>
|
<option value="information"@if($place->icon == 'information')selected @endif>information</option>
|
||||||
<option value="laundry"@if($icon == 'laundry')selected @endif>laundry</option>
|
<option value="laundry"@if($place->icon == 'laundry')selected @endif>laundry</option>
|
||||||
<option value="library"@if($icon == 'library')selected @endif>library</option>
|
<option value="library"@if($place->icon == 'library')selected @endif>library</option>
|
||||||
<option value="lodging"@if($icon == 'lodging')selected @endif>lodging</option>
|
<option value="lodging"@if($place->icon == 'lodging')selected @endif>lodging</option>
|
||||||
<option value="marker"@if($icon == 'marker')selected @endif>marker</option>
|
<option value="marker"@if($place->icon == 'marker')selected @endif>marker</option>
|
||||||
<option value="monument"@if($icon == 'monument')selected @endif>monument</option>
|
<option value="monument"@if($place->icon == 'monument')selected @endif>monument</option>
|
||||||
<option value="mountain"@if($icon == 'mountain')selected @endif>mountain</option>
|
<option value="mountain"@if($place->icon == 'mountain')selected @endif>mountain</option>
|
||||||
<option value="museum"@if($icon == 'museum')selected @endif>museum</option>
|
<option value="museum"@if($place->icon == 'museum')selected @endif>museum</option>
|
||||||
<option value="music"@if($icon == 'music')selected @endif>music</option>
|
<option value="music"@if($place->icon == 'music')selected @endif>music</option>
|
||||||
<option value="park"@if($icon == 'park')selected @endif>park</option>
|
<option value="park"@if($place->icon == 'park')selected @endif>park</option>
|
||||||
<option value="pharmacy"@if($icon == 'pharmacy')selected @endif>pharmacy</option>
|
<option value="pharmacy"@if($place->icon == 'pharmacy')selected @endif>pharmacy</option>
|
||||||
<option value="picnic-site"@if($icon == 'picnic-site')selected @endif>picnic-site</option>
|
<option value="picnic-site"@if($place->icon == 'picnic-site')selected @endif>picnic-site</option>
|
||||||
<option value="place-of-worship"@if($icon == 'place-of-worship')selected @endif>place-of-worship</option>
|
<option value="place-of-worship"@if($place->icon == 'place-of-worship')selected @endif>place-of-worship</option>
|
||||||
<option value="playground"@if($icon == 'playground')selected @endif>playground</option>
|
<option value="playground"@if($place->icon == 'playground')selected @endif>playground</option>
|
||||||
<option value="police"@if($icon == 'police')selected @endif>police</option>
|
<option value="police"@if($place->icon == 'police')selected @endif>police</option>
|
||||||
<option value="post"@if($icon == 'post')selected @endif>post</option>
|
<option value="post"@if($place->icon == 'post')selected @endif>post</option>
|
||||||
<option value="prison"@if($icon == 'prison')selected @endif>prison</option>
|
<option value="prison"@if($place->icon == 'prison')selected @endif>prison</option>
|
||||||
<option value="rail"@if($icon == 'rail')selected @endif>rail</option>
|
<option value="rail"@if($place->icon == 'rail')selected @endif>rail</option>
|
||||||
<option value="rail-light"@if($icon == 'rail-light')selected @endif>rail-light</option>
|
<option value="rail-light"@if($place->icon == 'rail-light')selected @endif>rail-light</option>
|
||||||
<option value="rail-metro"@if($icon == 'rail-metro')selected @endif>rail-metro</option>
|
<option value="rail-metro"@if($place->icon == 'rail-metro')selected @endif>rail-metro</option>
|
||||||
<option value="religious-christian"@if($icon == 'religious-christian')selected @endif>religious-christian</option>
|
<option value="religious-christian"@if($place->icon == 'religious-christian')selected @endif>religious-christian</option>
|
||||||
<option value="religious-jewish"@if($icon == 'religious-jewish')selected @endif>religious-jewish</option>
|
<option value="religious-jewish"@if($place->icon == 'religious-jewish')selected @endif>religious-jewish</option>
|
||||||
<option value="religious-muslim"@if($icon == 'religious-muslim')selected @endif>religious-muslim</option>
|
<option value="religious-muslim"@if($place->icon == 'religious-muslim')selected @endif>religious-muslim</option>
|
||||||
<option value="restaurant"@if($icon == 'restaurant')selected @endif>restaurant</option>
|
<option value="restaurant"@if($place->icon == 'restaurant')selected @endif>restaurant</option>
|
||||||
<option value="rocket"@if($icon == 'rocket')selected @endif>rocket</option>
|
<option value="rocket"@if($place->icon == 'rocket')selected @endif>rocket</option>
|
||||||
<option value="school"@if($icon == 'school')selected @endif>school</option>
|
<option value="school"@if($place->icon == 'school')selected @endif>school</option>
|
||||||
<option value="shop"@if($icon == 'shop')selected @endif>shop</option>
|
<option value="shop"@if($place->icon == 'shop')selected @endif>shop</option>
|
||||||
<option value="stadium"@if($icon == 'stadium')selected @endif>stadium</option>
|
<option value="stadium"@if($place->icon == 'stadium')selected @endif>stadium</option>
|
||||||
<option value="star"@if($icon == 'star')selected @endif>star</option>
|
<option value="star"@if($place->icon == 'star')selected @endif>star</option>
|
||||||
<option value="suitcase"@if($icon == 'suitcase')selected @endif>suitcase</option>
|
<option value="suitcase"@if($place->icon == 'suitcase')selected @endif>suitcase</option>
|
||||||
<option value="swimming"@if($icon == 'swimming')selected @endif>swimming</option>
|
<option value="swimming"@if($place->icon == 'swimming')selected @endif>swimming</option>
|
||||||
<option value="theatre"@if($icon == 'theatre')selected @endif>theatre</option>
|
<option value="theatre"@if($place->icon == 'theatre')selected @endif>theatre</option>
|
||||||
<option value="toilet"@if($icon == 'toilet')selected @endif>toilet</option>
|
<option value="toilet"@if($place->icon == 'toilet')selected @endif>toilet</option>
|
||||||
<option value="town-hall"@if($icon == 'town-hall')selected @endif>town-hall</option>
|
<option value="town-hall"@if($place->icon == 'town-hall')selected @endif>town-hall</option>
|
||||||
<option value="triangle"@if($icon == 'triangle')selected @endif>triangle</option>
|
<option value="triangle"@if($place->icon == 'triangle')selected @endif>triangle</option>
|
||||||
<option value="triangle-stroked"@if($icon == 'triangle-stroked')selected @endif>triangle-stroked</option>
|
<option value="triangle-stroked"@if($place->icon == 'triangle-stroked')selected @endif>triangle-stroked</option>
|
||||||
<option value="veterinary"@if($icon == 'veterinary')selected @endif>veterinary</option>
|
<option value="veterinary"@if($place->icon == 'veterinary')selected @endif>veterinary</option>
|
||||||
<option value="volcano"@if($icon == 'volcano')selected @endif>volcano</option>
|
<option value="volcano"@if($place->icon == 'volcano')selected @endif>volcano</option>
|
||||||
<option value="zoo"@if($icon == 'zoo')selected @endif>zoo</option>
|
<option value="zoo"@if($place->icon == 'zoo')selected @endif>zoo</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<input type="submit" name="edit" value="Edit"><br><br>
|
<input type="submit" name="edit" value="Edit"><br><br>
|
||||||
<input type="submit" name="delete" value="Delete">
|
<input type="submit" name="delete" value="Delete">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p><a href="/admin/places/{{ $id }}/merge">Merge with another place?</a></p>
|
<p><a href="/admin/places/{{ $place->id }}/merge">Merge with another place?</a></p>
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('scripts')
|
@section('scripts')
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
@empty($bookmark->name)
|
@empty($bookmark->name)
|
||||||
{{ $bookmark->url }}
|
{{ $bookmark->url }}
|
||||||
@endempty
|
@endempty
|
||||||
</a> <a href="/bookmarks/{{ $bookmark->id }}">🔗</a>
|
</a> <a href="{{ $bookmark->longurl }}">🔗</a>
|
||||||
@isset($bookmark->content)
|
@isset($bookmark->content)
|
||||||
<p>{{ $bookmark->content }}</p>
|
<p>{{ $bookmark->content }}</p>
|
||||||
@endisset
|
@endisset
|
||||||
|
|
|
@ -14,10 +14,12 @@
|
||||||
@else
|
@else
|
||||||
<span class="p-name">{{ $like->author_name }}</span>
|
<span class="p-name">{{ $like->author_name }}</span>
|
||||||
@endisset
|
@endisset
|
||||||
</span>:
|
</span>
|
||||||
|
@isset($like->content)
|
||||||
<blockquote class="e-content">
|
<blockquote class="e-content">
|
||||||
{!! $like->content !!}
|
{!! $like->content !!}
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
@endisset
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
}) as $reply)
|
}) as $reply)
|
||||||
<div class="u-comment h-cite">
|
<div class="u-comment h-cite">
|
||||||
<a class="u-author h-card mini-h-card" href="{{ $reply['author']['properties']['url'][0] }}">
|
<a class="u-author h-card mini-h-card" href="{{ $reply['author']['properties']['url'][0] }}">
|
||||||
<img src="{{ $reply['author']['properties']['photo'][0] }}" alt="" class="photo u-photo logo"> <span class="fn">{{ $reply['author']['properties']['name'][0] }}</span>
|
@if (array_key_exists('photo', $reply['author']['properties']))<img src="{{ $reply['author']['properties']['photo'][0] }}" alt="" class="photo u-photo logo">@endif <span class="fn">{{ $reply['author']['properties']['name'][0] }}</span>
|
||||||
</a> said at <a class="dt-published u-url" href="{{ $reply['source'] }}">{{ $reply['published'] }}</a>
|
</a> said at <a class="dt-published u-url" href="{{ $reply['source'] }}">{{ $reply['published'] }}</a>
|
||||||
<div class="e-content p-name">
|
<div class="e-content p-name">
|
||||||
{!! $reply['reply'] !!}
|
{!! $reply['reply'] !!}
|
||||||
|
|
|
@ -9,12 +9,11 @@
|
||||||
@include('templates.note', ['note' => $note])
|
@include('templates.note', ['note' => $note])
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
{{ $notes->links() }}
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('scripts')
|
@section('scripts')
|
||||||
@include('templates.mapbox-links')
|
@include('templates.mapbox-links')
|
||||||
|
|
||||||
<script src="/assets/frontend/Autolinker.min.js"></script>
|
|
||||||
<script src="/assets/js/links.js"></script>
|
<script src="/assets/js/links.js"></script>
|
||||||
<script src="/assets/js/maps.js"></script>
|
<script src="/assets/js/maps.js"></script>
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<span class="u-category h-card mini-h-card"><a class="u-url p-name" href="{{ $contact->homepage }}">{!! $contact->name !!}</a><span class="hovercard">@if ($contact->facebook)<a class="u-url" href="https://www.facebook.com/{{ $contact->facebook }}"><img class="social-icon" src="/assets/img/social-icons/facebook.svg"> {{ $contact->facebook_name ?: 'Facebook' }}</a>@endif @if ($contact->twitter)<a class="u-url" href="https://twitter.com/{{ $contact->twitter }}"><img class="social-icon" src="/assets/img/social-icons/twitter.svg"> {{ $contact->twitter }}</a><img class="u-photo" alt="" src="{{ $contact->photo }}">@endif</span></span>
|
<span class="u-category h-card mini-h-card"><a class="u-url p-name" href="{{ $contact->homepage }}">{!! $contact->name !!}</a><span class="hovercard">@if ($contact->facebook)<a class="u-url" href="https://www.facebook.com/{{ $contact->facebook }}"><img class="social-icon" src="/assets/img/social-icons/facebook.svg"> {{ $contact->facebook_name ?: 'Facebook' }}</a>@endif @if ($contact->twitter)<a class="u-url" href="https://twitter.com/{{ $contact->twitter }}"><img class="social-icon" src="/assets/img/social-icons/twitter.svg"> {{ $contact->twitter }}</a>@endif<img class="u-photo" alt="" src="{{ $contact->photo }}"></span></span>
|
||||||
|
|
|
@ -150,7 +150,6 @@ Route::group(['domain' => config('url.shorturl')], function () {
|
||||||
Route::get('/', 'ShortURLsController@baseURL');
|
Route::get('/', 'ShortURLsController@baseURL');
|
||||||
Route::get('@', 'ShortURLsController@twitter');
|
Route::get('@', 'ShortURLsController@twitter');
|
||||||
Route::get('+', 'ShortURLsController@googlePlus');
|
Route::get('+', 'ShortURLsController@googlePlus');
|
||||||
Route::get('α', 'ShortURLsController@appNet');
|
|
||||||
|
|
||||||
Route::get('{type}/{id}', 'ShortURLsController@expandType')->where(
|
Route::get('{type}/{id}', 'ShortURLsController@expandType')->where(
|
||||||
[
|
[
|
||||||
|
@ -160,9 +159,4 @@ Route::group(['domain' => config('url.shorturl')], function () {
|
||||||
);
|
);
|
||||||
|
|
||||||
Route::get('h/{id}', 'ShortURLsController@redirect');
|
Route::get('h/{id}', 'ShortURLsController@redirect');
|
||||||
Route::get('{id}', 'ShortURLsController@oldRedirect')->where(
|
|
||||||
[
|
|
||||||
'id' => '[0-9A-HJ-NP-Z_a-km-z]{4}',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
16
tests/Feature/AdminHomeControllerTest.php
Normal file
16
tests/Feature/AdminHomeControllerTest.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class AdminHomeControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_admin_homepage()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin');
|
||||||
|
$response->assertViewIs('admin.welcome');
|
||||||
|
}
|
||||||
|
}
|
39
tests/Feature/AdminTest.php
Normal file
39
tests/Feature/AdminTest.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class AdminTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_admin_page_redirects_to_login()
|
||||||
|
{
|
||||||
|
$response = $this->get('/admin');
|
||||||
|
$response->assertRedirect('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_login_page()
|
||||||
|
{
|
||||||
|
$response = $this->get('/login');
|
||||||
|
$response->assertViewIs('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_attempt_login_with_good_credentials()
|
||||||
|
{
|
||||||
|
$response = $this->post('/login', [
|
||||||
|
'username' => config('admin.user'),
|
||||||
|
'password' => config('admin.pass'),
|
||||||
|
]);
|
||||||
|
$response->assertRedirect('/admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_attempt_login_with_bad_credentials()
|
||||||
|
{
|
||||||
|
$response = $this->post('/login', [
|
||||||
|
'username' => 'bad',
|
||||||
|
'password' => 'credentials',
|
||||||
|
]);
|
||||||
|
$response->assertRedirect('/login');
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,20 @@ class ArticlesAdminTest extends TestCase
|
||||||
{
|
{
|
||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_index_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/blog');
|
||||||
|
$response->assertSeeText('Select article to edit:');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/blog/create');
|
||||||
|
$response->assertSeeText('Title (URL)');
|
||||||
|
}
|
||||||
|
|
||||||
public function test_create_new_article()
|
public function test_create_new_article()
|
||||||
{
|
{
|
||||||
$this->withSession(['loggedin' => true])
|
$this->withSession(['loggedin' => true])
|
||||||
|
@ -42,4 +56,36 @@ class ArticlesAdminTest extends TestCase
|
||||||
'main' => $text,
|
'main' => $text,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_see_edit_form()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/blog/1/edit');
|
||||||
|
$response->assertSeeText('This is *my* new blog. It uses `Markdown`.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_article()
|
||||||
|
{
|
||||||
|
$this->withSession(['loggedin' => true])
|
||||||
|
->post('/admin/blog/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'title' => 'My New Blog',
|
||||||
|
'main' => 'This article has been edited',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('articles', [
|
||||||
|
'title' => 'My New Blog',
|
||||||
|
'main' => 'This article has been edited',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete_article()
|
||||||
|
{
|
||||||
|
$this->withSession(['loggedin' => true])
|
||||||
|
->post('/admin/blog/1', [
|
||||||
|
'_method' => 'DELETE',
|
||||||
|
]);
|
||||||
|
$this->assertSoftDeleted('articles', [
|
||||||
|
'title' => 'My New Blog',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
33
tests/Feature/ArticlesTest.php
Normal file
33
tests/Feature/ArticlesTest.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class ArticlesTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_articles_page()
|
||||||
|
{
|
||||||
|
$response = $this->get('/blog');
|
||||||
|
$response->assertViewIs('articles.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_single_article()
|
||||||
|
{
|
||||||
|
$response = $this->get('/blog/' . date('Y') . '/' . date('m') . '/my-new-blog');
|
||||||
|
$response->assertViewIs('articles.show');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_wrong_date_redirects()
|
||||||
|
{
|
||||||
|
$response = $this->get('/blog/1900/01/my-new-blog');
|
||||||
|
$response->assertRedirect('/blog/' . date('Y') . '/' . date('m') . '/my-new-blog');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_redirect_for_id()
|
||||||
|
{
|
||||||
|
$response = $this->get('/blog/s/1');
|
||||||
|
$response->assertRedirect('/blog/' . date('Y') . '/' . date('m') . '/my-new-blog');
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,27 @@ use Tests\TestCase;
|
||||||
use Tests\TestToken;
|
use Tests\TestToken;
|
||||||
use App\Jobs\ProcessBookmark;
|
use App\Jobs\ProcessBookmark;
|
||||||
use Illuminate\Support\Facades\Queue;
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use App\Jobs\SyndicateBookmarkToTwitter;
|
||||||
|
use App\Jobs\SyndicateBookmarkToFacebook;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
class BookmarksTest extends TestCase
|
class BookmarksTest extends TestCase
|
||||||
{
|
{
|
||||||
use DatabaseTransactions, TestToken;
|
use DatabaseTransactions, TestToken;
|
||||||
|
|
||||||
public function test_browsershot_job_dispatches_when_bookmark_added()
|
public function test_bookmarks_page()
|
||||||
|
{
|
||||||
|
$response = $this->get('/bookmarks');
|
||||||
|
$response->assertViewIs('bookmarks.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_single_bookmark_page()
|
||||||
|
{
|
||||||
|
$response = $this->get('/bookmarks/1');
|
||||||
|
$response->assertViewIs('bookmarks.show');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_browsershot_job_dispatches_when_bookmark_added_http_post_syntax()
|
||||||
{
|
{
|
||||||
Queue::fake();
|
Queue::fake();
|
||||||
|
|
||||||
|
@ -21,6 +35,95 @@ class BookmarksTest extends TestCase
|
||||||
])->post('/api/post', [
|
])->post('/api/post', [
|
||||||
'h' => 'entry',
|
'h' => 'entry',
|
||||||
'bookmark-of' => 'https://example.org/blog-post',
|
'bookmark-of' => 'https://example.org/blog-post',
|
||||||
|
'mp-syndicate-to' => [
|
||||||
|
'https://twitter.com/jonnybarnes',
|
||||||
|
'https://facebook.com/jonnybarnes',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertJson(['response' => 'created']);
|
||||||
|
|
||||||
|
Queue::assertPushed(ProcessBookmark::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToTwitter::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToFacebook::class);
|
||||||
|
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_browsershot_job_dispatches_when_bookmark_added_json_syntax()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . $this->getToken(),
|
||||||
|
])->json('POST', '/api/post', [
|
||||||
|
'type' => ['h-entry'],
|
||||||
|
'properties' => [
|
||||||
|
'bookmark-of' => ['https://example.org/blog-post'],
|
||||||
|
'mp-syndicate-to' => [
|
||||||
|
'https://twitter.com/jonnybarnes',
|
||||||
|
'https://facebook.com/jonnybarnes',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertJson(['response' => 'created']);
|
||||||
|
|
||||||
|
Queue::assertPushed(ProcessBookmark::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToTwitter::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToFacebook::class);
|
||||||
|
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_single_twitter_syndication_target_causes_job_dispatch_http_post_syntax()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . $this->getToken(),
|
||||||
|
])->post('/api/post', [
|
||||||
|
'h' => 'entry',
|
||||||
|
'bookmark-of' => 'https://example.org/blog-post',
|
||||||
|
'mp-syndicate-to' => 'https://twitter.com/jonnybarnes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertJson(['response' => 'created']);
|
||||||
|
|
||||||
|
Queue::assertPushed(ProcessBookmark::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToTwitter::class);
|
||||||
|
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_single_facebook_syndication_target_causes_job_dispatch_http_post_syntax()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . $this->getToken(),
|
||||||
|
])->post('/api/post', [
|
||||||
|
'h' => 'entry',
|
||||||
|
'bookmark-of' => 'https://example.org/blog-post',
|
||||||
|
'mp-syndicate-to' => 'https://facebook.com/jonnybarnes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertJson(['response' => 'created']);
|
||||||
|
|
||||||
|
Queue::assertPushed(ProcessBookmark::class);
|
||||||
|
Queue::assertPushed(SyndicateBookmarkToFacebook::class);
|
||||||
|
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tags_created_with_new_bookmark()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . $this->getToken(),
|
||||||
|
])->json('POST', '/api/post', [
|
||||||
|
'type' => ['h-entry'],
|
||||||
|
'properties' => [
|
||||||
|
'bookmark-of' => ['https://example.org/blog-post'],
|
||||||
|
'category' => ['tag1', 'tag2'],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response->assertJson(['response' => 'created']);
|
$response->assertJson(['response' => 'created']);
|
||||||
|
@ -28,13 +131,4 @@ class BookmarksTest extends TestCase
|
||||||
Queue::assertPushed(ProcessBookmark::class);
|
Queue::assertPushed(ProcessBookmark::class);
|
||||||
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_screenshot_of_google()
|
|
||||||
{
|
|
||||||
$url = 'https://www.google.co.uk';
|
|
||||||
|
|
||||||
$uuid = (new \App\Services\BookmarkService())->saveScreenshot($url);
|
|
||||||
|
|
||||||
$this->assertTrue(file_exists(public_path() . '/assets/img/bookmarks/' . $uuid . '.png'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ class BridgyPosseTest extends TestCase
|
||||||
{
|
{
|
||||||
public function test_bridgy_twitter_content()
|
public function test_bridgy_twitter_content()
|
||||||
{
|
{
|
||||||
$response = $this->get('/notes/C');
|
$response = $this->get('/notes/E');
|
||||||
|
|
||||||
$html = $response->content();
|
$html = $response->content();
|
||||||
$this->assertTrue(is_string(mb_stristr($html, 'p-bridgy-twitter-content')));
|
$this->assertTrue(is_string(mb_stristr($html, 'p-bridgy-twitter-content')));
|
||||||
|
@ -16,7 +16,7 @@ class BridgyPosseTest extends TestCase
|
||||||
|
|
||||||
public function test_bridgy_facebook_content()
|
public function test_bridgy_facebook_content()
|
||||||
{
|
{
|
||||||
$response = $this->get('/notes/C');
|
$response = $this->get('/notes/E');
|
||||||
|
|
||||||
$html = $response->content();
|
$html = $response->content();
|
||||||
$this->assertTrue(is_string(mb_stristr($html, 'p-bridgy-facebook-content')));
|
$this->assertTrue(is_string(mb_stristr($html, 'p-bridgy-facebook-content')));
|
||||||
|
|
70
tests/Feature/ClientsAdminTest.php
Normal file
70
tests/Feature/ClientsAdminTest.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class ClientsAdminTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_index_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/clients');
|
||||||
|
$response->assertSeeText('Clients');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/clients/create');
|
||||||
|
$response->assertSeeText('New Client');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_new_client()
|
||||||
|
{
|
||||||
|
$this->withSession(['loggedin' => true])
|
||||||
|
->post('/admin/clients', [
|
||||||
|
'client_name' => 'Micropublish',
|
||||||
|
'client_url' => 'https://micropublish.net'
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('clients', [
|
||||||
|
'client_name' => 'Micropublish',
|
||||||
|
'client_url' => 'https://micropublish.net'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_see_edit_form()
|
||||||
|
{
|
||||||
|
$response = $this->withSession(['loggedin' => true])
|
||||||
|
->get('/admin/clients/1/edit');
|
||||||
|
$response->assertSee('https://jbl5.dev/notes/new');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_client()
|
||||||
|
{
|
||||||
|
$this->withSession(['loggedin' => true])
|
||||||
|
->post('/admin/clients/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'client_url' => 'https://jbl5.dev/notes/new',
|
||||||
|
'client_name' => 'JBL5dev',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('clients', [
|
||||||
|
'client_url' => 'https://jbl5.dev/notes/new',
|
||||||
|
'client_name' => 'JBL5dev',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete_client()
|
||||||
|
{
|
||||||
|
$this->withSession(['loggedin' => true])
|
||||||
|
->post('/admin/clients/1', [
|
||||||
|
'_method' => 'DELETE',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseMissing('clients', [
|
||||||
|
'client_url' => 'https://jbl5.dev/notes/new',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
194
tests/Feature/ContactsAdminTest.php
Normal file
194
tests/Feature/ContactsAdminTest.php
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Contact;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\HandlerStack;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class ContactsAdminTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
if (file_exists(public_path() . '/assets/profile-images/tantek.com/image')) {
|
||||||
|
unlink(public_path() . '/assets/profile-images/tantek.com/image');
|
||||||
|
rmdir(public_path() . '/assets/profile-images/tantek.com');
|
||||||
|
}
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_index_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->get('/admin/contacts');
|
||||||
|
$response->assertViewIs('admin.contacts.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->get('/admin/contacts/create');
|
||||||
|
$response->assertViewIs('admin.contacts.create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_new_contact()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->post('/admin/contacts', [
|
||||||
|
'name' => 'Fred Bloggs',
|
||||||
|
'nick' => 'fred',
|
||||||
|
'homepage' => 'https://fred.blog/gs',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('contacts', [
|
||||||
|
'name' => 'Fred Bloggs',
|
||||||
|
'nick' => 'fred',
|
||||||
|
'homepage' => 'https://fred.blog/gs'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_see_edit_form()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->get('/admin/contacts/1/edit');
|
||||||
|
$response->assertViewIs('admin.contacts.edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_contact_no_uploaded_avatar()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->post('/admin/contacts/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'name' => 'Tantek Celik',
|
||||||
|
'nick' => 'tantek',
|
||||||
|
'homepage' => 'https://tantek.com',
|
||||||
|
'twitter' => 't',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('contacts', [
|
||||||
|
'name' => 'Tantek Celik',
|
||||||
|
'homepage' => 'https://tantek.com',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_contact_with_uploaded_avatar()
|
||||||
|
{
|
||||||
|
copy(__DIR__ . '/../aaron.png', sys_get_temp_dir() . '/tantek.png');
|
||||||
|
$path = sys_get_temp_dir() . '/tantek.png';
|
||||||
|
$file = new UploadedFile($path, 'tantek.png', 'image/png', filesize($path), null, true);
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->post('/admin/contacts/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'name' => 'Tantek Celik',
|
||||||
|
'nick' => 'tantek',
|
||||||
|
'homepage' => 'https://tantek.com',
|
||||||
|
'twitter' => 't',
|
||||||
|
'avatar' => $file,
|
||||||
|
]);
|
||||||
|
$this->assertFileEquals(
|
||||||
|
__DIR__ . '/../aaron.png',
|
||||||
|
public_path() . '/assets/profile-images/tantek.com/image'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete_contact()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true
|
||||||
|
])->post('/admin/contacts/1', [
|
||||||
|
'_method' => 'DELETE',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseMissing('contacts', [
|
||||||
|
'nick' => 'tantek',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_avatar_method()
|
||||||
|
{
|
||||||
|
$html = <<<HTML
|
||||||
|
<div class="h-card">
|
||||||
|
<img class="u-photo" src="http://tantek.com/tantek.png">
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$file = fopen(__DIR__ . '/../aaron.png', 'r');
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['Content-Type' => 'text/html'], $html),
|
||||||
|
new Response(200, ['Content-Type' => 'iamge/png'], $file),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/contacts/1/getavatar');
|
||||||
|
|
||||||
|
$this->assertFileEquals(
|
||||||
|
__DIR__ . '/../aaron.png',
|
||||||
|
public_path() . '/assets/profile-images/tantek.com/image'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_avatar_method_redirects_with_failed_homepage()
|
||||||
|
{
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(404),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/contacts/1/getavatar');
|
||||||
|
|
||||||
|
$response->assertRedirect('/admin/contacts/1/edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_avatar_method_redirects_with_failed_avatar_download()
|
||||||
|
{
|
||||||
|
$html = <<<HTML
|
||||||
|
<div class="h-card">
|
||||||
|
<img class="u-photo" src="http://tantek.com/tantek.png">
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['Content-Type' => 'text/html'], $html),
|
||||||
|
new Response(404),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/contacts/1/getavatar');
|
||||||
|
|
||||||
|
$response->assertRedirect('/admin/contacts/1/edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_avatar_for_contact_with_no_homepage()
|
||||||
|
{
|
||||||
|
$contact = Contact::create([
|
||||||
|
'nick' => 'fred',
|
||||||
|
'name' => 'Fred Bloggs',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/contacts/' . $contact->id . '/getavatar');
|
||||||
|
|
||||||
|
$response->assertRedirect('/admin/contacts/' . $contact->id . '/edit');
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ class LikesTest extends TestCase
|
||||||
$response->assertViewIs('likes.show');
|
$response->assertViewIs('likes.show');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_like_micropub_request()
|
public function test_like_micropub_json_request()
|
||||||
{
|
{
|
||||||
Queue::fake();
|
Queue::fake();
|
||||||
|
|
||||||
|
@ -51,7 +51,24 @@ class LikesTest extends TestCase
|
||||||
$this->assertDatabaseHas('likes', ['url' => 'https://example.org/blog-post']);
|
$this->assertDatabaseHas('likes', ['url' => 'https://example.org/blog-post']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_process_like_job()
|
public function test_like_micropub_form_request()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . $this->getToken(),
|
||||||
|
])->post('/api/post', [
|
||||||
|
'h' => 'entry',
|
||||||
|
'like-of' => 'https://example.org/blog-post',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertStatus(201);
|
||||||
|
|
||||||
|
Queue::assertPushed(ProcessLike::class);
|
||||||
|
$this->assertDatabaseHas('likes', ['url' => 'https://example.org/blog-post']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_process_like_job_with_simple_author()
|
||||||
{
|
{
|
||||||
$like = new Like();
|
$like = new Like();
|
||||||
$like->url = 'http://example.org/note/id';
|
$like->url = 'http://example.org/note/id';
|
||||||
|
@ -85,4 +102,75 @@ END;
|
||||||
|
|
||||||
$this->assertEquals('Fred Bloggs', Like::find($id)->author_name);
|
$this->assertEquals('Fred Bloggs', Like::find($id)->author_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_process_like_job_with_h_card()
|
||||||
|
{
|
||||||
|
$like = new Like();
|
||||||
|
$like->url = 'http://example.org/note/id';
|
||||||
|
$like->save();
|
||||||
|
$id = $like->id;
|
||||||
|
|
||||||
|
$job = new ProcessLike($like);
|
||||||
|
|
||||||
|
$content = <<<END
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div class="h-entry">
|
||||||
|
<div class="e-content">
|
||||||
|
A post that I like.
|
||||||
|
</div>
|
||||||
|
by
|
||||||
|
<div class="p-author h-card">
|
||||||
|
<span class="p-name">Fred Bloggs</span>
|
||||||
|
<a class="u-url" href="https://fredd.blog/gs"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
END;
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, [], $content),
|
||||||
|
new Response(200, [], $content),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->bind(Client::class, $client);
|
||||||
|
$authorship = new Authorship();
|
||||||
|
|
||||||
|
$job->handle($client, $authorship);
|
||||||
|
|
||||||
|
$this->assertEquals('Fred Bloggs', Like::find($id)->author_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_process_like_job_without_mf2()
|
||||||
|
{
|
||||||
|
$like = new Like();
|
||||||
|
$like->url = 'http://example.org/note/id';
|
||||||
|
$like->save();
|
||||||
|
$id = $like->id;
|
||||||
|
|
||||||
|
$job = new ProcessLike($like);
|
||||||
|
|
||||||
|
$content = <<<END
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
I liked a post
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
END;
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, [], $content),
|
||||||
|
new Response(200, [], $content),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->bind(Client::class, $client);
|
||||||
|
$authorship = new Authorship();
|
||||||
|
|
||||||
|
$job->handle($client, $authorship);
|
||||||
|
|
||||||
|
$this->assertNull(Like::find($id)->author_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,11 @@ namespace Tests\Feature;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use Tests\TestToken;
|
use Tests\TestToken;
|
||||||
use Lcobucci\JWT\Builder;
|
use Lcobucci\JWT\Builder;
|
||||||
|
use App\Jobs\ProcessMedia;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
class MicropubControllerTest extends TestCase
|
class MicropubControllerTest extends TestCase
|
||||||
|
@ -18,7 +22,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_without_token_returns_401_response()
|
public function test_micropub_get_request_without_token_returns_401_response()
|
||||||
{
|
{
|
||||||
$response = $this->get('/api/post');
|
$response = $this->get('/api/post');
|
||||||
$response->assertStatus(401);
|
$response->assertStatus(401);
|
||||||
|
@ -31,7 +35,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_without_valid_token_returns_400_response()
|
public function test_micropub_get_request_without_valid_token_returns_400_response()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer abc123']);
|
$response = $this->call('GET', '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer abc123']);
|
||||||
$response->assertStatus(400);
|
$response->assertStatus(400);
|
||||||
|
@ -44,7 +48,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_with_valid_token_returns_200_response()
|
public function test_micropub_get_request_with_valid_token_returns_200_response()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
@ -56,7 +60,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_for_syndication_targets()
|
public function test_micropub_get_request_for_syndication_targets()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', ['q' => 'syndicate-to'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', ['q' => 'syndicate-to'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']);
|
$response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']);
|
||||||
|
@ -67,7 +71,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_for_nearby_places()
|
public function test_micropub_get_request_for_nearby_places()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', ['q' => 'geo:53.5,-2.38'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', ['q' => 'geo:53.5,-2.38'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertJson(['places' => [['slug' =>'the-bridgewater-pub']]]);
|
$response->assertJson(['places' => [['slug' =>'the-bridgewater-pub']]]);
|
||||||
|
@ -78,7 +82,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_for_nearby_places_with_uncertainty_parameter()
|
public function test_micropub_get_request_for_nearby_places_with_uncertainty_parameter()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', ['q' => 'geo:53.5,-2.38;u=35'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', ['q' => 'geo:53.5,-2.38;u=35'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertJson(['places' => [['slug' => 'the-bridgewater-pub']]]);
|
$response->assertJson(['places' => [['slug' => 'the-bridgewater-pub']]]);
|
||||||
|
@ -89,7 +93,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_for_nearby_places_where_non_exist()
|
public function test_micropub_get_request_for_nearby_places_where_non_exist()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', ['q' => 'geo:1.23,4.56'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', ['q' => 'geo:1.23,4.56'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertJson(['places' => []]);
|
$response->assertJson(['places' => []]);
|
||||||
|
@ -100,7 +104,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_for_config()
|
public function test_micropub_get_request_for_config()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/api/post', ['q' => 'config'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
$response = $this->call('GET', '/api/post', ['q' => 'config'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
|
||||||
$response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']);
|
$response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']);
|
||||||
|
@ -111,7 +115,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_creates_new_note()
|
public function test_micropub_post_request_creates_new_note()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$note = $faker->text;
|
$note = $faker->text;
|
||||||
|
@ -135,7 +139,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_creates_new_place()
|
public function test_micropub_post_request_creates_new_place()
|
||||||
{
|
{
|
||||||
$response = $this->call(
|
$response = $this->call(
|
||||||
'POST',
|
'POST',
|
||||||
|
@ -153,12 +157,37 @@ class MicropubControllerTest extends TestCase
|
||||||
$this->assertDatabaseHas('places', ['slug' => 'the-barton-arms']);
|
$this->assertDatabaseHas('places', ['slug' => 'the-barton-arms']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test a valid micropub requests creates a new place with latitude
|
||||||
|
* and longitude values defined separately.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function test_micropub_post_request_creates_new_place_with_latlng()
|
||||||
|
{
|
||||||
|
$response = $this->call(
|
||||||
|
'POST',
|
||||||
|
'/api/post',
|
||||||
|
[
|
||||||
|
'h' => 'card',
|
||||||
|
'name' => 'The Barton Arms',
|
||||||
|
'latitude' => '53.4974',
|
||||||
|
'longitude' => '-2.3768',
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response->assertJson(['response' => 'created']);
|
||||||
|
$this->assertDatabaseHas('places', ['slug' => 'the-barton-arms']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test a valid micropub requests using JSON syntax creates a new note.
|
* Test a valid micropub requests using JSON syntax creates a new note.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_with_json_syntax_creates_new_note()
|
public function test_micropub_post_request_with_json_syntax_creates_new_note()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$note = $faker->text;
|
$note = $faker->text;
|
||||||
|
@ -184,7 +213,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_with_json_syntax_without_token_returns_error()
|
public function test_micropub_post_request_with_json_syntax_without_token_returns_error()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$note = $faker->text;
|
$note = $faker->text;
|
||||||
|
@ -212,7 +241,7 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_with_json_syntax_with_invalid_token_returns_error()
|
public function test_micropub_post_request_with_json_syntax_with_invalid_token_returns_error()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$note = $faker->text;
|
$note = $faker->text;
|
||||||
|
@ -235,7 +264,7 @@ class MicropubControllerTest extends TestCase
|
||||||
->assertStatus(401);
|
->assertStatus(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_micropub_request_with_json_syntax_creates_new_place()
|
public function test_micropub_post_request_with_json_syntax_creates_new_place()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$response = $this->json(
|
$response = $this->json(
|
||||||
|
@ -255,7 +284,7 @@ class MicropubControllerTest extends TestCase
|
||||||
->assertStatus(201);
|
->assertStatus(201);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_micropub_request_with_json_syntax_and_uncertainty_parameter_creates_new_place()
|
public function test_micropub_post_request_with_json_syntax_and_uncertainty_parameter_creates_new_place()
|
||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$response = $this->json(
|
$response = $this->json(
|
||||||
|
@ -275,7 +304,7 @@ class MicropubControllerTest extends TestCase
|
||||||
->assertStatus(201);
|
->assertStatus(201);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_micropub_request_with_json_syntax_update_replace_post()
|
public function test_micropub_post_request_with_json_syntax_update_replace_post()
|
||||||
{
|
{
|
||||||
$response = $this->json(
|
$response = $this->json(
|
||||||
'POST',
|
'POST',
|
||||||
|
@ -294,7 +323,7 @@ class MicropubControllerTest extends TestCase
|
||||||
->assertStatus(200);
|
->assertStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_micropub_request_with_json_syntax_update_add_post()
|
public function test_micropub_post_request_with_json_syntax_update_add_post()
|
||||||
{
|
{
|
||||||
$response = $this->json(
|
$response = $this->json(
|
||||||
'POST',
|
'POST',
|
||||||
|
@ -315,4 +344,54 @@ class MicropubControllerTest extends TestCase
|
||||||
'swarm_url' => 'https://www.swarmapp.com/checkin/123'
|
'swarm_url' => 'https://www.swarmapp.com/checkin/123'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_media_endpoint_request_with_invalid_token_return_400_response()
|
||||||
|
{
|
||||||
|
$response = $this->call(
|
||||||
|
'POST',
|
||||||
|
'/api/media',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['HTTP_Authorization' => 'Bearer abc123']
|
||||||
|
);
|
||||||
|
$response->assertStatus(400);
|
||||||
|
$response->assertJsonFragment(['error_description' => 'The provided token did not pass validation']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_media_endpoint_request_with_insufficient_token_scopes_returns_401_response()
|
||||||
|
{
|
||||||
|
$response = $this->call(
|
||||||
|
'POST',
|
||||||
|
'/api/media',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getInvalidToken()]
|
||||||
|
);
|
||||||
|
$response->assertStatus(401);
|
||||||
|
$response->assertJsonFragment(['error_description' => 'The token’s scope does not have the necessary requirements.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_media_endpoint_upload_a_file()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
Storage::fake('local');
|
||||||
|
|
||||||
|
$response = $this->call(
|
||||||
|
'POST',
|
||||||
|
'/api/media',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'file' => UploadedFile::fake()->image('scrot.png', 1920, 1080)->size(250),
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
|
||||||
|
$path = parse_url($response->getData()->location, PHP_URL_PATH);
|
||||||
|
$filename = substr($path, 7);
|
||||||
|
Queue::assertPushed(ProcessMedia::class);
|
||||||
|
Storage::disk('local')->assertExists($filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Feature;
|
|
||||||
|
|
||||||
use Tests\TestCase;
|
|
||||||
use App\Services\NoteService;
|
|
||||||
use App\Jobs\SyndicateNoteToTwitter;
|
|
||||||
use App\Jobs\SyndicateNoteToFacebook;
|
|
||||||
use Illuminate\Support\Facades\Queue;
|
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
||||||
|
|
||||||
class NoteServiceTest extends TestCase
|
|
||||||
{
|
|
||||||
use DatabaseTransactions;
|
|
||||||
|
|
||||||
public function test_syndicate_to_twitter_job_is_sent()
|
|
||||||
{
|
|
||||||
Queue::fake();
|
|
||||||
|
|
||||||
$noteService = new NoteService();
|
|
||||||
$note = $noteService->createNote([
|
|
||||||
'content' => 'Hello Fred',
|
|
||||||
'in-reply-to' => 'https://fredbloggs.com/note/abc',
|
|
||||||
'syndicate' => ['twitter'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
Queue::assertPushed(SyndicateNoteToTwitter::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_syndicate_to_facebook_job_is_sent()
|
|
||||||
{
|
|
||||||
Queue::fake();
|
|
||||||
|
|
||||||
$noteService = new NoteService();
|
|
||||||
$note = $noteService->createNote([
|
|
||||||
'content' => 'Hello Fred',
|
|
||||||
'in-reply-to' => 'https://fredbloggs.com/note/abc',
|
|
||||||
'syndicate' => ['facebook'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
Queue::assertPushed(SyndicateNoteToFacebook::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_syndicate_to_target_jobs_are_sent()
|
|
||||||
{
|
|
||||||
Queue::fake();
|
|
||||||
|
|
||||||
$noteService = new NoteService();
|
|
||||||
$note = $noteService->createNote([
|
|
||||||
'content' => 'Hello Fred',
|
|
||||||
'in-reply-to' => 'https://fredbloggs.com/note/abc',
|
|
||||||
'syndicate' => ['twitter', 'facebook'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
Queue::assertPushed(SyndicateNoteToTwitter::class);
|
|
||||||
Queue::assertPushed(SyndicateNoteToFacebook::class);
|
|
||||||
}
|
|
||||||
}
|
|
79
tests/Feature/NotesAdminTest.php
Normal file
79
tests/Feature/NotesAdminTest.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\Jobs\SendWebMentions;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class NotesAdminTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_index_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/notes');
|
||||||
|
$response->assertViewIs('admin.notes.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/notes/create');
|
||||||
|
$response->assertViewIs('admin.notes.create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_a_new_note()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->post('/admin/notes', [
|
||||||
|
'content' => 'A new test note',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('notes', [
|
||||||
|
'note' => 'A new test note',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/notes/1/edit');
|
||||||
|
$response->assertViewIs('admin.notes.edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_a_note()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->post('/admin/notes/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'content' => 'An edited note',
|
||||||
|
'webmentions' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('notes', [
|
||||||
|
'note' => 'An edited note',
|
||||||
|
]);
|
||||||
|
Queue::assertPushed(SendWebMentions::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete_note()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->post('/admin/notes/1', [
|
||||||
|
'_method' => 'DELETE',
|
||||||
|
]);
|
||||||
|
$this->assertSoftDeleted('notes', [
|
||||||
|
'id' => '1',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,12 @@ class NotesControllerTest extends TestCase
|
||||||
$response->assertViewHas('note');
|
$response->assertViewHas('note');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_note_replying_to_tweet()
|
||||||
|
{
|
||||||
|
$response = $this->get('/notes/B');
|
||||||
|
$response->assertViewHas('note');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that `/note/{decID}` redirects to `/notes/{nb60id}`.
|
* Test that `/note/{decID}` redirects to `/notes/{nb60id}`.
|
||||||
*
|
*
|
||||||
|
|
57
tests/Feature/ParseCachedWebMentionsTest.php
Normal file
57
tests/Feature/ParseCachedWebMentionsTest.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\WebMention;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class ParseCachedWebMentionsTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
mkdir(storage_path('HTML') . '/https/aaronpk.localhost/reply', 0777, true);
|
||||||
|
mkdir(storage_path('HTML') . '/http/tantek.com', 0777, true);
|
||||||
|
copy(__DIR__.'/../aaron.html', storage_path('HTML') . '/https/aaronpk.localhost/reply/1');
|
||||||
|
copy(__DIR__.'/../tantek.html', storage_path('HTML') . '/http/tantek.com/index.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parsing_html()
|
||||||
|
{
|
||||||
|
$this->assertFileExists(storage_path('HTML') . '/https/aaronpk.localhost/reply/1');
|
||||||
|
$this->assertFileExists(storage_path('HTML') . '/http/tantek.com/index.html');
|
||||||
|
$htmlAaron = file_get_contents(storage_path('HTML') . '/https/aaronpk.localhost/reply/1');
|
||||||
|
$htmlAaron = str_replace('href="/notes', 'href="' . config('app.url') . '/notes', $htmlAaron);
|
||||||
|
$htmlAaron = str_replace('datetime=""', 'dateime="' . carbon()->now()->toIso8601String() . '"', $htmlAaron);
|
||||||
|
file_put_contents(storage_path('HTML') . '/https/aaronpk.localhost/reply/1', $htmlAaron);
|
||||||
|
$htmlTantek = file_get_contents(storage_path('HTML') . '/http/tantek.com/index.html');
|
||||||
|
$htmlTantek = str_replace('href="/notes', 'href="' . config('app.url') . '/notes', $htmlTantek);
|
||||||
|
$htmlTantek = str_replace('datetime=""', 'dateime="' . carbon()->now()->toIso8601String() . '"', $htmlTantek);
|
||||||
|
file_put_contents(storage_path('HTML') . '/http/tantek.com/index.html', $htmlTantek);
|
||||||
|
|
||||||
|
Artisan::call('webmentions:parsecached');
|
||||||
|
|
||||||
|
$webmentionAaron = WebMention::find(1);
|
||||||
|
$webmentionTantek = WebMention::find(2);
|
||||||
|
$this->assertTrue($webmentionAaron->updated_at->gt($webmentionAaron->created_at));
|
||||||
|
$this->assertTrue($webmentionTantek->updated_at->gt($webmentionTantek->created_at));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
unlink(storage_path('HTML') . '/https/aaronpk.localhost/reply/1');
|
||||||
|
rmdir(storage_path('HTML') . '/https/aaronpk.localhost/reply');
|
||||||
|
rmdir(storage_path('HTML') . '/https/aaronpk.localhost');
|
||||||
|
rmdir(storage_path('HTML') . '/https');
|
||||||
|
unlink(storage_path('HTML') . '/http/tantek.com/index.html');
|
||||||
|
rmdir(storage_path('HTML') . '/http/tantek.com');
|
||||||
|
rmdir(storage_path('HTML') . '/http');
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
}
|
67
tests/Feature/PlacesAdminTest.php
Normal file
67
tests/Feature/PlacesAdminTest.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class PlacesAdminTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_index_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/places');
|
||||||
|
$response->assertViewIs('admin.places.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/places/create');
|
||||||
|
$response->assertViewIs('admin.places.create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_new_place()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->post('/admin/places', [
|
||||||
|
'name' => 'Test Place',
|
||||||
|
'description' => 'A dummy place for feature tests',
|
||||||
|
'latitude' => '1.23',
|
||||||
|
'longitude' => '4.56',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('places', [
|
||||||
|
'name' => 'Test Place',
|
||||||
|
'description' => 'A dummy place for feature tests',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edit_page()
|
||||||
|
{
|
||||||
|
$response = $this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->get('/admin/places/1/edit');
|
||||||
|
$response->assertViewIs('admin.places.edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_updating_a_place()
|
||||||
|
{
|
||||||
|
$this->withSession([
|
||||||
|
'loggedin' => true,
|
||||||
|
])->post('/admin/places/1', [
|
||||||
|
'_method' => 'PUT',
|
||||||
|
'name' => 'The Bridgewater',
|
||||||
|
'description' => 'Who uses “Pub” anyway',
|
||||||
|
'latitude' => '53.4983',
|
||||||
|
'longitude' => '-2.3805',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('places', [
|
||||||
|
'name' => 'The Bridgewater',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
20
tests/Feature/ReDownloadWebMentionsTest.php
Normal file
20
tests/Feature/ReDownloadWebMentionsTest.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\Jobs\DownloadWebMention;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
|
||||||
|
class ReDownloadWebMentionsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_jobs_are_dispatched()
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
Artisan::call('webmentions:redownload');
|
||||||
|
|
||||||
|
Queue::assertPushed(DownloadWebMention::class);
|
||||||
|
}
|
||||||
|
}
|
15
tests/Feature/SearchControllerTest.php
Normal file
15
tests/Feature/SearchControllerTest.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class SearchControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_search()
|
||||||
|
{
|
||||||
|
$response = $this->get('/search?terms=wedding');
|
||||||
|
$response->assertSee('#weddingfavour');
|
||||||
|
}
|
||||||
|
}
|
15
tests/Feature/SessionStoreControllerTest.php
Normal file
15
tests/Feature/SessionStoreControllerTest.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class SessionStoreControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_colour_preference_saved()
|
||||||
|
{
|
||||||
|
$response = $this->post('update-colour-scheme', ['css' => 'some.css']);
|
||||||
|
$response->assertJson(['status' => 'ok']);
|
||||||
|
}
|
||||||
|
}
|
39
tests/Feature/ShortURLsControllerTest.php
Normal file
39
tests/Feature/ShortURLsControllerTest.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class ShortURLsControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_short_domain_redirects_to_long_domain()
|
||||||
|
{
|
||||||
|
$response = $this->get('http://' . config('app.shorturl'));
|
||||||
|
$response->assertRedirect(config('app.url'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_short_domain_slashat_redirects_to_twitter()
|
||||||
|
{
|
||||||
|
$response = $this->get('http://' . config('app.shorturl') . '/@');
|
||||||
|
$response->assertRedirect('https://twitter.com/jonnybarnes');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_short_domain_slashplus_redirects_to_googleplus()
|
||||||
|
{
|
||||||
|
$response = $this->get('http://' . config('app.shorturl') . '/+');
|
||||||
|
$response->assertRedirect('https://plus.google.com/u/0/117317270900655269082/about');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_short_domain_slasht_redirects_to_long_domain_slash_notes()
|
||||||
|
{
|
||||||
|
$response = $this->get('http://' . config('app.shorturl') . '/t/E');
|
||||||
|
$response->assertRedirect(config('app.url') . '/notes/E');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_short_domain_slashb_redirects_to_long_domain_slash_blog()
|
||||||
|
{
|
||||||
|
$response = $this->get('http://' . config('app.shorturl') . '/b/1');
|
||||||
|
$response->assertRedirect(config('app.url') . '/blog/s/1');
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ class SwarmTest extends TestCase
|
||||||
{
|
{
|
||||||
use DatabaseTransactions, TestToken;
|
use DatabaseTransactions, TestToken;
|
||||||
|
|
||||||
public function test_faked_ownyourswarm_request()
|
public function test_faked_ownyourswarm_request_with_foursquare()
|
||||||
{
|
{
|
||||||
$response = $this->json(
|
$response = $this->json(
|
||||||
'POST',
|
'POST',
|
||||||
|
@ -42,11 +42,81 @@ class SwarmTest extends TestCase
|
||||||
$response
|
$response
|
||||||
->assertStatus(201)
|
->assertStatus(201)
|
||||||
->assertJson(['response' => 'created']);
|
->assertJson(['response' => 'created']);
|
||||||
|
$this->assertDatabaseHas('notes', [
|
||||||
|
'swarm_url' => 'https://www.swarmapp.com/checkin/abc'
|
||||||
|
]);
|
||||||
$this->assertDatabaseHas('places', [
|
$this->assertDatabaseHas('places', [
|
||||||
'external_urls' => '{"foursquare": "https://foursquare.com/v/123456"}'
|
'external_urls' => '{"foursquare": "https://foursquare.com/v/123456"}'
|
||||||
]);
|
]);
|
||||||
$this->assertDatabaseHas('notes', [
|
}
|
||||||
'swarm_url' => 'https://www.swarmapp.com/checkin/abc'
|
|
||||||
|
// this request would actually come from another client than OwnYourSwarm
|
||||||
|
public function test_faked_ownyourswarm_request_with_osm()
|
||||||
|
{
|
||||||
|
$response = $this->json(
|
||||||
|
'POST',
|
||||||
|
'api/post',
|
||||||
|
[
|
||||||
|
'type' => ['h-entry'],
|
||||||
|
'properties' => [
|
||||||
|
'published' => [\Carbon\Carbon::now()->toDateTimeString()],
|
||||||
|
'content' => [[
|
||||||
|
'value' => 'My first #checkin using Example Product',
|
||||||
|
'html' => 'My first #checkin using <a href="http://example.org">Example Product</a>',
|
||||||
|
]],
|
||||||
|
'checkin' => [[
|
||||||
|
'type' => ['h-card'],
|
||||||
|
'properties' => [
|
||||||
|
'name' => ['Awesome Venue'],
|
||||||
|
'url' => ['https://www.openstreetmap.org/way/123456'],
|
||||||
|
'latitude' => ['1.23'],
|
||||||
|
'longitude' => ['4.56'],
|
||||||
|
],
|
||||||
|
]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response
|
||||||
|
->assertStatus(201)
|
||||||
|
->assertJson(['response' => 'created']);
|
||||||
|
$this->assertDatabaseHas('places', [
|
||||||
|
'external_urls' => '{"osm": "https://www.openstreetmap.org/way/123456"}'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this request would actually come from another client than OwnYourSwarm
|
||||||
|
public function test_faked_ownyourswarm_request_without_known_external_url()
|
||||||
|
{
|
||||||
|
$response = $this->json(
|
||||||
|
'POST',
|
||||||
|
'api/post',
|
||||||
|
[
|
||||||
|
'type' => ['h-entry'],
|
||||||
|
'properties' => [
|
||||||
|
'published' => [\Carbon\Carbon::now()->toDateTimeString()],
|
||||||
|
'content' => [[
|
||||||
|
'value' => 'My first #checkin using Example Product',
|
||||||
|
'html' => 'My first #checkin using <a href="http://example.org">Example Product</a>',
|
||||||
|
]],
|
||||||
|
'checkin' => [[
|
||||||
|
'type' => ['h-card'],
|
||||||
|
'properties' => [
|
||||||
|
'name' => ['Awesome Venue'],
|
||||||
|
'url' => ['https://www.example.org/way/123456'],
|
||||||
|
'latitude' => ['1.23'],
|
||||||
|
'longitude' => ['4.56'],
|
||||||
|
],
|
||||||
|
]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response
|
||||||
|
->assertStatus(201)
|
||||||
|
->assertJson(['response' => 'created']);
|
||||||
|
$this->assertDatabaseHas('places', [
|
||||||
|
'external_urls' => '{"default": "https://www.example.org/way/123456"}'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use Lcobucci\JWT\Builder;
|
||||||
use App\Services\TokenService;
|
use App\Services\TokenService;
|
||||||
|
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||||
|
|
||||||
class TokenServiceTest extends TestCase
|
class TokenServiceTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -30,4 +32,29 @@ class TokenServiceTest extends TestCase
|
||||||
];
|
];
|
||||||
$this->assertSame($data, $validData);
|
$this->assertSame($data, $validData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException App\Exceptions\InvalidTokenException
|
||||||
|
* @expectedExceptionMessage Token failed validation
|
||||||
|
*/
|
||||||
|
public function test_token_with_different_singing_key_throws_exception()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'me' => 'https://example.org',
|
||||||
|
'client_id' => 'https://quill.p3k.io',
|
||||||
|
'scope' => 'post'
|
||||||
|
];
|
||||||
|
$signer = new Sha256();
|
||||||
|
$token = (new Builder())->set('me', $data['me'])
|
||||||
|
->set('client_id', $data['client_id'])
|
||||||
|
->set('scope', $data['scope'])
|
||||||
|
->set('date_issued', time())
|
||||||
|
->set('nonce', bin2hex(random_bytes(8)))
|
||||||
|
->sign($signer, 'r4ndomk3y')
|
||||||
|
->getToken();
|
||||||
|
|
||||||
|
$service = new TokenService();
|
||||||
|
$token = $service->validateToken($token);
|
||||||
|
dump($token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@ use Illuminate\Support\Facades\Queue;
|
||||||
|
|
||||||
class WebMentionsControllerTest extends TestCase
|
class WebMentionsControllerTest extends TestCase
|
||||||
{
|
{
|
||||||
|
public function test_get_endpoint()
|
||||||
|
{
|
||||||
|
$response = $this->get('/webmention');
|
||||||
|
$response->assertViewIs('webmention-endpoint');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test webmentions without source and target are rejected.
|
* Test webmentions without source and target are rejected.
|
||||||
*
|
*
|
||||||
|
|
22
tests/Unit/AddClientToDatabaseJobTest.php
Normal file
22
tests/Unit/AddClientToDatabaseJobTest.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\Jobs\AddClientToDatabase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class AddClientToDatabaseJobTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_job_adds_client()
|
||||||
|
{
|
||||||
|
$job = new AddClientToDatabase('https://example.org/client');
|
||||||
|
$job->handle();
|
||||||
|
$this->assertDatabaseHas('clients', [
|
||||||
|
'client_url' => 'https://example.org/client',
|
||||||
|
'client_name' => 'https://example.org/client',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
72
tests/Unit/ArticlesTest.php
Normal file
72
tests/Unit/ArticlesTest.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Article;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class ArticlesTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_sluggable_method()
|
||||||
|
{
|
||||||
|
$article = new Article();
|
||||||
|
$article->title = 'My Title';
|
||||||
|
$article->main = 'Content';
|
||||||
|
$article->save();
|
||||||
|
|
||||||
|
$this->assertEquals('my-title', $article->titleurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_markdown_conversion()
|
||||||
|
{
|
||||||
|
$article = new Article();
|
||||||
|
$article->main = 'Some *markdown*';
|
||||||
|
|
||||||
|
$this->assertEquals('<p>Some <em>markdown</em></p>'.PHP_EOL, $article->html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_time_attributes()
|
||||||
|
{
|
||||||
|
$article = Article::create([
|
||||||
|
'title' => 'Test',
|
||||||
|
'main' => 'test',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($article->w3c_time, $article->updated_at->toW3CString());
|
||||||
|
$this->assertEquals($article->tooltip_time, $article->updated_at->toRFC850String());
|
||||||
|
$this->assertEquals($article->human_time, $article->updated_at->diffForHumans());
|
||||||
|
$this->assertEquals($article->pubdate, $article->updated_at->toRSSString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_link_accessor()
|
||||||
|
{
|
||||||
|
$article = Article::create([
|
||||||
|
'title' => 'Test',
|
||||||
|
'main' => 'Test',
|
||||||
|
]);
|
||||||
|
$article->title = 'Test Title';
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'/blog/' . date('Y') . '/' . date('m') . '/test',
|
||||||
|
$article->link
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_date_scope()
|
||||||
|
{
|
||||||
|
$yearAndMonth = Article::date(date('Y'), date('m'))->get();
|
||||||
|
$this->assertTrue(count($yearAndMonth) === 1);
|
||||||
|
|
||||||
|
$monthDecember = Article::date(date('Y') - 1, 12)->get();
|
||||||
|
$this->assertTrue(count($monthDecember) === 0);
|
||||||
|
|
||||||
|
$monthNotDecember = Article::date(date('Y') - 1, 1)->get();
|
||||||
|
$this->assertTrue(count($monthNotDecember) === 0);
|
||||||
|
|
||||||
|
$emptyScope = Article::date()->get();
|
||||||
|
$this->assertTrue(count($emptyScope) === 1);
|
||||||
|
}
|
||||||
|
}
|
59
tests/Unit/BookmarksTest.php
Normal file
59
tests/Unit/BookmarksTest.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\HandlerStack;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
|
use App\Services\BookmarkService;
|
||||||
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
|
|
||||||
|
class BookmarksTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_screenshot_of_google()
|
||||||
|
{
|
||||||
|
$uuid = (new BookmarkService())->saveScreenshot('https://www.google.co.uk');
|
||||||
|
$this->assertTrue(file_exists(public_path() . '/assets/img/bookmarks/' . $uuid . '.png'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_archive_link_method()
|
||||||
|
{
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['Content-Location' => '/web/1234/example.org']),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
$url = (new BookmarkService())->getArchiveLink('https://example.org');
|
||||||
|
$this->assertEquals('/web/1234/example.org', $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException App\Exceptions\InternetArchiveException
|
||||||
|
*/
|
||||||
|
public function test_archive_link_method_archive_site_error_exception()
|
||||||
|
{
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(403),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
$url = (new BookmarkService())->getArchiveLink('https://example.org');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException App\Exceptions\InternetArchiveException
|
||||||
|
*/
|
||||||
|
public function test_archive_link_method_archive_site_no_location_exception()
|
||||||
|
{
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
$this->app->instance(Client::class, $client);
|
||||||
|
$url = (new BookmarkService())->getArchiveLink('https://example.org');
|
||||||
|
}
|
||||||
|
}
|
112
tests/Unit/DownloadWebMentionJobTest.php
Normal file
112
tests/Unit/DownloadWebMentionJobTest.php
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\HandlerStack;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
|
use App\Jobs\DownloadWebMention;
|
||||||
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class DownloadWebMentionJobTest extends TestCase
|
||||||
|
{
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
$this->delTree(storage_path('HTML/https'));
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_the_job_saves_html()
|
||||||
|
{
|
||||||
|
$this->assertFileNotExists(storage_path('HTML/https'));
|
||||||
|
$source = 'https://example.org/reply/1';
|
||||||
|
$html = <<<HTML
|
||||||
|
<div class="h-entry">
|
||||||
|
<a class="u-like-of" href=""></a>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$html = str_replace('href=""', 'href="' . config('app.url') . '/notes/A"', $html);
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['X-Foo' => 'Bar'], $html),
|
||||||
|
new Response(200, ['X-Foo' => 'Bar'], $html),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
|
||||||
|
$job = new DownloadWebMention($source);
|
||||||
|
$job->handle($client);
|
||||||
|
|
||||||
|
$this->assertFileExists(storage_path('HTML/https'));
|
||||||
|
|
||||||
|
$job->handle($client);
|
||||||
|
|
||||||
|
$this->assertFileNotExists(storage_path('HTML/https/example.org/reply') . '/1.' . date('Y-m-d') . '.backup');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_the_job_saves_html_and_backup()
|
||||||
|
{
|
||||||
|
$this->assertFileNotExists(storage_path('HTML/https'));
|
||||||
|
$source = 'https://example.org/reply/1';
|
||||||
|
$html = <<<HTML
|
||||||
|
<div class="h-entry">
|
||||||
|
<a class="u-like-of" href=""></a>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$html2 = <<<HTML
|
||||||
|
<div class="h-entry">
|
||||||
|
<a class="u-like-of" href=""></a>
|
||||||
|
<a class="u-repost-of" href=""></a>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$html = str_replace('href=""', 'href="' . config('app.url') . '/notes/A"', $html);
|
||||||
|
$html2 = str_replace('href=""', 'href="' . config('app.url') . '/notes/A"', $html2);
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['X-Foo' => 'Bar'], $html),
|
||||||
|
new Response(200, ['X-Foo' => 'Bar'], $html2),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
|
||||||
|
$job = new DownloadWebMention($source);
|
||||||
|
$job->handle($client);
|
||||||
|
|
||||||
|
$this->assertFileExists(storage_path('HTML/https'));
|
||||||
|
|
||||||
|
$job->handle($client);
|
||||||
|
|
||||||
|
$this->assertFileExists(storage_path('HTML/https/example.org/reply') . '/1.' . date('Y-m-d') . '.backup');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_an_index_html_file()
|
||||||
|
{
|
||||||
|
$this->assertFileNotExists(storage_path('HTML/https'));
|
||||||
|
$source = 'https://example.org/reply-one/';
|
||||||
|
$html = <<<HTML
|
||||||
|
<div class="h-entry">
|
||||||
|
<a class="u-like-of" href=""></a>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
$html = str_replace('href=""', 'href="' . config('app.url') . '/notes/A"', $html);
|
||||||
|
$mock = new MockHandler([
|
||||||
|
new Response(200, ['X-Foo' => 'Bar'], $html),
|
||||||
|
]);
|
||||||
|
$handler = HandlerStack::create($mock);
|
||||||
|
$client = new Client(['handler' => $handler]);
|
||||||
|
|
||||||
|
$job = new DownloadWebMention($source);
|
||||||
|
$job->handle($client);
|
||||||
|
|
||||||
|
$this->assertFileExists(storage_path('HTML/https/example.org/reply-one/index.html'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function delTree($dir) {
|
||||||
|
$files = array_diff(scandir($dir), array('.','..'));
|
||||||
|
foreach ($files as $file) {
|
||||||
|
(is_dir("$dir/$file")) ? $this->delTree("$dir/$file") : unlink("$dir/$file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
16
tests/Unit/LikesTest.php
Normal file
16
tests/Unit/LikesTest.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Like;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class LikesTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_setting_author_url()
|
||||||
|
{
|
||||||
|
$like = new Like();
|
||||||
|
$like->author_url = 'https://joe.bloggs/';
|
||||||
|
$this->assertEquals('https://joe.bloggs', $like->author_url);
|
||||||
|
}
|
||||||
|
}
|
16
tests/Unit/MediaTest.php
Normal file
16
tests/Unit/MediaTest.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Media;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class MediaTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_get_note_from_media()
|
||||||
|
{
|
||||||
|
$media = Media::find(1);
|
||||||
|
$note = $media->note;
|
||||||
|
$this->assertInstanceOf('App\Note', $note);
|
||||||
|
}
|
||||||
|
}
|
17
tests/Unit/MicropbClientsTest.php
Normal file
17
tests/Unit/MicropbClientsTest.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\MicropubClient;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
||||||
|
class MicropbClientsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_notes_relationship()
|
||||||
|
{
|
||||||
|
$client = MicropubClient::find(3);
|
||||||
|
$this->assertInstanceOf(Collection::class, $client->notes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,21 +2,23 @@
|
||||||
|
|
||||||
namespace Tests\Unit;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Tag;
|
||||||
use App\Note;
|
use App\Note;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use Thujohn\Twitter\Facades\Twitter;
|
||||||
|
|
||||||
class NotesTest extends TestCase
|
class NotesTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Test the getNoteAttribute method. This note will check the markdown,
|
* Test the getNoteAttribute method. This will then also call the
|
||||||
* emoji-a11y, and hashtag sub-methods.
|
* relevant sub-methods.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_get_note_attribute_method()
|
public function test_get_note_attribute_method()
|
||||||
{
|
{
|
||||||
$expected = '<p>Having a <a rel="tag" class="p-category" href="/notes/tagged/beer">#beer</a> at the local. <span role="img" aria-label="beer mug">🍺</span></p>' . PHP_EOL;
|
$expected = '<p>Having a <a rel="tag" class="p-category" href="/notes/tagged/beer">#beer</a> at the local. <span role="img" aria-label="beer mug">🍺</span></p>' . PHP_EOL;
|
||||||
$note = Note::find(11);
|
$note = Note::find(12);
|
||||||
$this->assertEquals($expected, $note->note);
|
$this->assertEquals($expected, $note->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ class NotesTest extends TestCase
|
||||||
public function test_default_image_used_in_makehcards_method()
|
public function test_default_image_used_in_makehcards_method()
|
||||||
{
|
{
|
||||||
$expected = '<p>Hi <span class="u-category h-card mini-h-card"><a class="u-url p-name" href="http://tantek.com">Tantek Çelik</a><span class="hovercard"> <a class="u-url" href="https://twitter.com/t"><img class="social-icon" src="/assets/img/social-icons/twitter.svg"> t</a><img class="u-photo" alt="" src="/assets/profile-images/default-image"></span></span></p>' . PHP_EOL;
|
$expected = '<p>Hi <span class="u-category h-card mini-h-card"><a class="u-url p-name" href="http://tantek.com">Tantek Çelik</a><span class="hovercard"> <a class="u-url" href="https://twitter.com/t"><img class="social-icon" src="/assets/img/social-icons/twitter.svg"> t</a><img class="u-photo" alt="" src="/assets/profile-images/default-image"></span></span></p>' . PHP_EOL;
|
||||||
$note = Note::find(12);
|
$note = Note::find(13);
|
||||||
$this->assertEquals($expected, $note->note);
|
$this->assertEquals($expected, $note->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +41,8 @@ class NotesTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function test_specific_profile_image_used_in_makehcards_method()
|
public function test_specific_profile_image_used_in_makehcards_method()
|
||||||
{
|
{
|
||||||
$expected = '<p>Hi <span class="u-category h-card mini-h-card"><a class="u-url p-name" href="https://aaronparecki.com">Aaron Parecki</a><span class="hovercard"><a class="u-url" href="https://www.facebook.com/123456"><img class="social-icon" src="/assets/img/social-icons/facebook.svg"> Facebook</a> <a class="u-url" href="https://twitter.com/aaronpk"><img class="social-icon" src="/assets/img/social-icons/twitter.svg"> aaronpk</a><img class="u-photo" alt="" src="/assets/profile-images/aaronparecki.com/image"></span></span></p>' . PHP_EOL;
|
$expected = '<p>Hi <span class="u-category h-card mini-h-card"><a class="u-url p-name" href="https://aaronparecki.com">Aaron Parecki</a><span class="hovercard"><a class="u-url" href="https://www.facebook.com/123456"><img class="social-icon" src="/assets/img/social-icons/facebook.svg"> Facebook</a> <img class="u-photo" alt="" src="/assets/profile-images/aaronparecki.com/image"></span></span></p>' . PHP_EOL;
|
||||||
$note = Note::find(13);
|
$note = Note::find(14);
|
||||||
$this->assertEquals($expected, $note->note);
|
$this->assertEquals($expected, $note->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +54,47 @@ class NotesTest extends TestCase
|
||||||
public function test_twitter_link_created_when_no_contact_found()
|
public function test_twitter_link_created_when_no_contact_found()
|
||||||
{
|
{
|
||||||
$expected = '<p>Hi <a href="https://twitter.com/bob">@bob</a></p>' . PHP_EOL;
|
$expected = '<p>Hi <a href="https://twitter.com/bob">@bob</a></p>' . PHP_EOL;
|
||||||
$note = Note::find(14);
|
$note = Note::find(15);
|
||||||
$this->assertEquals($expected, $note->note);
|
$this->assertEquals($expected, $note->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_shorturl_method()
|
||||||
|
{
|
||||||
|
$note = Note::find(14);
|
||||||
|
$this->assertEquals(config('app.shorturl') . '/notes/E', $note->shorturl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_latlng_of_associated_place()
|
||||||
|
{
|
||||||
|
$note = Note::find(12); // should be having beer at bridgewater note
|
||||||
|
$this->assertEquals('53.4983', $note->latitude);
|
||||||
|
$this->assertEquals('-2.3805', $note->longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_latlng_returns_null_otherwise()
|
||||||
|
{
|
||||||
|
$note = Note::find(5);
|
||||||
|
$this->assertNull($note->latitude);
|
||||||
|
$this->assertNull($note->longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_address_attribute_for_places()
|
||||||
|
{
|
||||||
|
$note = Note::find(12);
|
||||||
|
$this->assertEquals('The Bridgewater Pub', $note->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_deleting_event_observer()
|
||||||
|
{
|
||||||
|
// first we’ll create a temporary note to delete
|
||||||
|
$note = Note::create(['note' => 'temporary #temp']);
|
||||||
|
$this->assertDatabaseHas('tags', [
|
||||||
|
'tag' => 'temp',
|
||||||
|
]);
|
||||||
|
$tag = Tag::where('tag', 'temp')->first();
|
||||||
|
$note->forceDelete();
|
||||||
|
$this->assertDatabaseMissing('note_tag', [
|
||||||
|
'tag_id' => $tag->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,21 @@ namespace Tests\Unit;
|
||||||
|
|
||||||
use App\Place;
|
use App\Place;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use App\Services\PlaceService;
|
||||||
use Phaza\LaravelPostgis\Geometries\Point;
|
use Phaza\LaravelPostgis\Geometries\Point;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
class PlacesTest extends TestCase
|
class PlacesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_notes_method()
|
||||||
|
{
|
||||||
|
$place = Place::find(1);
|
||||||
|
$this->assertInstanceOf(Collection::class, $place->notes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the near method returns a collection.
|
* Test the near method returns a collection.
|
||||||
*
|
*
|
||||||
|
@ -18,4 +29,67 @@ class PlacesTest extends TestCase
|
||||||
$nearby = Place::near(new Point(53.5, -2.38), 1000)->get();
|
$nearby = Place::near(new Point(53.5, -2.38), 1000)->get();
|
||||||
$this->assertEquals('the-bridgewater-pub', $nearby[0]->slug);
|
$this->assertEquals('the-bridgewater-pub', $nearby[0]->slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_longurl_method()
|
||||||
|
{
|
||||||
|
$place = Place::find(1);
|
||||||
|
$this->assertEquals(config('app.url') . '/places/the-bridgewater-pub', $place->longurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_uri_method()
|
||||||
|
{
|
||||||
|
$place = Place::find(1);
|
||||||
|
$this->assertEquals(config('app.url') . '/places/the-bridgewater-pub', $place->uri);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_shorturl_method()
|
||||||
|
{
|
||||||
|
$place = Place::find(1);
|
||||||
|
$this->assertEquals(config('app.shorturl') . '/places/the-bridgewater-pub', $place->shorturl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_service_returns_existing_place()
|
||||||
|
{
|
||||||
|
$place = new Place();
|
||||||
|
$place->name = 'Temp Place';
|
||||||
|
$place->location = new Point(37.422009, -122.084047);
|
||||||
|
$place->external_urls = 'https://www.openstreetmap.org/way/1234';
|
||||||
|
$place->save();
|
||||||
|
$service = new PlaceService();
|
||||||
|
$ret = $service->createPlaceFromCheckin([
|
||||||
|
'properties' => [
|
||||||
|
'url' => ['https://www.openstreetmap.org/way/1234'],
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$this->assertInstanceOf('App\Place', $ret); // a place was returned
|
||||||
|
$this->assertEquals(2, count(Place::all())); // still 2 places
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Missing required name
|
||||||
|
*/
|
||||||
|
public function test_service_requires_name()
|
||||||
|
{
|
||||||
|
$service = new PlaceService();
|
||||||
|
$service->createPlaceFromCheckin(['foo' => 'bar']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Missing required longitude/latitude
|
||||||
|
*/
|
||||||
|
public function test_service_requires_latitude()
|
||||||
|
{
|
||||||
|
$service = new PlaceService();
|
||||||
|
$service->createPlaceFromCheckin(['properties' => ['name' => 'bar']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_updating_external_urls()
|
||||||
|
{
|
||||||
|
$place = Place::find(1);
|
||||||
|
$place->external_urls = 'https://bridgewater.pub';
|
||||||
|
$this->assertEquals('{"osm":"https:\/\/www.openstreetmap.org\/way\/987654","foursquare":"https:\/\/foursquare.com\/v\/123435\/the-bridgewater-pub","default":"https:\/\/bridgewater.pub"}', $place->external_urls);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
60
tests/Unit/ProcessBookmarkJobTest.php
Normal file
60
tests/Unit/ProcessBookmarkJobTest.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Bookmark;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\HandlerStack;
|
||||||
|
use App\Jobs\ProcessBookmark;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
|
use App\Services\BookmarkService;
|
||||||
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
|
use App\Exceptions\InternetArchiveException;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class ProcessBookmarkJobTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_screenshot_and_archive_link_are_saved()
|
||||||
|
{
|
||||||
|
$bookmark = Bookmark::find(1);
|
||||||
|
$uuid = Uuid::uuid4();
|
||||||
|
$service = $this->createMock(BookmarkService::class);
|
||||||
|
$service->method('saveScreenshot')
|
||||||
|
->willReturn($uuid->toString());
|
||||||
|
$service->method('getArchiveLink')
|
||||||
|
->willReturn('https://web.archive.org/web/1234');
|
||||||
|
$this->app->instance(BookmarkService::class, $service);
|
||||||
|
|
||||||
|
$job = new ProcessBookmark($bookmark);
|
||||||
|
$job->handle();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('bookmarks', [
|
||||||
|
'screenshot' => $uuid->toString(),
|
||||||
|
'archive' => 'https://web.archive.org/web/1234',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_exception_casesu_null_value_for_archive_link()
|
||||||
|
{
|
||||||
|
$bookmark = Bookmark::find(1);
|
||||||
|
$uuid = Uuid::uuid4();
|
||||||
|
$service = $this->createMock(BookmarkService::class);
|
||||||
|
$service->method('saveScreenshot')
|
||||||
|
->willReturn($uuid->toString());
|
||||||
|
$service->method('getArchiveLink')
|
||||||
|
->will($this->throwException(new InternetArchiveException));
|
||||||
|
$this->app->instance(BookmarkService::class, $service);
|
||||||
|
|
||||||
|
$job = new ProcessBookmark($bookmark);
|
||||||
|
$job->handle();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('bookmarks', [
|
||||||
|
'screenshot' => $uuid->toString(),
|
||||||
|
'archive' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
use Storage;
|
use Storage;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use App\Jobs\ProcessMedia;
|
||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
|
|
||||||
class ProcessImageTest extends TestCase
|
class ProcessMediaJobTest extends TestCase
|
||||||
{
|
{
|
||||||
public function test_job_does_nothing_to_non_image()
|
public function test_job_does_nothing_to_non_image()
|
||||||
{
|
{
|
||||||
|
Storage::fake('s3');
|
||||||
$manager = app()->make(ImageManager::class);
|
$manager = app()->make(ImageManager::class);
|
||||||
Storage::disk('local')->put('file.txt', 'This is not an image');
|
Storage::disk('local')->put('file.txt', 'This is not an image');
|
||||||
$job = new \App\Jobs\ProcessImage('file.txt');
|
$job = new ProcessMedia('file.txt');
|
||||||
$job->handle($manager);
|
$job->handle($manager);
|
||||||
|
|
||||||
$this->assertFalse(file_exists(storage_path('app') . '/file.txt'));
|
$this->assertFalse(file_exists(storage_path('app') . '/file.txt'));
|
||||||
|
@ -20,9 +22,10 @@ class ProcessImageTest extends TestCase
|
||||||
|
|
||||||
public function test_job_does_nothing_to_small_images()
|
public function test_job_does_nothing_to_small_images()
|
||||||
{
|
{
|
||||||
|
Storage::fake('s3');
|
||||||
$manager = app()->make(ImageManager::class);
|
$manager = app()->make(ImageManager::class);
|
||||||
Storage::disk('local')->put('aaron.png', file_get_contents(__DIR__.'/../aaron.png'));
|
Storage::disk('local')->put('aaron.png', file_get_contents(__DIR__.'/../aaron.png'));
|
||||||
$job = new \App\Jobs\ProcessImage('aaron.png');
|
$job = new ProcessMedia('aaron.png');
|
||||||
$job->handle($manager);
|
$job->handle($manager);
|
||||||
|
|
||||||
$this->assertFalse(file_exists(storage_path('app') . '/aaron.png'));
|
$this->assertFalse(file_exists(storage_path('app') . '/aaron.png'));
|
||||||
|
@ -33,7 +36,7 @@ class ProcessImageTest extends TestCase
|
||||||
$manager = app()->make(ImageManager::class);
|
$manager = app()->make(ImageManager::class);
|
||||||
Storage::disk('local')->put('test-image.jpg', file_get_contents(__DIR__.'/../test-image.jpg'));
|
Storage::disk('local')->put('test-image.jpg', file_get_contents(__DIR__.'/../test-image.jpg'));
|
||||||
Storage::fake('s3');
|
Storage::fake('s3');
|
||||||
$job = new \App\Jobs\ProcessImage('test-image.jpg');
|
$job = new ProcessMedia('test-image.jpg');
|
||||||
$job->handle($manager);
|
$job->handle($manager);
|
||||||
|
|
||||||
Storage::disk('s3')->assertExists('media/test-image-small.jpg');
|
Storage::disk('s3')->assertExists('media/test-image-small.jpg');
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue