Compare commits
4 Commits
c0da2a1a1b
...
7dc2c6753e
Author | SHA1 | Date |
---|---|---|
King Kévin | 7dc2c6753e | |
King Kévin | 2ef85a2008 | |
King Kévin | 35a865e2db | |
King Kévin | 08df82d092 |
|
@ -11,6 +11,8 @@ Distributors also need to be managed directly in the database.
|
|||
Since this does change very often, it isn't too much of a hassle.
|
||||
An example is in `populate.sql`, also with some other entries.
|
||||
|
||||
To import an LCSC part, simply go to the `/import/lcsc/Cxxxx` page and the part will be added to the database.
|
||||
|
||||
goals
|
||||
=====
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
-- manufacturers
|
||||
INSERT INTO manufacturer (name, homepage, search) VALUES ("Espressif", "https://www.espressif.com/", "https://products.espressif.com/#/product-selector");
|
||||
|
||||
-- packages
|
||||
INSERT INTO package (name) VALUES ("module");
|
||||
|
||||
-- distributors
|
||||
INSERT INTO distributor (name, homepage, product_page) VALUES ("LCSC", "https://www.lcsc.com/", "https://www.lcsc.com/product-detail/%s.html");
|
||||
INSERT INTO distributor (name, homepage, product_page) VALUES ("JLCPCB", "https://jlcpcb.com/", "https://jlcpcb.com/partdetail/part/%s");
|
||||
|
@ -14,7 +11,7 @@ INSERT INTO distributor (name, homepage, product_page) VALUES ("Octopart", "http
|
|||
INSERT INTO distributor (name, homepage, product_page) VALUES ("AliExpress", "https://www.aliexpress.com/", "https://aliexpress.com/item/%s.html");
|
||||
|
||||
-- parts
|
||||
INSERT INTO part (name, description, manufacturer, datasheet, package, pincount, page) VALUES ("ESP32-S3-WROOM-1", "ESP32-S3 module, PCB antenna", (SELECT id FROM manufacturer WHERE name = "Espressif"), "https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf", (SELECT id FROM package WHERE name = "module"), 49, "https://www.espressif.com/en/module/esp32-s3-wroom-1-en");
|
||||
INSERT INTO part (name, description, manufacturer, datasheet, package, page) VALUES ("ESP32-S3-WROOM-1", "ESP32-S3 module, PCB antenna", (SELECT id FROM manufacturer WHERE name = "Espressif"), "https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf", "module-49", "https://www.espressif.com/en/module/esp32-s3-wroom-1-en");
|
||||
INSERT INTO part (name, description) VALUES ("ESP32-S3-WROOM-1-N4", "ESP32-S3 module, PCB antenna, 4MB flash");
|
||||
UPDATE part SET family=(SELECT id FROM part WHERE name = "ESP32-S3-WROOM-1") WHERE name = "ESP32-S3-WROOM-1-N4";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>electronic parts database explorer</title>
|
||||
<title>electronic parts inventory manager</title>
|
||||
<script type='application/javascript' src='partdb.js'></script>
|
||||
<link rel='stylesheet' href='index.css'>
|
||||
</head>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<div class="name">description:</div><div class="justify"><input class="full" type="text" id="part_description"></div>
|
||||
<div>details:</div>
|
||||
<div class="justify"><textarea class="full" id="part_details" rows="4"></textarea></div>
|
||||
<div>package: <input type="text" id="part_package" size="4">-<input type="text" id="part_pincount" size="2"></div>
|
||||
<div class="name">package:</div><div class="justify"><input class="full" type="text" id="part_package"></div>
|
||||
<div class="name">manufacturer:</div><div class="justify"><input class="full" type="text" id="part_manufacturer"></div>
|
||||
<div class="name">mpn:</div><div class="justify"><input class="full" type="text" id="part_mpn"></div>
|
||||
<div class="name">family:</div><div class="justify"><input class="full" type="text" id="part_family"></div>
|
||||
|
|
|
@ -9,7 +9,7 @@ var last_search = null;
|
|||
// the collection of parts
|
||||
var parts = null;
|
||||
// part field to populate
|
||||
const fields = ["name", "description", "details", "package", "pincount", "manufacturer", "mpn", "family", "datasheet", "page", "location", "stock"];
|
||||
const fields = ["name", "description", "details", "package", "manufacturer", "mpn", "family", "datasheet", "page", "location", "stock"];
|
||||
// URLs to set
|
||||
const urls = ["page","datasheet"];
|
||||
|
||||
|
|
14
schema.sql
14
schema.sql
|
@ -20,14 +20,6 @@ CREATE TABLE IF NOT EXISTS distributor (
|
|||
product_page TEXT -- URL to product page (%s is replace by sku)
|
||||
);
|
||||
|
||||
-- part package
|
||||
CREATE TABLE IF NOT EXISTS package (
|
||||
id INTEGER AUTO_INCREMENT PRIMARY KEY, -- index
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
family INTEGER, -- if this package is part of a more general package family
|
||||
FOREIGN KEY (family) REFERENCES package (id)
|
||||
);
|
||||
|
||||
-- the part itself
|
||||
CREATE TABLE IF NOT EXISTS part (
|
||||
id INTEGER AUTO_INCREMENT PRIMARY KEY, -- index
|
||||
|
@ -38,12 +30,10 @@ CREATE TABLE IF NOT EXISTS part (
|
|||
mpn TEXT,
|
||||
family INTEGER, -- if this part is part of a part family
|
||||
datasheet TEXT, -- URL to datasheet
|
||||
package INTEGER,
|
||||
pincount INTEGER,
|
||||
package TEXT,
|
||||
page TEXT, -- URL to product page
|
||||
FOREIGN KEY (manufacturer) REFERENCES manufacturer (id),
|
||||
FOREIGN KEY (family) REFERENCES part (id),
|
||||
FOREIGN KEY (package) REFERENCES package (id)
|
||||
FOREIGN KEY (family) REFERENCES part (id)
|
||||
);
|
||||
|
||||
-- a project (as part) can be an assembly of other parts
|
||||
|
|
90
server.rb
90
server.rb
|
@ -15,6 +15,8 @@ require 'set'
|
|||
require 'mysql2'
|
||||
require 'json'
|
||||
require 'sinatra'
|
||||
require 'uri'
|
||||
require 'net/http'
|
||||
|
||||
# allow dumping crashes in browser
|
||||
DEBUG = false
|
||||
|
@ -77,7 +79,7 @@ end
|
|||
|
||||
def get_part_by_id(id)
|
||||
return nil unless id
|
||||
statement = @db.prepare("SELECT part.id, part.name, part.description, part.details, part.datasheet, manufacturer.name AS manufacturer, part.mpn AS mpn, package.name AS package, part.pincount AS pincount, part.page AS page, part.family AS parent, p2.name AS family FROM part LEFT JOIN package ON package.id = part.package LEFT JOIN manufacturer ON manufacturer.id = part.manufacturer LEFT JOIN part AS p2 ON p2.id = part.family WHERE part.id = ?")
|
||||
statement = @db.prepare("SELECT part.id, part.name, part.description, part.details, part.datasheet, manufacturer.name AS manufacturer, part.mpn AS mpn, package.name AS package, part.page AS page, part.family AS parent, p2.name AS family FROM part LEFT JOIN package ON package.id = part.package LEFT JOIN manufacturer ON manufacturer.id = part.manufacturer LEFT JOIN part AS p2 ON p2.id = part.family WHERE part.id = ?")
|
||||
part = statement.execute(id).to_a[0]
|
||||
return nil unless part
|
||||
parent = get_part_by_id(part["parent"])
|
||||
|
@ -230,23 +232,16 @@ get '/delete/:id' do
|
|||
return 200
|
||||
end
|
||||
|
||||
post '/part' do
|
||||
request.body.rewind
|
||||
begin
|
||||
part = JSON.parse(request.body.read)
|
||||
rescue
|
||||
halt 401, "not json"
|
||||
end
|
||||
puts part if DEBUG
|
||||
def add_part(part)
|
||||
if part["id"] then
|
||||
# ensure part to update exists
|
||||
statement = @db.prepare("SELECT id FROM part WHERE id = ?")
|
||||
halt(401, "id not valid") if statement.execute(part["id"]).to_a.empty?
|
||||
raise StandardError.new("id not valid") if statement.execute(part["id"]).to_a.empty?
|
||||
else
|
||||
# add new part
|
||||
halt(401, "name required") unless part["name"] and part["name"].length > 0
|
||||
raise StandardError.new("name required") unless part["name"] and part["name"].length > 0
|
||||
statement = @db.prepare("SELECT id FROM part WHERE name = ?")
|
||||
halt(401, "name already existing") unless statement.execute(part["name"]).to_a.empty?
|
||||
raise StandardError.new("name already existing") unless statement.execute(part["name"]).to_a.empty?
|
||||
insert = @db.prepare("INSERT INTO part (name) VALUES (?)");
|
||||
insert.execute(part["name"])
|
||||
part["id"] = statement.execute(part["name"]).to_a[0]["id"]
|
||||
|
@ -258,23 +253,22 @@ post '/part' do
|
|||
if part[field] then
|
||||
statement = @db.prepare("SELECT id FROM part WHERE name = ?")
|
||||
family = statement.execute(part[field]).to_a
|
||||
halt(401, "family not existing") if family.empty?
|
||||
raise StandardError.new("family not existing") if family.empty?
|
||||
update = @db.prepare("UPDATE part SET #{field} = ? WHERE id = ?")
|
||||
update.execute(family[0]["id"], part["id"])
|
||||
family = get_part_by_id(family[0]["id"])
|
||||
end
|
||||
# update fields
|
||||
fields_txt = ["name", "description", "details", "mpn", "pincount", "datasheet", "page"];
|
||||
fields_txt = ["name", "description", "details", "mpn", "package", "datasheet", "page"];
|
||||
fields_txt.each do |field|
|
||||
next unless part[field]
|
||||
part[field] = nil if part[field].kind_of?(String) and 0 == part[field].length
|
||||
part[field] = part[field].to_i if part[field] and "pincount" == field
|
||||
next if family and family[field] == part[field]
|
||||
update = @db.prepare("UPDATE part SET #{field} = ? WHERE id = ?")
|
||||
update.execute(part[field], part["id"])
|
||||
end
|
||||
# update manufacturer and package
|
||||
field_ref = ["manufacturer", "package"]
|
||||
field_ref = ["manufacturer"]
|
||||
field_ref.each do |field|
|
||||
part[field] = nil if part[field] and 0 == part[field].length
|
||||
next if family and family[field] == part[field]
|
||||
|
@ -328,7 +322,7 @@ post '/part' do
|
|||
next unless sku and !sku.empty?
|
||||
statement = @db.prepare("SELECT id FROM distributor WHERE LOWER(name) = ?")
|
||||
ref = statement.execute(distributor.downcase).to_a[0]
|
||||
halt(401, "distributor unknown") unless ref
|
||||
raise StandardError.new("distributor unknown") unless ref
|
||||
insert = @db.prepare("INSERT INTO distribution (distributor,part,sku) VALUES (?,?,?)");
|
||||
insert.execute(ref["id"], part["id"], sku)
|
||||
end
|
||||
|
@ -355,5 +349,67 @@ post '/part' do
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
post '/part' do
|
||||
request.body.rewind
|
||||
begin
|
||||
part = JSON.parse(request.body.read)
|
||||
rescue
|
||||
halt 401, "not json"
|
||||
end
|
||||
puts part if DEBUG
|
||||
begin
|
||||
add_part(part)
|
||||
rescue StandardError => e
|
||||
halt 401, e.message
|
||||
end
|
||||
return 200
|
||||
end
|
||||
|
||||
get '/import/lcsc/:lcsc' do
|
||||
halt 401 unless params['lcsc'] and params['lcsc'] =~ /^C\d+$/i
|
||||
uri = URI("https://wmsc.lcsc.com/wmsc/product/detail?productCode=#{params['lcsc']}")
|
||||
res = Net::HTTP.get_response(uri)
|
||||
halt 401, "could not get part" unless res.is_a?(Net::HTTPSuccess)
|
||||
json = JSON.parse(res.body)
|
||||
#puts json
|
||||
halt 401, "part not found" unless 200 == json["code"] and json["result"]
|
||||
result = json["result"]
|
||||
part = {}
|
||||
part["name"] = result["productModel"]
|
||||
part["mpn"] = result["productModel"]
|
||||
part["description"] = result["productDescEn"]
|
||||
part["details"] = result["productIntroEn"]
|
||||
part["manufacturer"] = result["brandNameEn"]
|
||||
part["package"] = result["encapStandard"]
|
||||
part["distributors"] = {"LCSC" => result["productCode"]}
|
||||
part["attachments"] = result["productImages"]
|
||||
part["datasheet"] = result["pdfUrl"]
|
||||
existing = get_part_by_name(part["name"])
|
||||
halt 401, "part name already exists" if existing
|
||||
puts part
|
||||
begin
|
||||
add_part(part)
|
||||
rescue StandardError => e
|
||||
halt 401, e.message
|
||||
end
|
||||
i = 0
|
||||
(part["attachments"] + [part["datasheet"]]).each do |attachement|
|
||||
file = attachement.split("/")[-1]
|
||||
dir = PUBLIC + "/" + ATTACHMENTS + "/" + part["name"]
|
||||
path = "#{dir}/#{i}_#{file}"
|
||||
i += 1
|
||||
unless File.file?(path) then
|
||||
uri = URI(attachement)
|
||||
res = Net::HTTP.get_response(uri)
|
||||
if (res.is_a?(Net::HTTPSuccess)) then
|
||||
Dir.mkdir(dir) unless File.directory?(dir)
|
||||
File.open(path, "wb") do |f|
|
||||
f.write res.body
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return 200
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue