Search code examples
pythonreportlab

Code to generate pages of boxes filled with user/pass not wrapping and gets too tall


I want to change this code so that it wraps the table in each page as much as possible to avoid printing out too many papers. For example, generating 256 users gives me 14 pages to print, too much paper waste over time.

PS: you are welcome to change the table style.

The below is the code:

import random
import string
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Table, Spacer
from reportlab.lib import colors
from reportlab.platypus import TableStyle
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import portrait, A4

# Function to generate random passwords based on the selected format
def generate_password(format):
    if format == '1':
        return username
    elif format == '2':
        return ''.join(random.choice(characters) for _ in range(3))
    elif format == '3':
        return ''.join(random.choice(characters) for _ in range(4))
    elif format == '4':
        return ''.join(random.choice(characters) for _ in range(5))
    else:
        return ''

print(
    """
=====================================
HOTSPOT TICKET GENERATOR FOR MIKROTIK
=====================================
BY ALI

"""
)

print("Enter the number of users: ")
numOfUsers = int(input())

print("Enter the rate limit [Up/Down] (ex: 1M/2M):")
rateLimit = input(str())

print("Enter username format (ex: user_, user-..): ")
usernameFormat = input(str())

print("Enter password format (1 for pass=user, 2 for 3-chars, 3 for 4-chars, 4 for 5-chars): ")
passwordFormat = input()

print("Enter limit uptime (ex: 1d, 1h, 1m): ")
limitUpTime = input(str())

print("Enter limit bytes total (ex: 1K, 1M, 1G): ")
limitBytesTotal = input(str())

characters = string.ascii_letters + string.digits

# Create a list to store usernames and passwords
usernames_passwords = []

# Generate usernames and passwords
for i in range(1, numOfUsers + 1):
    username = usernameFormat + str(i)
    password = generate_password(passwordFormat)
    usernames_passwords.append((username, password))

# Create a PDF document
doc = SimpleDocTemplate("usernames_and_passwords.pdf", pagesize=portrait(A4))

# Create a list to store content
story = []

# Create a table for displaying usernames and passwords
table_data = []

for username, password in usernames_passwords:
    table_data.append([f"Username: {username}", f"Password: {password}"])
    table_data.append([Spacer(1, 10)])  # Add 10-pixel space between rows

# Define table style
table_style = TableStyle([
    ('BACKGROUND', (0, 0), (-1, 0), colors.beige),  # Header row background color
    ('TEXTCOLOR', (0, 0), (-1, 0), colors.black),  # Header text color
    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # Center text horizontally
    ('FONTNAME', (0, 0), (-1, 0), 'Helvetica'),  # Header font
    ('BACKGROUND', (0, 1), (-1, -1), colors.beige),  # Data rows background color
    ('LEFTPADDING', (0,0), (-1,-1), 0),
    ('GRID', (0, 0), (-1, -1), 1, colors.black)  # Border for data rows
])

# Create a table and apply the style
table = Table(table_data)
table.setStyle(table_style)

# Add the table to the story
story.append(table)

# Build the PDF document
doc.build(story)

print("PDF generated successfully.")

This is what I'm getting (for more clarification):

...

And this is what I want it to look like if you understand, fit as many as possible in each page so i get to print less pages than usual (PS: No need to show ''member-free'' and the numbering ''1, 2, 3...'', just each user and pass in a box with little white space/padding around so I can cut them out later on.)

...


Solution

  • This does what you want. You might consider passing your input data as command-line parameters instead of inputs. That makes it a lot easier to run several in a row.

    Also, input(str()) is not what you want. The parameter to input is the prompt to use.

    import random
    import string
    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    from reportlab.lib import colors
    from reportlab.lib.units import inch
    from reportlab.lib.pagesizes import portrait, A4
    
    # Function to generate random passwords based on the selected format
    def generate_password(format):
        if format == '1':
            return username
        else:
            return ''.join(random.choice(characters) for _ in range(int(format)+1))
    
    print( """
    =====================================
    HOTSPOT TICKET GENERATOR FOR MIKROTIK
    =====================================
    BY ALI
    
    """
    )
    
    #numOfUsers = int(input("Enter the number of users: "))
    #
    #rateLimit = input("Enter the rate limit [Up/Down] (ex: 1M/2M): ")
    #
    #usernameFormat = input("Enter username format (ex: user_, user-..): ")
    #
    #passwordFormat = input("Enter password format (1 for pass=user, 2 for 3-chars, 3 for 4-chars, 4 for 5-chars): ")
    #
    #limitUpTime = input("Enter limit uptime (ex: 1d, 1h, 1m): ")
    #
    #limitBytesTotal = input("Enter limit bytes total (ex: 1K, 1M, 1G): ")
    
    
    numOfUsers = 128
    usernameFormat = 'user'
    passwordFormat = '4'
    
    # A box is 1.5" by 5/8".
    # We have 1/2" margin on all sides, leaving 4 boxes across.
    
    PAGE = portrait(A4)
    MARGIN = 36
    BOXW = 1.5 * inch
    BOXH = 5 * inch / 8
    ACROSS = (PAGE[0] - 2*MARGIN) // BOXW
    DOWN = (PAGE[1] - 2*MARGIN) // BOXH - 1
    
    def setup(doc):
        doc.setLineWidth( 0.5 )
        doc.setFont( 'Helvetica', 9 )
    
    def createLabel( doc, x, y, ord, user, password ):
       doc.setStrokeColor( (0,0,0) )
       doc.rect( x, y-BOXH, BOXW, BOXH )
       doc.line( x, y-12, x+BOXW, y-12 )
       doc.setFillColor( (0,0,0) )
       doc.drawString( x+3, y-9, "member-free" )
       doc.drawRightString( x+BOXW-3, y-9, str(ord) )
       doc.drawString( x+3, y-24, "Username:" )
       doc.drawString( x+3, y-36, "Password:" )
       doc.setFillColor( colors.purple )
       doc.drawString( x+69, y-24, user )
       doc.drawString( x+69, y-36, password )
    
    def coords(n):
       x = MARGIN + (BOXW+3)*(n % ACROSS)
       y = PAGE[1] - MARGIN - (BOXH+3)*((n // ACROSS) % DOWN)
       return x,y
    
    characters = string.ascii_letters + string.digits
    
    # Create a PDF document
    doc = canvas.Canvas("usernames_and_passwords.pdf", pagesize=PAGE)
    setup(doc)
    
    # Generate usernames and passwords
    for i in range(numOfUsers):
        # Have we started a new page?
        if i and not i % (ACROSS*DOWN):
            doc.showPage()
            setup(doc)
        username = usernameFormat + str(i+1)
        password = generate_password(passwordFormat)
        x,y = coords(i)
        createLabel( doc, x, y, i+1, username, password )
    
    
    doc.save()
    
    print("PDF generated successfully.")
    

    Output: enter image description here