Initial commit
This commit is contained in:
198
home-server/printing/cupsd.conf
Normal file
198
home-server/printing/cupsd.conf
Normal file
@@ -0,0 +1,198 @@
|
||||
#
|
||||
# Configuration file for the CUPS scheduler. See "man cupsd.conf" for a
|
||||
# complete description of this file.
|
||||
#
|
||||
|
||||
# Log general information in error_log - change "warn" to "debug"
|
||||
# for troubleshooting...
|
||||
LogLevel warn
|
||||
PageLogFormat
|
||||
|
||||
# Specifies the maximum size of the log files before they are rotated. The value "0" disables log rotation.
|
||||
MaxLogSize 0
|
||||
|
||||
# Default error policy for printers
|
||||
ErrorPolicy retry-job
|
||||
|
||||
# Allow remote access
|
||||
Listen *:631 # important
|
||||
ServerAlias * # important
|
||||
|
||||
# Show shared printers on the local network.
|
||||
Browsing Yes
|
||||
BrowseLocalProtocols dnssd
|
||||
|
||||
# Default authentication type, when authentication is required...
|
||||
DefaultAuthType Basic
|
||||
DefaultEncryption IfRequested
|
||||
|
||||
# Web interface setting...
|
||||
WebInterface Yes
|
||||
|
||||
# Timeout after cupsd exits if idle (applied only if cupsd runs on-demand - with -l)
|
||||
IdleExitTimeout 60
|
||||
|
||||
# Restrict access to the server...
|
||||
<Location />
|
||||
Order allow,deny
|
||||
Allow all
|
||||
</Location>
|
||||
|
||||
# Restrict access to the admin pages...
|
||||
<Location /admin>
|
||||
Order allow,deny
|
||||
Allow all
|
||||
</Location>
|
||||
|
||||
# Restrict access to configuration files...
|
||||
<Location /admin/conf>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order allow,deny
|
||||
Allow all
|
||||
</Location>
|
||||
|
||||
# Restrict access to log files...
|
||||
<Location /admin/log>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order allow,deny
|
||||
Allow all
|
||||
</Location>
|
||||
|
||||
# Set the default printer/job policies...
|
||||
<Policy default>
|
||||
# Job/subscription privacy...
|
||||
JobPrivateAccess default
|
||||
JobPrivateValues default
|
||||
SubscriptionPrivateAccess default
|
||||
SubscriptionPrivateValues default
|
||||
|
||||
# Job-related operations must be done by the owner or an administrator...
|
||||
<Limit Create-Job Print-Job Print-URI Validate-Job>
|
||||
Order deny,allow
|
||||
# Allow all # mine...
|
||||
</Limit>
|
||||
|
||||
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All administration operations require an administrator to authenticate...
|
||||
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All printer operations require a printer operator to authenticate...
|
||||
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# Only the owner or an administrator can cancel or authenticate a job...
|
||||
<Limit Cancel-Job CUPS-Authenticate-Job>
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
<Limit All>
|
||||
Order deny,allow
|
||||
# Allow all # mine
|
||||
</Limit>
|
||||
</Policy>
|
||||
|
||||
# Set the authenticated printer/job policies...
|
||||
<Policy authenticated>
|
||||
# Job/subscription privacy...
|
||||
JobPrivateAccess default
|
||||
JobPrivateValues default
|
||||
SubscriptionPrivateAccess default
|
||||
SubscriptionPrivateValues default
|
||||
|
||||
# Job-related operations must be done by the owner or an administrator...
|
||||
<Limit Create-Job Print-Job Print-URI Validate-Job>
|
||||
AuthType Default
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
|
||||
AuthType Default
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All administration operations require an administrator to authenticate...
|
||||
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All printer operations require a printer operator to authenticate...
|
||||
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# Only the owner or an administrator can cancel or authenticate a job...
|
||||
<Limit Cancel-Job CUPS-Authenticate-Job>
|
||||
AuthType Default
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
<Limit All>
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
</Policy>
|
||||
|
||||
# Set the kerberized printer/job policies...
|
||||
<Policy kerberos>
|
||||
# Job/subscription privacy...
|
||||
JobPrivateAccess default
|
||||
JobPrivateValues default
|
||||
SubscriptionPrivateAccess default
|
||||
SubscriptionPrivateValues default
|
||||
|
||||
# Job-related operations must be done by the owner or an administrator...
|
||||
<Limit Create-Job Print-Job Print-URI Validate-Job>
|
||||
AuthType Negotiate
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
<Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
|
||||
AuthType Negotiate
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All administration operations require an administrator to authenticate...
|
||||
<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# All printer operations require a printer operator to authenticate...
|
||||
<Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
|
||||
AuthType Default
|
||||
Require user @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
# Only the owner or an administrator can cancel or authenticate a job...
|
||||
<Limit Cancel-Job CUPS-Authenticate-Job>
|
||||
AuthType Negotiate
|
||||
Require user @OWNER @SYSTEM
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
|
||||
<Limit All>
|
||||
Order deny,allow
|
||||
</Limit>
|
||||
</Policy>
|
||||
19
home-server/printing/docker-compose.yml
Normal file
19
home-server/printing/docker-compose.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
cups:
|
||||
image: olbat/cupsd:stable-2024-01-19 # admin user/password: print/print
|
||||
container_name: cups
|
||||
privileged: true
|
||||
volumes:
|
||||
- "/dev/bus/usb:/dev/bus/usb" # keep this under volumes, not devices
|
||||
- "/run/dbus:/run/dbus"
|
||||
- "./cupsd.conf:/etc/cups/cupsd.conf:ro"
|
||||
#- "./data/printers.conf:/etc/cups/printers.conf:ro"
|
||||
ports:
|
||||
- "631:631/tcp" # CUPS
|
||||
restart: "always"
|
||||
|
||||
cups-webpage:
|
||||
buid: server
|
||||
ports:
|
||||
- 6311:6311
|
||||
24
home-server/printing/printer.conf
Normal file
24
home-server/printing/printer.conf
Normal file
@@ -0,0 +1,24 @@
|
||||
# Printer configuration file for CUPS v2.4.2
|
||||
# Written by cupsd
|
||||
# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING
|
||||
NextPrinterId 2
|
||||
<Printer Brother_HL-L2300D_series>
|
||||
PrinterId 1
|
||||
UUID urn:uuid:8ac038d7-8659-3de9-57d0-0a7f97b956cc
|
||||
Info Brother HL-L2300D series
|
||||
Location
|
||||
MakeModel Brother HL-L2300D series, using brlaser v6
|
||||
DeviceURI usb://Brother/HL-L2300D%20series?serial=U63878J0N375067
|
||||
State Idle
|
||||
StateTime 1714021523
|
||||
ConfigTime 1714021523
|
||||
Type 4180
|
||||
Accepting Yes
|
||||
Shared Yes
|
||||
JobSheets none none
|
||||
QuotaPeriod 0
|
||||
PageLimit 0
|
||||
KLimit 0
|
||||
OpPolicy default
|
||||
ErrorPolicy retry-job
|
||||
</Printer>
|
||||
13
home-server/printing/readme.md
Normal file
13
home-server/printing/readme.md
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
|
||||
## what I am running on office server
|
||||
|
||||
```bash
|
||||
sudo apt install python3-pip cups python3-cups hplip
|
||||
pip install pycups fastapi "uvicorn[standard]" python-multipart
|
||||
sudo hp-setup -i # manually configure printer...
|
||||
python -m uvicorn print_api:app --reload --host 0.0.0.0
|
||||
```
|
||||
|
||||
url: http://100.103.75.97:8000/
|
||||
11
home-server/printing/server/Dockerfile
Normal file
11
home-server/printing/server/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM python:3
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libcups2-dev python3-pip cups python3-cups gcc \
|
||||
&& pip install pycups fastapi "uvicorn[standard]" python-multipart
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
COPY ./src .
|
||||
|
||||
CMD python -m uvicorn print_api:app --reload --host 0.0.0.0 --port 6311
|
||||
27
home-server/printing/server/flake.lock
generated
Normal file
27
home-server/printing/server/flake.lock
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1725634671,
|
||||
"narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
38
home-server/printing/server/flake.nix
Normal file
38
home-server/printing/server/flake.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
description = "Printer Server Flake";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
outputs = { self, nixpkgs, ... }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
myPython = pkgs.python3.withPackages (python-pkgs: with pkgs; [
|
||||
python312Packages.fastapi
|
||||
python312Packages.fastapi-cli
|
||||
python312Packages.pycups
|
||||
python312Packages.python-multipart
|
||||
python312Packages.uvicorn
|
||||
]);
|
||||
in
|
||||
{
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
python312Packages.fastapi
|
||||
python312Packages.fastapi-cli
|
||||
python312Packages.pycups
|
||||
python312Packages.python-multipart
|
||||
python312Packages.uvicorn
|
||||
];
|
||||
};
|
||||
|
||||
packages.${system} = rec {
|
||||
fastapi-server = pkgs.writeShellScriptBin "start-server" ''
|
||||
${myPython}/bin/fastapi run ${self}/src/print_api.py
|
||||
'';
|
||||
|
||||
default = fastapi-server;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
149
home-server/printing/server/src/index.html
Normal file
149
home-server/printing/server/src/index.html
Normal file
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Document Upload</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
background: #09373e;
|
||||
color: #85bfc8;
|
||||
}
|
||||
#form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
form {
|
||||
border: 1px solid #ccc;
|
||||
padding: 20px;
|
||||
background: #05252a;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h2 {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
input[type="file"] {
|
||||
display: none; /* Hide the file input */
|
||||
}
|
||||
input[type="submit"] {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
background: #007bff;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
#dropzone {
|
||||
border: 2px dashed #ccc;
|
||||
padding: 20px;
|
||||
width: 300px;
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#dropzone.dragover {
|
||||
border-color: #000;
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Upload Document</h2>
|
||||
<br />
|
||||
<section id="form-container">
|
||||
<form
|
||||
id="printForm"
|
||||
action="/print/"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<div id="dropzone">Drop file to upload or click to select</div>
|
||||
<input type="file" id="fileInput" />
|
||||
<br />
|
||||
<input type="submit" value="Upload Document" name="submit" />
|
||||
</form>
|
||||
</section>
|
||||
<script>
|
||||
var stagedFile = undefined;
|
||||
const formElement = document.getElementById("printForm");
|
||||
const fileInputElement = document.getElementById("fileInput");
|
||||
|
||||
formElement.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData();
|
||||
formData.append("file", stagedFile);
|
||||
|
||||
const response = await fetch("/print/", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("dragover", function (event) {
|
||||
event.preventDefault(); // Prevent default behavior (Prevent file from being opened)
|
||||
event.stopPropagation();
|
||||
event.target.classList.add("dragover"); // Optional: add a style change
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("dragleave", function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.target.classList.remove("dragover"); // Optional: revert style change
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("drop", function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.target.classList.remove("dragover"); // Optional: revert style change
|
||||
|
||||
// Process files
|
||||
var files = event.dataTransfer.files;
|
||||
handleFiles(files);
|
||||
});
|
||||
|
||||
// Handle file selection when clicked
|
||||
document
|
||||
.getElementById("dropzone")
|
||||
.addEventListener("click", function () {
|
||||
fileInputElement.click(); // Trigger the hidden file input's click
|
||||
});
|
||||
|
||||
fileInputElement.addEventListener("change", function (event) {
|
||||
const files = event.target.files;
|
||||
handleFiles(files);
|
||||
});
|
||||
|
||||
const handleFiles = (files) => {
|
||||
stagedFile = files[0];
|
||||
renderStagedFile();
|
||||
};
|
||||
|
||||
const renderStagedFile = () => {
|
||||
const element = document.getElementById("dropzone");
|
||||
if (!stagedFile) {
|
||||
element.textContent = "Drop file to upload or click to select";
|
||||
} else {
|
||||
element.textContent = `FILE: ${stagedFile.name}`;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
69
home-server/printing/server/src/print_api.py
Normal file
69
home-server/printing/server/src/print_api.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
from pprint import pprint
|
||||
import tempfile
|
||||
from fastapi import FastAPI, File, UploadFile, Request
|
||||
import cups
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
# @app.post("/print/")
|
||||
# async def print_document(file: UploadFile = File(...)):
|
||||
# temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
# temp_file.write(await file.read())
|
||||
# temp_file.close()
|
||||
|
||||
# conn = cups.Connection(host="server.alexmickelson.guru")
|
||||
|
||||
# printers = conn.getPrinters()
|
||||
# print(file.filename)
|
||||
# print(temp_file.name)
|
||||
# pprint(printers)
|
||||
# for printer in printers:
|
||||
# print(printer, printers[printer]["device-uri"])
|
||||
|
||||
# default_printer = list(printers.keys())[0]
|
||||
|
||||
|
||||
# job_id = conn.printFile(default_printer, temp_file.name, f"FastAPI Print Job for {temp_file.name}", {})
|
||||
# os.unlink(temp_file.name)
|
||||
|
||||
# return {"job_id": job_id, "file_name": file.filename}
|
||||
|
||||
|
||||
@app.post("/print/")
|
||||
async def print_document(file: UploadFile = File(...)):
|
||||
# Save the uploaded file to a temporary file
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.write(await file.read())
|
||||
temp_file.close()
|
||||
|
||||
# Connect to the CUPS server on the host (use default CUPS connection)
|
||||
conn = cups.Connection() # This will connect to localhost CUPS
|
||||
|
||||
# Get the list of available printers
|
||||
printers = conn.getPrinters()
|
||||
print(file.filename)
|
||||
print(temp_file.name)
|
||||
pprint(printers)
|
||||
for printer in printers:
|
||||
print(printer, printers[printer]["device-uri"])
|
||||
|
||||
# Use the default printer (first one in the list)
|
||||
default_printer = list(printers.keys())[0]
|
||||
|
||||
# Print the file
|
||||
job_id = conn.printFile(default_printer, temp_file.name, f"FastAPI Print Job for {temp_file.name}", {})
|
||||
|
||||
# Clean up the temporary file
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
return {"job_id": job_id, "file_name": file.filename}
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
with open('src/index.html', 'r') as f:
|
||||
html_content = f.read()
|
||||
return HTMLResponse(content=html_content, status_code=200)
|
||||
|
||||
Reference in New Issue
Block a user