Compare commits

..

No commits in common. "master" and "etapa2" have entirely different histories.

9 changed files with 59 additions and 1366 deletions

8
.vscode/launch.json vendored
View File

@ -18,10 +18,10 @@
"cwd": "${workspaceFolder}/Biblioteca",
"stopAtEntry": false,
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
// "serverReadyAction": {
// "action": "openExternally",
// "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
// },
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},

View File

@ -8,7 +8,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" />
<PackageReference Include="MySqlConnector" Version="2.4.0" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,7 @@
### Obtém uma lista de livros
GET {{url}}/livros?pagina=3
GET {{url}}/livros
Accept: application/json
### Cria um novo livro
@ -12,28 +12,29 @@ Accept: application/json
Content-Type: application/json
{
"isbn": "aabbccddee",
"titulo": "Livro teste",
"autor": "Autor"
"isbn": "9780321741769",
"titulo": "The C# Programming Language",
"autor": "Anders Hejlsberg"
}
### Edita um livro
PUT {{url}}/livros/1027
PUT {{url}}/livros/9780321741769
Accept: application/json
Content-Type: application/json
{
"titulo": "teste4",
"isbn": "9780321741769",
"titulo": "The C# Programming Language",
"autor": "Anders Hejlsberg, Mads Torgensen"
}
### Obtém um livro individual
GET {{url}}/livros/1027
GET {{url}}/livros/9780321741769
Accept: application/json
### Remove um livro
DELETE {{url}}/livros/1027
DELETE {{url}}/livros/9780321741769
Accept: application/json

View File

@ -1,16 +0,0 @@
namespace Biblioteca.Models;
public class Livro
{
public long Id { get; set; }
public string? Isbn { get; set; }
public string? Titulo { get; set; }
public string? Autor { get; set; }
public string? Genero { get; set; }
public string? Descricao { get; set; }
public string? Foto { get; set; }
public string? Keywords { get; set; }
public bool Ativo { get; set; }
public DateTime CriadoEm { get; set; }
public DateTime AtualizadoEm { get; set; }
}

View File

