init
This commit is contained in:
135
.gitignore
vendored
Normal file
135
.gitignore
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
# MacOS
|
||||
.DS_Store
|
||||
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
23
LICENSE
Normal file
23
LICENSE
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright <yyyy, yyyy> The Open Group
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and
|
||||
its documentation for any purpose is hereby granted without fee,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation.
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of The Open Group
|
||||
shall not be used in advertising or otherwise to promote the sale, use
|
||||
or other dealings in this Software without prior written authorization
|
||||
from The Open Group.
|
||||
39
README.md
Normal file
39
README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Przykład MVC CRUD w Node.js + Express + SQLite + Sequelize
|
||||
|
||||
Przykład aplikacji CRUD w NodeJS, framework Express i ORM
|
||||
|
||||
## Struktura katalogów
|
||||
```
|
||||
my-app/
|
||||
├── app.js
|
||||
├── package.json
|
||||
├── config/
|
||||
│ └── database.js
|
||||
├── models/
|
||||
│ └── customer.js
|
||||
├── controllers/
|
||||
│ └── customerController.js
|
||||
├── routes/
|
||||
│ └── customerRoutes.js
|
||||
└── views/
|
||||
├── layout.ejs
|
||||
├── index.ejs
|
||||
├── create.ejs
|
||||
├── edit.ejs
|
||||
└── show.ejs
|
||||
```
|
||||
|
||||
## Instalacja
|
||||
|
||||
Po sklonowaniu repozytorium otwórz folder projektu w Visual Studio Code i w temrminalu:
|
||||
|
||||
npm install
|
||||
|
||||
npm start
|
||||
|
||||
## Uruchomienie serwera
|
||||
|
||||
npm run start
|
||||
|
||||
http://localhost:3000
|
||||
|
||||
35
app.js
Normal file
35
app.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const methodOverride = require('method-override');
|
||||
const expressLayouts = require('express-ejs-layouts');
|
||||
const path = require('path');
|
||||
|
||||
const db = require('./config/database');
|
||||
|
||||
// Test połączenia z bazą
|
||||
db.authenticate()
|
||||
.then(() => console.log('Połączono z SQLite.'))
|
||||
.catch(err => console.error('Błąd połączenia:', err));
|
||||
|
||||
// Inicjalizacja Express
|
||||
const app = express();
|
||||
// Uzycie expressLayout i konfiguracja ejs
|
||||
app.use(expressLayouts);
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('layout', 'layout');
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(methodOverride('_method'));
|
||||
|
||||
// Routing
|
||||
const customerRoutes = require('./routes/customerRoutes');
|
||||
app.use('/customers', customerRoutes);
|
||||
|
||||
// Strona główna przekierowuje do listy klientów
|
||||
app.get('/', (req, res) => {
|
||||
res.redirect('/customers');
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, () => console.log(`Serwer działa na porcie ${PORT}`));
|
||||
8
config/database.js
Normal file
8
config/database.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { Sequelize } = require('sequelize');
|
||||
|
||||
const sequelize = new Sequelize({
|
||||
dialect: 'sqlite',
|
||||
storage: './database.sqlite'
|
||||
});
|
||||
|
||||
module.exports = sequelize;
|
||||
35
controllers/customerController.js
Normal file
35
controllers/customerController.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const Customer = require('../models/customer');
|
||||
|
||||
exports.list = async (req, res) => {
|
||||
const customers = await Customer.findAll();
|
||||
res.render('index', { customers });
|
||||
};
|
||||
|
||||
exports.show = async (req, res) => {
|
||||
const customer = await Customer.findByPk(req.params.id);
|
||||
res.render('show', { customer });
|
||||
};
|
||||
|
||||
exports.createForm = (req, res) => {
|
||||
res.render('create');
|
||||
};
|
||||
|
||||
exports.create = async (req, res) => {
|
||||
await Customer.create(req.body);
|
||||
res.redirect('/customers');
|
||||
};
|
||||
|
||||
exports.editForm = async (req, res) => {
|
||||
const customer = await Customer.findByPk(req.params.id);
|
||||
res.render('edit', { customer });
|
||||
};
|
||||
|
||||
exports.update = async (req, res) => {
|
||||
await Customer.update(req.body, { where: { id: req.params.id } });
|
||||
res.redirect('/customers');
|
||||
};
|
||||
|
||||
exports.delete = async (req, res) => {
|
||||
await Customer.destroy({ where: { id: req.params.id } });
|
||||
res.redirect('/customers');
|
||||
};
|
||||
BIN
database.sqlite
Normal file
BIN
database.sqlite
Normal file
Binary file not shown.
38
models/customer.js
Normal file
38
models/customer.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const Customer = sequelize.define('Customer', {
|
||||
firstName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
lastName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
address: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
postalCode: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
city: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
phone: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
nip: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
}
|
||||
});
|
||||
|
||||
// Synchronizacja modelu z bazą
|
||||
Customer.sync();
|
||||
|
||||
module.exports = Customer;
|
||||
2865
package-lock.json
generated
Normal file
2865
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
Normal file
32
package.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "nodejs-express-orm-crud",
|
||||
"version": "1.0.0",
|
||||
"description": "Przykład aplikacji CRUD w NodeJS, framework Express i ORM",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
"dev": "nodemon app.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.klich.net.pl/skyer/Nodejs-express-orm-crud.git"
|
||||
},
|
||||
"keywords": [
|
||||
"node"
|
||||
],
|
||||
"author": "Leszek Klich",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2.0",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^5.1.0",
|
||||
"express-ejs-layouts": "^2.5.1",
|
||||
"method-override": "^3.0.0",
|
||||
"sequelize": "^6.37.7",
|
||||
"sqlite3": "^5.1.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.10"
|
||||
}
|
||||
}
|
||||
13
routes/customerRoutes.js
Normal file
13
routes/customerRoutes.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const controller = require('../controllers/customerController');
|
||||
|
||||
router.get('/', controller.list);
|
||||
router.get('/new', controller.createForm);
|
||||
router.post('/', controller.create);
|
||||
router.get('/:id', controller.show);
|
||||
router.get('/:id/edit', controller.editForm);
|
||||
router.put('/:id', controller.update);
|
||||
router.delete('/:id', controller.delete);
|
||||
|
||||
module.exports = router;
|
||||
4
views/create.ejs
Normal file
4
views/create.ejs
Normal file
@@ -0,0 +1,4 @@
|
||||
<form action="/customers" method="post">
|
||||
<%- include('form', { customer: {} }) %>
|
||||
<button class="btn btn-success">Zapisz</button>
|
||||
</form>
|
||||
4
views/edit.ejs
Normal file
4
views/edit.ejs
Normal file
@@ -0,0 +1,4 @@
|
||||
<form action="/customers/<%= customer.id %>?_method=PUT" method="post">
|
||||
<%- include('form', { customer }) %>
|
||||
<button class="btn btn-primary">Aktualizuj</button>
|
||||
</form>
|
||||
12
views/example.ejs
Normal file
12
views/example.ejs
Normal file
@@ -0,0 +1,12 @@
|
||||
<!-- views/przyklad.ejs -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%= title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<h1><%= title %></h1>
|
||||
<p>Liczba: <%= liczba %></p>
|
||||
</body>
|
||||
</html>
|
||||
28
views/form.ejs
Normal file
28
views/form.ejs
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Imię</label>
|
||||
<input type="text" name="firstName" class="form-control" value="<%= customer.firstName || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nazwisko</label>
|
||||
<input type="text" name="lastName" class="form-control" value="<%= customer.lastName || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Adres</label>
|
||||
<input type="text" name="address" class="form-control" value="<%= customer.address || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Kod pocztowy</label>
|
||||
<input type="text" name="postalCode" class="form-control" value="<%= customer.postalCode || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Miasto</label>
|
||||
<input type="text" name="city" class="form-control" value="<%= customer.city || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Telefon</label>
|
||||
<input type="text" name="phone" class="form-control" value="<%= customer.phone || '' %>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">NIP</label>
|
||||
<input type="text" name="nip" class="form-control" value="<%= customer.nip || '' %>" required>
|
||||
</div>
|
||||
29
views/index.ejs
Normal file
29
views/index.ejs
Normal file
@@ -0,0 +1,29 @@
|
||||
<a href="/customers/new" class="btn btn-primary mb-3">Dodaj klienta</a>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Imię</th>
|
||||
<th>Nazwisko</th>
|
||||
<th>Miasto</th>
|
||||
<th>Telefon</th>
|
||||
<th>Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% customers.forEach(c => { %>
|
||||
<tr>
|
||||
<td><%= c.firstName %></td>
|
||||
<td><%= c.lastName %></td>
|
||||
<td><%= c.city %></td>
|
||||
<td><%= c.phone %></td>
|
||||
<td>
|
||||
<a href="/customers/<%= c.id %>" class="btn btn-sm btn-info">Pokaż</a>
|
||||
<a href="/customers/<%= c.id %>/edit" class="btn btn-sm btn-warning">Edytuj</a>
|
||||
<form action="/customers/<%= c.id %>?_method=DELETE" method="post" style="display:inline">
|
||||
<button class="btn btn-sm btn-danger" onclick="return confirm('Usunąć?')">Usuń</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
15
views/layout.ejs
Normal file
15
views/layout.ejs
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Lista klientów</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
||||
</head>
|
||||
<body class="p-3">
|
||||
<div class="container">
|
||||
<h1 class="mb-4">Lista klientów</h1>
|
||||
<%- body %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
10
views/show.ejs
Normal file
10
views/show.ejs
Normal file
@@ -0,0 +1,10 @@
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item"><strong>Imię:</strong> <%= customer.firstName %></li>
|
||||
<li class="list-group-item"><strong>Nazwisko:</strong> <%= customer.lastName %></li>
|
||||
<li class="list-group-item"><strong>Adres:</strong> <%= customer.address %></li>
|
||||
<li class="list-group-item"><strong>Kod pocztowy:</strong> <%= customer.postalCode %></li>
|
||||
<li class="list-group-item"><strong>Miasto:</strong> <%= customer.city %></li>
|
||||
<li class="list-group-item"><strong>Telefon:</strong> <%= customer.phone %></li>
|
||||
<li class="list-group-item"><strong>NIP:</strong> <%= customer.nip %></li>
|
||||
</ul>
|
||||
<a href="/customers" class="btn btn-link mt-3">Powrót</a>
|
||||
21
views/users.ejs
Normal file
21
views/users.ejs
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Użytkownicy</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Lista użytkowników</h1>
|
||||
<ul>
|
||||
<% users.forEach(function(user) { %>
|
||||
<li><%= user.id %>: <%= user.name %></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
<% if (config.showEmails) { %>
|
||||
<p>Adresy e-mail są widoczne</p>
|
||||
<% } else { %>
|
||||
<p>Adresy e-mail ukryte (strona <%= config.page %>)</p>
|
||||
<% } %>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user