diff --git a/cypress/e2e/auth.cy.js b/cypress/e2e/auth.cy.js index ae22d22..bc44396 100644 --- a/cypress/e2e/auth.cy.js +++ b/cypress/e2e/auth.cy.js @@ -69,6 +69,60 @@ describe('Authentication flows', () => { cy.url().should('include', '/login') }) + it('logout button on today page works', () => { + cy.loginAsUser() + cy.visit('/today') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/today') + cy.url().should('include', '/login') + }) + + it('logout button on user texts list page works', () => { + cy.loginAsUser() + cy.visit('/texts') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/texts') + cy.url().should('include', '/login') + }) + + it('logout button on user specific text page works', () => { + cy.loginAsUser() + cy.visit('/texts/0') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/texts/0') + cy.url().should('include', '/login') + }) + + it('logout button on admin page works', () => { + cy.loginAsAdmin() + cy.visit('/admin') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/admin') + cy.url().should('include', '/login') + }) + + it('logout button on admin texts list page works', () => { + cy.loginAsAdmin() + cy.visit('/admin/texts') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/admin/texts') + cy.url().should('include', '/login') + }) + + it('logout button on admin specific text page works', () => { + cy.loginAsAdmin() + cy.visit('/admin/texts/0') + cy.get('#logout').click() + cy.url().should('include', '/login') + cy.visit('/admin/texts/0') + cy.url().should('include', '/login') + }) + it('non-admin user hitting /admin gets 403', () => { cy.loginAsUser() cy.request({ diff --git a/data/seedMore.php b/data/seedMore.php new file mode 100644 index 0000000..abea97f --- /dev/null +++ b/data/seedMore.php @@ -0,0 +1,127 @@ + 0, + 'name' => 'Tanach', + 'userId' => 1, + ], +]; + +$nodes = [ + [ + 'id' => 0, + 'title' => 'Tanach', + 'textId' => 0, + 'parentNodeId' => null, + ], + [ + 'id' => 1, + 'title' => 'Torah', + 'textId' => 0, + 'parentNodeId' => 0, + ], + [ + 'id' => 2, + 'title' => 'Neviim', + 'textId' => 0, + 'parentNodeId' => 0, + ], + [ + 'id' => 3, + 'title' => 'Kesuvim', + 'textId' => 0, + 'parentNodeId' => 0, + ], + [ + 'id' => 4, + 'title' => 'Bereishis', + 'textId' => 0, + 'parentNodeId' => 1, + ], + [ + 'id' => 5, + 'title' => 'Shmos', + 'textId' => 0, + 'parentNodeId' => 1, + ], + [ + 'id' => 6, + 'title' => 'Vayikra', + 'textId' => 0, + 'parentNodeId' => 1, + ], + [ + 'id' => 7, + 'title' => 'Bamidbar', + 'textId' => 0, + 'parentNodeId' => 1, + ], + [ + 'id' => 8, + 'title' => 'Devarim', + 'textId' => 0, + 'parentNodeId' => 1, + ], + [ + 'id' => 9, + 'title' => 'Bereishis', + 'textId' => 0, + 'parentNodeId' => 4, + ], + [ + 'id' => 10, + 'title' => 'Noach', + 'textId' => 0, + 'parentNodeId' => 4, + ], + [ + 'id' => 11, + 'title' => 'Lech Lecha', + 'textId' => 0, + 'parentNodeId' => 4, + ], +]; + +// Default credentials: +// admin@example.com / admin1234 (admin) +// user@example.com / password1 (regular user) +// user2@example.com / password2 (second regular user, no texts seeded) +$users = [ + [ + 'id' => 0, + 'email' => 'admin@example.com', + 'passwordHash' => password_hash('admin1234', PASSWORD_DEFAULT), + 'isAdmin' => true, + ], + [ + 'id' => 1, + 'email' => 'user@example.com', + 'passwordHash' => password_hash('password1', PASSWORD_DEFAULT), + 'isAdmin' => false, + ], + [ + 'id' => 2, + 'email' => 'user2@example.com', + 'passwordHash' => password_hash('password2', PASSWORD_DEFAULT), + 'isAdmin' => false, + ], +]; + +$plans = []; +$scheduledNodes = []; +$sessions = []; + +$fileDataMap = [ + 'texts.json' => $texts, + 'nodes.json' => $nodes, + 'users.json' => $users, + 'plans.json' => $plans, + 'scheduledNodes.json' => $scheduledNodes, + 'sessions.json' => $sessions, +]; + +foreach ($fileDataMap as $file => $data) { + $path = __DIR__ . "/$file"; + file_put_contents($path, json_encode($data, JSON_PRETTY_PRINT)); +} diff --git a/public/js/text.js b/public/js/text.js index 2b021d0..7566869 100644 --- a/public/js/text.js +++ b/public/js/text.js @@ -32,8 +32,15 @@ document.addEventListener('DOMContentLoaded', () => { function fetchAndRenderNodes(textId) { return fetch('/api/nodes/' + textId, { credentials: 'same-origin' }) - .then(res => res.json()) + .then(function (response) { + if (!response.ok) { + return null; + } + return response.json(); + }) .then(nodes => { + if (!Array.isArray(nodes)) return; + const existing = document.querySelector('#text-detail > ul'); if (existing) existing.remove(); diff --git a/views/templates/text.php b/views/templates/text.php index 6d41421..6c62559 100644 --- a/views/templates/text.php +++ b/views/templates/text.php @@ -9,14 +9,18 @@