-1) {
18 | domain = url.split('/')[2];
19 | } else {
20 | domain = url.split('/')[0];
21 | }
22 | //find & remove port number
23 | domain = domain.split(':')[0];
24 | return window.location.protocol + '//' + domain + '/';
25 | }
26 |
27 | var bookmarkMeText = '';
28 | bookmarkMeText += '(';
29 | bookmarkMeText += ' function() {';
30 | bookmarkMeText += ' l="' + extractDomain(window.location.href) + '#/bookmark/add?title="+encodeURIComponent(document.title)+"&link="+encodeURIComponent(window.location.href);';
31 | bookmarkMeText += ' var e=window.open(l+"&window=1","EasyBookmarkManager","location=0,links=0,scrollbars=0,toolbar=0,width=594,height=600");';
32 | bookmarkMeText += ' }';
33 | bookmarkMeText += ')()';
34 |
35 | $('a.bookmark-me-link').attr('href', 'javascript:' + encodeURIComponent(bookmarkMeText));
36 | }
37 |
38 | generateBookmarkMe();
39 | });
40 |
--------------------------------------------------------------------------------
/resources/assets/js/routes.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var routes = function ($routeProvider, $locationProvider) {
4 | $routeProvider.
5 | when('/', {
6 | templateUrl: '/views/bookmark-view.html',
7 | controller: 'bookmarkViewController'
8 | }).
9 | when('/bookmark/edit/:bookmarkId', {
10 | templateUrl: '/views/bookmark-edit.html',
11 | controller: 'bookmarkEditController'
12 | }).
13 | when('/bookmark/add', {
14 | templateUrl: '/views/bookmark-edit.html',
15 | controller: 'bookmarkEditController'
16 | }).
17 | when('/user/edit', {
18 | templateUrl: '/views/user-edit.html',
19 | controller: 'userEditController'
20 | }).
21 | otherwise({
22 | redirectTo: '/login'
23 | });
24 |
25 | // reverting back to no prefix in url (somehow defaulted to using ! e.g. /#!/bookmark/add)
26 | $locationProvider.hashPrefix('');
27 |
28 | // use the HTML5 History API
29 | $locationProvider.html5Mode(false);
30 | };
31 |
32 | angular.module('bookmarksApp')
33 | .config(['$routeProvider', '$locationProvider', routes]);
34 |
35 | }());
36 |
--------------------------------------------------------------------------------
/resources/assets/js/sessionService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var sessionService = function () {
4 |
5 | var service = {
6 |
7 | model: {
8 | theme: '',
9 | search: '',
10 | pageNo: 1
11 | },
12 |
13 | setModel: function (data) {
14 | this.model = data;
15 | },
16 |
17 | getModel: function () {
18 | return this.model;
19 | },
20 |
21 | clearModel: function () {
22 | this.model = {
23 | theme: '',
24 | search: '',
25 | pageNo: 1
26 | };
27 | }
28 |
29 | };
30 |
31 | return service;
32 |
33 | };
34 |
35 | angular.module('bookmarksApp')
36 | .service('sessionService', [sessionService]);
37 |
38 | }());
39 |
--------------------------------------------------------------------------------
/resources/assets/js/translation.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | angular.module('bookmarksApp')
4 | .config(['$translateProvider', function ($translateProvider) {
5 |
6 | var availableLanguages = [ "en", "fr" ];
7 |
8 | // we used a native language detector approach as some browsers like Edge and IE
9 | // return en-EN instead of en on Firefox or Chrome
10 |
11 | var userLang = navigator.language || navigator.userLanguage;
12 | userLang = userLang.split('-')[0];
13 |
14 | // if not in available languages, default to english.
15 | if (availableLanguages.indexOf(userLang) == -1) {
16 | userLang = 'en';
17 | }
18 |
19 | $translateProvider.useUrlLoader('/lang/' + userLang + '.json');
20 | $translateProvider.useSanitizeValueStrategy(null);
21 | $translateProvider.preferredLanguage(userLang);
22 |
23 | }]);
24 |
25 | }());
26 |
--------------------------------------------------------------------------------
/resources/assets/js/userEditController.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var userEditController = function ($scope, $location, $http, $interval, userService, $filter) {
4 |
5 | $scope.errorMessage = '';
6 | $scope.goodMessage = '';
7 | $scope.busyWithAction = true;
8 |
9 | $scope.profile = {
10 | name: '',
11 | email: '',
12 | theme: '',
13 | password1: '',
14 | password2: ''
15 | };
16 |
17 | var theme = localStorage.getItem('theme') || 'bootstrap-yeti';
18 | $scope.profile.theme = theme;
19 |
20 | userService
21 | .getDetails()
22 | .then(function (response) {
23 | $scope.busyWithAction = false;
24 | if (response.result != 'ok') {
25 | $scope.errorMessage = response.message;
26 | return;
27 | }
28 | $scope.profile.name = response.data.user.name;
29 | $scope.profile.email = response.data.user.email;
30 | });
31 |
32 | $scope.updateUser = function () {
33 | $scope.errorMessage = '';
34 | $scope.goodMessage = '';
35 |
36 | if ($scope.profile.password1.length > 0) {
37 | if ($scope.profile.password1.length < 5) {
38 | $scope.errorMessage = $filter('translate')('message.password.length');
39 | return;
40 | }
41 | if ($scope.profile.password1.search(/[a-z]/i) < 0) {
42 | $scope.errorMessage = $filter('translate')('message.password.oneLetter');
43 | return;
44 | }
45 | if ($scope.profile.password1.search(/[0-9]/) < 0) {
46 | $scope.errorMessage = $filter('translate')('message.password.oneDigit');
47 | return;
48 | }
49 | if ($scope.profile.password1 != $scope.profile.password2) {
50 | $scope.errorMessage = $filter('translate')('message.password.match');
51 | return;
52 | }
53 | }
54 |
55 | $scope.busyWithAction = true;
56 |
57 | userService
58 | .updateDetails($scope.profile)
59 | .then(function (response) {
60 | $scope.busyWithAction = false;
61 | if (response.result != 'ok') {
62 | $scope.errorMessage = response.message;
63 | return;
64 | }
65 | $scope.goodMessage = $filter('translate')('message.password.updated');
66 | $scope.profile.password1 = '';
67 | $scope.profile.password2 = '';
68 | });
69 | };
70 |
71 | $scope.changeTheme = function (item) {
72 | localStorage.setItem('theme', item);
73 | $scope.profile.theme = item;
74 | $('.custom-css').remove();
75 | loadTheme();
76 | };
77 |
78 | $scope.cancelUpdate = function () {
79 | $scope.busyWithAction = true;
80 | $location.path('/');
81 | };
82 | };
83 |
84 | angular.module('bookmarksApp')
85 | .controller('userEditController',
86 | ['$scope', '$location', '$http', '$interval', 'userService', '$filter', userEditController]);
87 |
88 | }());
89 |
--------------------------------------------------------------------------------
/resources/assets/js/userService.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var userService = function ($location, $http) {
4 |
5 | var service = {
6 |
7 | getDetails: function () {
8 | return $http
9 | .get(API_URL + 'user')
10 | .then(function (response) {
11 | return response.data;
12 | });
13 | },
14 |
15 | updateDetails: function (data) {
16 | return $http
17 | .put(API_URL + 'user?' + $.param(data))
18 | .then(function (response) {
19 | return response.data;
20 | });
21 | },
22 |
23 | checkLoginStatus: function () {
24 | return $http
25 | .get(API_URL + 'user/status?')
26 | .then(function (response) {
27 | return response.data;
28 | });
29 | }
30 | };
31 |
32 | return service;
33 |
34 | };
35 |
36 | angular.module('bookmarksApp')
37 | .service('userService', ['$location', '$http', userService]);
38 |
39 | }());
40 |
--------------------------------------------------------------------------------
/resources/assets/sass/main.scss:
--------------------------------------------------------------------------------
1 | @import "partials/bs-callout";
2 | @import "partials/angucomplete";
3 | @import "partials/tags";
4 | @import "partials/tag-cloud";
5 | @import "partials/code-pre-tags";
6 |
7 | body {
8 | overflow-x:hidden;
9 | }
10 |
11 | .highlight {
12 | color: #ff0000;
13 | }
14 |
15 | .bookmark-me-link, .bookmark-me-link:hover, .bookmark-me-link:link, .bookmark-me-link:visited, .bookmark-me-link:active {
16 | text-decoration: none;
17 | }
18 |
19 | .li-item-selected {
20 | font-weight: bold;
21 | }
22 |
23 | .click-item {
24 | cursor: pointer;
25 | }
26 |
27 | .edit-bookmark {
28 | padding: 15px 20px;
29 | cursor: pointer;
30 | position: absolute;
31 | top: 0;
32 | right: 0;
33 | height: 100%;
34 | }
35 |
36 | .btn-file {
37 | position: relative;
38 | overflow: hidden;
39 | }
40 |
41 | .btn-file input[type=file] {
42 | position: absolute;
43 | top: 0;
44 | right: 0;
45 | min-width: 100%;
46 | min-height: 100%;
47 | font-size: 100px;
48 | text-align: right;
49 | filter: alpha(opacity=0);
50 | opacity: 0;
51 | outline: none;
52 | background: white;
53 | cursor: inherit;
54 | display: block;
55 | }
56 |
57 | .prev-next {
58 | padding-bottom: 8px;
59 | }
60 |
61 | .prev-next-pages {
62 | margin-right: 18px;
63 | margin-top: 7px;
64 | }
65 |
66 | .ace_editor {
67 | height : 200px;
68 | }
69 |
70 | #search-clear {
71 | position: absolute;
72 | right: 10px;
73 | top: 0;
74 | bottom: 0;
75 | height: 18px;
76 | margin: auto;
77 | font-size: 18px;
78 | cursor: pointer;
79 | color: #bbb;
80 | }
81 |
82 | .li-hidden {
83 | display:none;
84 | }
85 |
86 | .tag-item {
87 | font-weight: normal;
88 | }
89 |
90 | .ace-snippet-container {
91 | padding:0;
92 |
93 | &.list {
94 | padding: 10px 0;
95 | }
96 | }
97 |
98 | .logged-in-user {
99 | float: right;
100 | font-size: 0.37em;
101 | line-height: 1.8em;
102 | margin: 10px 0 0 20px;
103 | /* text-align: right; */
104 | /* position: relative; */
105 | /* top: 14px; */
106 | /* right: 0px; */
107 | /* width: 300px; */
108 | /* display: block; */
109 | /* overflow-x: hidden; */
110 | /* margin: 0.5em 0 0 30px; */
111 | }
112 |
--------------------------------------------------------------------------------
/resources/assets/sass/partials/angucomplete.scss:
--------------------------------------------------------------------------------
1 | .angucomplete-holder {
2 | position: relative;
3 | }
4 |
5 | .angucomplete-dropdown {
6 | border-color: #ececec;
7 | border-width: 1px;
8 | border-style: solid;
9 | border-radius: 2px;
10 | width: 250px;
11 | padding: 6px;
12 | cursor: pointer;
13 | z-index: 9999;
14 | position: absolute;
15 | /*top: 32px;
16 | left: 0px;
17 | */
18 | margin-top: -6px;
19 | background-color: #ffffff;
20 | }
21 |
22 | .angucomplete-searching {
23 | color: #acacac;
24 | font-size: 14px;
25 | }
26 |
27 | .angucomplete-description {
28 | font-size: 14px;
29 | }
30 |
31 | .angucomplete-row {
32 | padding: 5px;
33 | color: #000000;
34 | margin-bottom: 4px;
35 | clear: both;
36 | }
37 |
38 | .angucomplete-selected-row {
39 | background-color: lightblue;
40 | color: #ffffff;
41 | }
42 |
43 | .angucomplete-image-holder {
44 | padding-top: 2px;
45 | float: left;
46 | margin-right: 10px;
47 | margin-left: 5px;
48 | }
49 |
50 | .angucomplete-image {
51 | height: 34px;
52 | width: 34px;
53 | border-radius: 50%;
54 | border-color: #ececec;
55 | border-style: solid;
56 | border-width: 1px;
57 | }
58 |
59 | .angucomplete-image-default {
60 | /* Add your own default image here
61 | background-image: url('/assets/default.png');
62 | */
63 | background-position: center;
64 | background-size: contain;
65 | height: 34px;
66 | width: 34px;
67 | }
68 |
--------------------------------------------------------------------------------
/resources/assets/sass/partials/bs-callout.scss:
--------------------------------------------------------------------------------
1 | .bs-callout {
2 | padding: 20px;
3 | margin: 20px 0;
4 | border: 1px solid #eee;
5 | border-left-width: 5px;
6 | border-radius: 3px;
7 | }
8 |
9 | .bs-callout h4 {
10 | margin-top: 0;
11 | margin-bottom: 5px;
12 | }
13 |
14 | .bs-callout p:last-child {
15 | margin-bottom: 0;
16 | }
17 |
18 | .bs-callout code {
19 | border-radius: 3px;
20 | }
21 |
22 | .bs-callout + .bs-callout {
23 | margin-top: -5px;
24 | }
25 |
26 | .bs-callout-default {
27 | border-left-color: #777;
28 | }
29 |
30 | .bs-callout-default h4 {
31 | color: #777;
32 | }
33 |
34 | .bs-callout-primary {
35 | border-left-color: #428bca;
36 | }
37 |
38 | .bs-callout-primary h4 {
39 | color: #428bca;
40 | }
41 |
42 | .bs-callout-success {
43 | border-left-color: #5cb85c;
44 | }
45 |
46 | .bs-callout-success h4 {
47 | color: #5cb85c;
48 | }
49 |
50 | .bs-callout-danger {
51 | border-left-color: #d9534f;
52 | }
53 |
54 | .bs-callout-danger h4 {
55 | color: #d9534f;
56 | }
57 |
58 | .bs-callout-warning {
59 | border-left-color: #f0ad4e;
60 | }
61 |
62 | .bs-callout-warning h4 {
63 | color: #f0ad4e;
64 | }
65 |
66 | .bs-callout-info {
67 | border-left-color: #5bc0de;
68 | }
69 |
70 | .bs-callout-info h4 {
71 | color: #5bc0de;
72 | }
73 |
74 | .custom-bs-callout {
75 | padding: 10px;
76 | margin: 10px 5px;
77 | position: relative;
78 | }
79 |
80 | .bs-callout h4 {
81 | margin-right: 44px;
82 | }
83 |
--------------------------------------------------------------------------------
/resources/assets/sass/partials/code-pre-tags.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Code borrowed from @link https://perishablepress.com/perfect-pre-tags/
3 | */
4 |
5 | code, samp, kbd {
6 | font-family: "Courier New", Courier, monospace, sans-serif;
7 | text-align: left;
8 | color: #555;
9 | }
10 | pre code {
11 | line-height: 1.6em;
12 | font-size: 11px;
13 | }
14 | pre {
15 | padding: 0.1em 0.5em 0.3em 0.7em;
16 | border-left: 11px solid #ccc;
17 | margin: 1.7em 0 1.7em 0.3em;
18 | overflow: auto;
19 | width: 93%;
20 | }
21 | /* target IE7 and IE6 */
22 | *:first-child+html pre {
23 | padding-bottom: 2em;
24 | overflow-y: hidden;
25 | overflow: visible;
26 | overflow-x: auto;
27 | }
28 | * html pre {
29 | padding-bottom: 2em;
30 | overflow: visible;
31 | overflow-x: auto;
32 | }
33 |
--------------------------------------------------------------------------------
/resources/assets/sass/partials/tag-cloud.scss:
--------------------------------------------------------------------------------
1 | #tagcloud ul {
2 | margin: 1em 0;
3 | padding: .5em 10px;
4 | text-align: center;
5 | /*background-color:#71b5e9;*/
6 | }
7 |
8 | #tagcloud li {
9 | margin: 0;
10 | padding: 0;
11 | list-style: none;
12 | display: inline;
13 | }
14 |
15 | #tagcloud li a {
16 | text-decoration: none;
17 | /*color:#fff;*/
18 | padding: 0 2px;
19 | }
20 |
21 | #tagcloud li a:hover {
22 | color: #cff400;
23 | }
24 |
25 | .tag1 {
26 | font-size: 100%;
27 | }
28 |
29 | .tag2 {
30 | font-size: 120%;
31 | }
32 |
33 | .tag3 {
34 | font-size: 140%;
35 | }
36 |
37 | .tag4 {
38 | font-size: 160%;
39 | }
40 |
41 | .tag5 {
42 | font-size: 180%;
43 | }
44 |
45 | .tag6 {
46 | font-size: 200%;
47 | }
48 |
49 | .tag7 {
50 | font-size: 220%;
51 | }
52 |
53 | .tag8 {
54 | font-size: 240%;
55 | }
56 |
57 | .tag9 {
58 | font-size: 260%;
59 | }
60 |
61 | .tag10 {
62 | font-size: 280%;
63 | }
64 |
--------------------------------------------------------------------------------
/resources/assets/sass/partials/tags.scss:
--------------------------------------------------------------------------------
1 | .tags {
2 | padding: 4px 0;
3 | }
4 |
5 | .tags .tag {
6 | border-radius: 10px;
7 | padding: 6px 4px 6px 8px;
8 | background-color: #EFEFEF;
9 | margin-right: 10px;
10 | line-height: 32px;
11 | }
12 |
13 | .tags .tag:hover {
14 | color: red;
15 | text-decoration: none;
16 | }
17 |
18 | .tags input {
19 | width: 80px;
20 | border: none;
21 | }
22 |
23 | .tag-item {
24 | margin-right: 1px;
25 | }
26 |
--------------------------------------------------------------------------------
/resources/assets/views/bookmark-edit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Oh snap! {{ globalErrorMessage }}
7 |
8 |
9 |
10 | Success! {{ globalGoodMessage }}
11 |
12 |
13 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/resources/assets/views/bookmark-view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ 'message.error' | translate }} {{ globalErrorMessage }}
7 |
8 |
9 |
10 | {{ 'message.success' | translate }} {{ globalGoodMessage }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ 'bookmark.categories' | translate }}
19 |
20 |
21 |
22 |
26 | {{category.name}}
27 | {{category.count}}
28 |
29 |
30 |
35 | load more...
36 |
37 |
38 |
39 |
40 |
41 |
42 | {{'bookmark.tags' | translate }}
43 |
44 |
45 |
57 |
58 |
59 |
60 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Loading
108 |
109 |
110 |
113 |
129 |
130 |
135 |
136 |
137 | {{ tag }}
138 |
139 |
140 |
141 |
142 |
144 | Previous
145 |
146 |
147 |
Next
150 |
151 |
152 |
{{
154 | bookmarkResults.page
155 | }} / {{ bookmarkResults.maxPages }}
156 |
157 |
158 |
159 | {{ 'bookmarks.nodata' | translate }}
160 |
161 |
162 |
163 | {{ badDataResponse }}
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/resources/assets/views/hero.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/resources/assets/views/tagmanager-directive.html:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/resources/assets/views/user-edit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
93 |
--------------------------------------------------------------------------------
/resources/lang/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "update": "Update user",
4 | "logout": "Logout",
5 | "loggedin": "Logged in as {{user}}",
6 | "useradmin": "User admin"
7 | },
8 | "export.bookmarks": "Export bookmarks",
9 | "import.bookmarks": "Import bookmarks",
10 | "new.bookmark": "New bookmark",
11 | "search.bookmark": "Refine search",
12 | "bookmarks.nodata": "no data found, try clicking on some filters",
13 | "bookmark": {
14 | "title": "Title",
15 | "link": "Link",
16 | "category": "Category",
17 | "categories": "Categories",
18 | "save": "Save",
19 | "create": "Create",
20 | "update": "Update",
21 | "saveandclose": "Save and close",
22 | "delete": "Delete",
23 | "close": "Close",
24 | "back": "Back",
25 | "enable": "Enable",
26 | "cancel": "Cancel",
27 | "search": "Search categories",
28 | "tagsPlaceholder": "Add tags",
29 | "favourite": "Favourite",
30 | "tag": "Tag",
31 | "tags": "Tags"
32 | },
33 | "message": {
34 | "error": "Oh snap!",
35 | "success": "Success",
36 | "password": {
37 | "length": "Your new password must be at least 5 characters",
38 | "oneLetter": "Your new password must contain at least 1 letter",
39 | "oneDigit": "Your new password must contain at least 1 digit",
40 | "match": "Both passwords must match",
41 | "updated": "Details updated"
42 | },
43 | "bookmark": {
44 | "delete": "Deleted, redirecting...",
45 | "create": "Created, closing...",
46 | "import": "Imported {{count}} record(s), reloading..."
47 | },
48 | "session": "No session found, please login via the browser"
49 | },
50 | "settings": {
51 | "name": "Name",
52 | "login": "Email/Login",
53 | "theme": "Theme",
54 | "password": "New password",
55 | "confirm": "Re-type new password"
56 | },
57 | "auth": {
58 | "failed": "These credentials do not match our records.",
59 | "throttle": "Too many login attempts. Please try again in :seconds seconds."
60 | },
61 | "messages": {
62 | "loginCombo": "That username\/password combo does not exist.",
63 | "userNameRequired": "The email field is required.",
64 | "usernameEmail": "The email must be a valid email address.",
65 | "usernameUnique": "The email has already been taken.",
66 | "user.add": "Add user",
67 | "user.edit": "Edit user",
68 | "edit": "Edit",
69 | "create": "Create",
70 | "delete": "Delete",
71 | "logout": "Logout",
72 | "loggedin": "logged in",
73 | "back": "Back",
74 | "save": "Save",
75 | "signin": "Sign in",
76 | "notConfirmed": "Your account has not been confirmed",
77 | "bookmark": {
78 | "notFound": "Could not retrieve the item."
79 | },
80 | "upload": {
81 | "error": "There was a problem with uploading the file."
82 | },
83 | "user": {
84 | "noSession": "No user sessions found.",
85 | "sessionReached": "Active session limit reached. Please logout to clean out session tokens.",
86 | "admin": "User Administration",
87 | "name": "Name",
88 | "mail": "Email \/ Login",
89 | "created": "Created",
90 | "adminRole": "Admin",
91 | "password": "Password",
92 | "confirm": "Confirm Password",
93 | "isAdmin": "Administrator",
94 | "register": "Register"
95 | },
96 | "password": {
97 | "match": "Both passwords must match."
98 | },
99 | "account": {
100 | "welcome": "Thanks to register on Easy Bookmark Manager.",
101 | "confirm": "You have to confirm your account clicking on this link",
102 | "confirmLink": "Account confirmation",
103 | "validated": "Your account has been validated !",
104 | "validationMessage": "Check your mail box to validate your account"
105 | },
106 | "yes": "yes"
107 | },
108 | "pagination": {
109 | "previous": "« Previous",
110 | "next": "Next »"
111 | },
112 | "passwords": {
113 | "password": "Passwords must be at least six characters and match the confirmation.",
114 | "reset": "Your password has been reset!",
115 | "sent": "We have e-mailed your password reset link!",
116 | "token": "This password reset token is invalid.",
117 | "user": "We can't find a user with that e-mail address."
118 | },
119 | "validation": {
120 | "accepted": "The :attribute must be accepted.",
121 | "active_url": "The :attribute is not a valid URL.",
122 | "after": "The :attribute must be a date after :date.",
123 | "alpha": "The :attribute may only contain letters.",
124 | "alpha_dash": "The :attribute may only contain letters, numbers, and dashes.",
125 | "alpha_num": "The :attribute may only contain letters and numbers.",
126 | "array": "The :attribute must be an array.",
127 | "before": "The :attribute must be a date before :date.",
128 | "between": {
129 | "numeric": "The :attribute must be between :min and :max.",
130 | "file": "The :attribute must be between :min and :max kilobytes.",
131 | "string": "The :attribute must be between :min and :max characters.",
132 | "array": "The :attribute must have between :min and :max items."
133 | },
134 | "boolean": "The :attribute field must be true or false.",
135 | "confirmed": "The :attribute confirmation does not match.",
136 | "date": "The :attribute is not a valid date.",
137 | "date_format": "The :attribute does not match the format :format.",
138 | "different": "The :attribute and :other must be different.",
139 | "digits": "The :attribute must be :digits digits.",
140 | "digits_between": "The :attribute must be between :min and :max digits.",
141 | "email": "The :attribute must be a valid email address.",
142 | "exists": "The selected :attribute is invalid.",
143 | "filled": "The :attribute field is required.",
144 | "image": "The :attribute must be an image.",
145 | "in": "The selected :attribute is invalid.",
146 | "integer": "The :attribute must be an integer.",
147 | "ip": "The :attribute must be a valid IP address.",
148 | "json": "The :attribute must be a valid JSON string.",
149 | "max": {
150 | "numeric": "The :attribute may not be greater than :max.",
151 | "file": "The :attribute may not be greater than :max kilobytes.",
152 | "string": "The :attribute may not be greater than :max characters.",
153 | "array": "The :attribute may not have more than :max items."
154 | },
155 | "mimes": "The :attribute must be a file of type: :values.",
156 | "min": {
157 | "numeric": "The :attribute must be at least :min.",
158 | "file": "The :attribute must be at least :min kilobytes.",
159 | "string": "The :attribute must be at least :min characters.",
160 | "array": "The :attribute must have at least :min items."
161 | },
162 | "not_in": "The selected :attribute is invalid.",
163 | "numeric": "The :attribute must be a number.",
164 | "regex": "The :attribute format is invalid.",
165 | "required": "The :attribute field is required.",
166 | "required_if": "The :attribute field is required when :other is :value.",
167 | "required_unless": "The :attribute field is required unless :other is in :values.",
168 | "required_with": "The :attribute field is required when :values is present.",
169 | "required_with_all": "The :attribute field is required when :values is present.",
170 | "required_without": "The :attribute field is required when :values is not present.",
171 | "required_without_all": "The :attribute field is required when none of :values are present.",
172 | "same": "The :attribute and :other must match.",
173 | "size": {
174 | "numeric": "The :attribute must be :size.",
175 | "file": "The :attribute must be :size kilobytes.",
176 | "string": "The :attribute must be :size characters.",
177 | "array": "The :attribute must contain :size items."
178 | },
179 | "string": "The :attribute must be a string.",
180 | "timezone": "The :attribute must be a valid zone.",
181 | "unique": "The :attribute has already been taken.",
182 | "url": "The :attribute format is invalid.",
183 | "custom": {
184 | "attribute-name": {
185 | "rule-name": "custom-message"
186 | }
187 | },
188 | "attributes": {}
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/resources/lang/en/auth.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Easy Bookmark Manager
9 |
10 |
15 |
16 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 | @yield('content')
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/resources/views/auth/login.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @include('partials/hero')
8 |
9 |
10 |
11 |
12 |
13 |
14 | @if (!empty($message))
15 |
16 | {{$message}}
17 |
18 | @endif
19 |
20 | {{ Form::open(['role' => 'form', 'url' => '/auth/login']) }}
21 |
22 | {!! csrf_field() !!}
23 |
24 |
25 | {{ Form::text('username', null, ['placeholder' => 'Email', 'class' => 'form-control']) }}
26 |
27 |
28 |
29 | {{ Form::password('password', ['placeholder' => trans('messages.user.password'), 'class' => 'form-control']) }}
30 |
31 |
32 |
33 | @include('partials/errors')
34 |
35 |
36 | {{ Form::submit(trans('messages.signin'), ['class' => 'btn btn-primary btn-small btn-block']) }}
37 |
38 | @if (env('ENABLE_REGISTER'))
39 |
42 | @endif
43 |
44 | {{ Form::close() }}
45 |
46 |
47 |
48 |
49 |
50 | @stop
51 |
52 |
53 |
--------------------------------------------------------------------------------
/resources/views/auth/register.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @include('partials/hero')
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 | {{ Form::open(['role' => 'form', 'url' => 'auth/register', 'name' => 'register']) }}
22 |
23 | @include('useradmin/registerform')
24 |
25 | @include('partials/errors')
26 |
27 |
28 | {{ Form::submit(trans('messages.user.register'), ['class' => 'btn btn-success']) }}
29 |
30 |
31 | {{ Form::close() }}
32 |
33 |
34 |
35 |
36 | @endsection
37 |
--------------------------------------------------------------------------------
/resources/views/emails/register.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Easy Bookmark Manager
8 |
9 |
10 |
11 | @include('partials.hero')
12 |
13 |
14 | {{ trans('messages.account.welcome') }}
15 |
16 | {{ trans('messages.account.confirm') }}
17 |
18 |
19 | {{ trans('messages.account.confirmLink') }}
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/resources/views/errors/503.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Be right back.
5 |
6 |
7 |
8 |
39 |
40 |
41 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/resources/views/pages/home.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @stop
8 |
--------------------------------------------------------------------------------
/resources/views/partials/errors.blade.php:
--------------------------------------------------------------------------------
1 | @if (isset($errors) && $errors->has())
2 |
3 |
4 | @foreach ($errors->all() as $error)
5 | {{ $error }}
6 | @endforeach
7 |
8 |
9 | @endif
10 |
--------------------------------------------------------------------------------
/resources/views/partials/hero.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/resources/views/useradmin/create.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
13 |
14 | {{ Form::open(['role' => 'form', 'url' => '/admin/user/store']) }}
15 |
16 | @include('useradmin/userform')
17 |
18 | @include('partials/errors')
19 |
20 |
21 | {{ Form::submit(trans('messages.create'), ['class' => 'btn btn-success']) }}
22 |
23 |
24 | {{ Form::close() }}
25 |
26 |
27 |
28 | @stop
29 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/views/useradmin/edit.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
13 |
14 | {{ Form::model($user, ['role' => 'form', 'url' => '/admin/user/' . $user->id, 'method' => 'PUT']) }}
15 |
16 | @include('useradmin/userform')
17 |
18 | @include('partials/errors')
19 |
20 |
21 | {{ Form::submit(trans('messages.save'), ['class' => 'btn btn-success']) }}
22 |
23 |
24 | {{ Form::close() }}
25 |
26 |
27 |
28 | @stop
29 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/views/useradmin/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('app')
2 |
3 | @section('content')
4 |
5 |
6 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {{ trans('messages.user.name') }}
28 |
29 |
30 | {{ trans('messages.user.mail') }}
31 |
32 |
33 | {{ trans('messages.user.created') }}
34 |
35 |
36 | {{ trans('messages.user.adminRole') }}
37 |
38 |
39 |
40 |
41 |
42 | @foreach ($users as $user)
43 |
44 | {{ $user->name }}
45 | {{ $user->username }}
46 | {{ $user->created_at->format('F d, Y h:ia') }}
47 | {{ $user->administrator ? trans('messages.yes') : '' }}
48 |
49 |
50 | {{ trans('messages.edit') }}
51 |
52 | {{ Form::open(['url' => '/admin/user/' . $user->id, 'method' => 'DELETE']) }}
53 | {{ Form::submit(trans('messages.delete'), ['class' => 'btn btn-danger btn-xs'])}}
54 | {{ Form::close() }}
55 |
56 |
57 | @endforeach
58 |
59 |
60 |
61 |
62 |
63 | {{ trans('messages.user.add') }}
64 |
65 |
66 |
67 | @stop
68 |
69 |
70 |
--------------------------------------------------------------------------------
/resources/views/useradmin/registerform.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ Form::label('name', trans('messages.user.name')) }}
3 | {{ Form::text('name', null, ['placeholder' => trans('messages.user.name'), 'class' => 'form-control']) }}
4 |
5 |
6 |
7 | {{ Form::label('username', 'Email') }}
8 | {{ Form::text('username', null, ['placeholder' => 'Email', 'class' => 'form-control']) }}
9 |
10 |
11 |
12 | {{ Form::label('password', trans('messages.user.password')) }}
13 | {{ Form::password('password', ['placeholder' => trans('messages.user.password'), 'class' => 'form-control']) }}
14 |
15 |
16 |
17 | {{ Form::label('password_confirmation', trans('messages.user.confirm')) }}
18 | {{ Form::password('password_confirmation', ['placeholder' => trans('messages.user.confirm'), 'class' => 'form-control']) }}
19 |
20 |
--------------------------------------------------------------------------------
/resources/views/useradmin/userform.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ Form::label('name', trans('messages.user.name')) }}
3 | {{ Form::text('name', null, ['placeholder' => trans('messages.user.name'), 'class' => 'form-control']) }}
4 |
5 |
6 |
7 | {{ Form::label('username', 'Email') }}
8 | {{ Form::text('username', null, ['placeholder' => 'Email', 'class' => 'form-control']) }}
9 |
10 |
11 |
12 | {{ Form::label('password', trans('messages.user.password')) }}
13 | {{ Form::password('password', ['placeholder' => trans('messages.user.password'), 'class' => 'form-control']) }}
14 |
15 |
16 |
17 | {{ Form::label('password_confirmation', trans('messages.user.confirm')) }}
18 | {{ Form::password('password_confirmation', ['placeholder' => trans('messages.user.confirm'), 'class' => 'form-control']) }}
19 |
20 |
21 |
22 | {{ Form::label('administrator', trans('messages.user.isAdmin')) }}
23 | {{ Form::checkbox('administrator', 1, null, ['class' => 'form-inline']) }}
24 |
25 |
--------------------------------------------------------------------------------
/resources/views/vendor/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devimust/easy-bookmark-manager/e03f619d1da89d32e5f06a33ac335c50710e9823/resources/views/vendor/.gitkeep
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | $uri = urldecode(
11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
12 | );
13 |
14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the
15 | // built-in PHP web server. This provides a convenient way to test a Laravel
16 | // application without having installed a "real" web server software here.
17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
18 | return false;
19 | }
20 |
21 | require_once __DIR__.'/public/index.php';
22 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | config.php
2 | routes.php
3 | compiled.php
4 | services.json
5 | events.scanned.php
6 | routes.scanned.php
7 | down
8 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/AppTitleTest.php:
--------------------------------------------------------------------------------
1 | visit('/')
17 | ->see('Easy Bookmark Manager');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | loadEnvironmentFrom('.env.testing');
22 |
23 | $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
24 |
25 | return $app;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/UserRegistrationTest.php:
--------------------------------------------------------------------------------
1 | $name,
18 | 'username' => $username,
19 | 'password' => $password,
20 | 'password_confirmation' => $confirmation,
21 | '_token' => csrf_token()
22 | ];
23 |
24 | $response = $this->call('POST', 'auth/register', $payload);
25 |
26 | return $response;
27 | }
28 |
29 | /**
30 | * Run migration tasks
31 | *
32 | * @return void
33 | */
34 | public function setUp()
35 | {
36 | parent::setUp();
37 |
38 | Artisan::call('migrate');
39 | // Artisan::call('db:seed');
40 | }
41 |
42 | /**
43 | * Test is user is created after register route
44 | * We disable send mail middleware
45 | *
46 | * @return void
47 | */
48 | public function testUserRegistration()
49 | {
50 | $beforeRegisterCount = count(User::all());
51 | $this->assertEquals(0, $beforeRegisterCount);
52 |
53 | $response = $this->registerAUser();
54 | $this->assertEquals(200, $response->getStatusCode());
55 |
56 | $afterRegisterCount = count(User::all());
57 | $this->assertEquals(1, $afterRegisterCount);
58 | }
59 |
60 | /**
61 | * Try to create a user with an already token username
62 | */
63 | public function testUserRegistrationFailed()
64 | {
65 |
66 | $beforeRegisterCount = count(User::all());
67 | $this->assertEquals(0, $beforeRegisterCount);
68 |
69 | $response = $this->registerAUser();
70 | $this->assertEquals(200, $response->getStatusCode());
71 |
72 | $response = $this->registerAUser();
73 | $this->assertEquals(302, $response->getStatusCode());
74 |
75 | $afterRegisterCount = count(User::all());
76 | $this->assertEquals(1, $afterRegisterCount);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------