@ -1,52 +1,71 @@
using Biblioteca.Models;
using Biblioteca.Repositories;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Obtém uma lista com os livros registrados.
app.MapGet("/livros", async (int pagina) =>
app.MapGet("/", () =>
{
var repo = new LivroRepository();
var res = await repo.Obter(pagina: pagina);
string[] saudacoes = ["Olá!", "こんにちは", "Привет", "Ողջույն"];
return res;
return saudacoes[Random.Shared.Next(saudacoes.Length)];
});
// Obtém uma lista com os livros registrados.
app.MapGet("/livros", () =>
{
return new Livro[]
{
new()
{
Isbn = "9780262510875",
Titulo = "Structure and Interpretation of Computer Programs",
Autor = "Gerald Jay Sussman"
},
new()
{
Isbn = "9780131103627",
Titulo = "C Programming Language: ANSI C Version",
Autor = "Dennis Ritchie, Brian Kerningham"
},
new()
{
Isbn = "9780134190440",
Titulo = "The Go Programming Language",
Autor = "Brian Kerningham"
}
};
});
// Cria um novo livro.
app.MapPost("/livros", async (Livro livro) =>
app.MapPost("/livros", (Livro livro) =>
{
var repo = new LivroRepository();
var res = await repo.Criar(livro);
return res;
return livro;
});
// Edita um livro.
app.MapPut("/livros/{id}", async (long id, Livro livro) =>
app.MapPut("/livros/{isbn}", (string isbn, Livro livro) =>
{
var repo = new LivroRepository();
var res = await repo.Editar(id, livro);
return res;
return new { editando = isbn, dados = livro };
});
// Obtém os dados de um livro individual.
app.MapGet("/livros/{id}", async (long id) =>
app.MapGet("/livros/{isbn}", (string isbn) =>
{
var repo = new LivroRepository();
var res = await repo.Obter(id);
return res;
return new Livro() { Isbn = isbn };
});
// Remove um livro.
app.MapDelete("/livros/{id}", async (long id) =>
app.MapDelete("/livros/{isbn}", (string isbn) =>
{
var repo = new LivroRepository();
await repo.Desativar(id);
return Results.NoContent();
});
app.Run();
app.Run();
public class Livro
{
public string? Isbn { get; set; }
public string? Titulo { get; set; }
public string? Autor { get; set; }
};

View File

@ -1,198 +0,0 @@
using Biblioteca.Models;
using MySqlConnector;
namespace Biblioteca.Repositories;
public class LivroRepository
{
private const string ConnString = "Server=gbrl.dev;Port=5306;User ID=sistemasdistribuidos.aluno;Password=eW03avS7M8kOUL1A9bZWW2RTIfzEI1Di;Database=sistemasdistribuidos";
public async Task<IEnumerable<Livro>> Obter(int pagina)
{
using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand();
await conn.OpenAsync();
var take = 30;
var offset = take * Math.Max(pagina-1, 0);
var lista = new List<Livro>();
cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro ORDER BY CriadoEm LIMIT @offset,@take";
cmd.Parameters.AddWithValue("offset", offset);
cmd.Parameters.AddWithValue("take", take);
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
lista.Add(new()
{
Id = reader.GetInt64(0),
Isbn = reader.GetString(1),
Titulo = reader.GetString(2),
Autor = reader.GetString(3),
Genero = reader.GetString(4),
Descricao = reader.GetString(5),
Foto = reader.GetString(6),
Keywords = reader.GetString(7),
Ativo = reader.GetBoolean(8),
CriadoEm = reader.GetDateTime(9),
AtualizadoEm = reader.GetDateTime(10),
});
}
return lista;
}
/// <summary>
/// Obtém um livro pelo seu ISBN.
/// </summary>
/// <param name="isbn"></param>
/// <returns></returns>
public async Task<Livro> Obter(long id)
{
using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand();
await conn.OpenAsync();
cmd.CommandText = "SELECT Id, Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm FROM Livro WHERE Id=@id";
cmd.Parameters.AddWithValue("id", id);
using var reader = await cmd.ExecuteReaderAsync();
var existe = await reader.ReadAsync();
if (!existe)
{
throw new Exception($"Livro {id} não encontrado");
}
return new()
{
Id = reader.GetInt64(0),
Isbn = reader.GetString(1),
Titulo = reader.GetString(2),
Autor = reader.GetString(3),
Genero = reader.GetString(4),
Descricao = reader.GetString(5),
Foto = reader.GetString(6),
Keywords = reader.GetString(7),
Ativo = reader.GetBoolean(8),
CriadoEm = reader.GetDateTime(9),
AtualizadoEm = reader.GetDateTime(10),
};
}
public async Task<Livro> Criar(Livro dados)
{
using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand();
await conn.OpenAsync();
var livro = new Livro
{
Isbn = dados.Isbn?.Trim() ?? "",
Titulo = dados.Titulo?.Trim() ?? "",
Autor = dados.Autor?.Trim() ?? "",
Genero = dados.Genero?.Trim() ?? "",
Descricao = dados.Descricao?.Trim() ?? "",
Foto = dados.Foto?.Trim() ?? "",
Keywords = dados.Keywords?.Trim() ?? "",
Ativo = true,
CriadoEm = DateTime.Now,
AtualizadoEm = default,
};
if (livro.Titulo == "")
{
throw new Exception("O título do livro é obrigatório.");
}
cmd.CommandText =
@"
INSERT INTO Livro
(Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm)
VALUES
(@isbn, @titulo, @autor, @genero, @descricao, @foto, @keywords, @ativo, @criadoem, @atualizadoem)
";
cmd.Parameters.AddWithValue("isbn", livro.Isbn);
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
cmd.Parameters.AddWithValue("autor", livro.Autor);
cmd.Parameters.AddWithValue("genero", livro.Genero);
cmd.Parameters.AddWithValue("descricao", livro.Descricao);
cmd.Parameters.AddWithValue("foto", livro.Foto);
cmd.Parameters.AddWithValue("keywords", livro.Keywords);
cmd.Parameters.AddWithValue("ativo", livro.Ativo);
cmd.Parameters.AddWithValue("criadoem", livro.CriadoEm);
cmd.Parameters.AddWithValue("atualizadoem", livro.AtualizadoEm);
await cmd.ExecuteNonQueryAsync();
using var cmd2 = conn.CreateCommand();
cmd2.CommandText = "SELECT LAST_INSERT_ID()";
using var reader = await cmd2.ExecuteReaderAsync();
await reader.ReadAsync();
livro.Id = reader.GetInt64(0);
return livro;
}
public async Task<Livro> Editar(long id, Livro dados)
{
using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand();
await conn.OpenAsync();
var livro = await Obter(id);
livro.Titulo = dados.Titulo?.Trim() ?? "";
livro.Autor = dados.Autor?.Trim() ?? "";
livro.Genero = dados.Genero?.Trim() ?? "";
livro.Descricao = dados.Descricao?.Trim() ?? "";
livro.Foto = dados.Foto?.Trim() ?? "";
livro.Keywords = dados.Keywords?.Trim() ?? "";
livro.AtualizadoEm = DateTime.Now;
cmd.CommandText =
@"
UPDATE Livro SET
Titulo=@titulo, Autor=@autor, Genero=@genero, Descricao=@descricao, Foto=@foto, Keywords=@keywords, AtualizadoEm=@atualizadoem
WHERE Id=@id
";
cmd.Parameters.AddWithValue("id", id);
cmd.Parameters.AddWithValue("titulo", livro.Titulo);
cmd.Parameters.AddWithValue("autor", livro.Autor);
cmd.Parameters.AddWithValue("genero", livro.Genero);
cmd.Parameters.AddWithValue("descricao", livro.Descricao);
cmd.Parameters.AddWithValue("foto", livro.Foto);
cmd.Parameters.AddWithValue("keywords", livro.Keywords);
cmd.Parameters.AddWithValue("atualizadoem", livro.AtualizadoEm);
await cmd.ExecuteNonQueryAsync();
return livro;
}
public async Task Desativar(long id)
{
using var conn = new MySqlConnection(ConnString);
using var cmd = conn.CreateCommand();
await conn.OpenAsync();
cmd.CommandText = "UPDATE Livro SET Ativo=false WHERE Id=@id";
cmd.Parameters.AddWithValue("id", id);
await cmd.ExecuteNonQueryAsync();
}
}

View File

@ -1,71 +0,0 @@
#
# books.py
# Gera um arquivo .sql com INSERTs de livros obtidos do Project Gutemberg
# https://gutendex.com/
#
import http.client
import json
import time
from urllib.parse import urlparse
API_URL = "https://gutendex.com/books/"
BOOKS_COUNT = 1000
FETCH_DELAY = 1#s
OUTPUT = "./books.sql"
def fetch(resource):
url = urlparse(resource)
client = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
conn = client(url.netloc)
conn.request("GET", f"{url.path}?{url.query}")
res = conn.getresponse()
if res.status < 200 or res.status > 299:
return {}
return json.loads(res.read())
def write_inserts(file, page):
data = fetch(f"{API_URL}?page={page}")
books = data["results"]
lines = []
esc = lambda str: str.replace('"', '\\"')
for book in books:
summaries = book["summaries"]
imgs = [book["formats"][f] for f in book["formats"] if f.startswith("image/")]
isbn = ""
titulo = book["title"]
autor = ",".join([a["name"] for a in book["authors"]])
genero = ",".join(book["subjects"])
descricao = summaries[0] if len(summaries) > 0 else ""
foto = imgs[0] if len(imgs) > 0 else ""
keywords = ",".join(book["bookshelves"])
lines.append(f'("{esc(isbn)}", "{esc(titulo)}", "{esc(autor)}", "{esc(genero)}", "{esc(descricao)}", "{esc(foto)}", "{esc(keywords)}", true, NOW(), NOW())')
values = ",\n".join(lines)
insert = f"INSERT INTO Livro (Isbn, Titulo, Autor, Genero, Descricao, Foto, Keywords, Ativo, CriadoEm, AtualizadoEm) VALUES {values};\n"
file.write(insert)
return len(lines)
def collect(n, file, _page=1):
if n <= 0:
return
written = write_inserts(file, _page)
time.sleep(FETCH_DELAY)
collect(n-written, file, _page+1)
def run():
with open(OUTPUT, "w") as file:
collect(BOOKS_COUNT, file)
run()

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
CREATE TABLE Livro (
Id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
Isbn VARCHAR(255) NOT NULL,
Titulo VARCHAR(512) NOT NULL,
Autor TEXT NOT NULL,
Genero TEXT NOT NULL,
Descricao TEXT NOT NULL,
Foto TEXT NOT NULL,
Keywords TEXT NOT NULL,
Ativo BOOLEAN NOT NULL DEFAULT 0,
CriadoEm DATETIME NOT NULL,
AtualizadoEm DATETIME NOT NULL,
INDEX (Isbn),
INDEX (CriadoEm),
FULLTEXT (Titulo, Autor, Genero, Descricao, Keywords)
);