Git Product home page Git Product logo

tejos_textiles's Introduction

Textiles Journal / Revista Tejos

Textiles Journal Logo 2020 An online literary journal publishing works in an interactive new medium.

Link to English edition (offline): Textiles Journal

Link to Spanish edition: Revista Tejos (tbd)

Showcase

The website is not currently online, but a showcase/tutorial/intro video can be viewed on Youtube.

tejos_textiles's People

Contributors

dependabot[bot] avatar ogallagher avatar

Stargazers

 avatar

tejos_textiles's Issues

Accountless (anonymous) authors

In addition to the “anonymous” author there will also be cases where a work available in the public domain or in creative commons might be used for a new textile, especially early on (...or for a while...) when the user base for sourcing works is still thin. In that case, many works will have authors that don’t have associated accounts.

The account page has to support these scenarios, by showing the username, the bio as “This user does not have an account”, the full contributions list, but hide everything else.

The database also has to support anonymous accounts, by adding an anonymous field to the people table. This also means that the work.author field should be a foreign key of people.username; all authors point to user accounts, but some can have people.anonymous=1. This prevents people from stealing anonymous accounts through registration.

Textile path import transform is not initially correct

The call to Puzzle.resizeGraphics() does not work on the first call, when the svg path data is first imported on puzzle select. When it is called subsequently, however (like in the case of resizing the window), the path centers correctly.

User-puzzle stats race condition

There’s a race happening between loading the puzzle data and the user account data in the home page, which sometimes prevents the user-puzzle stats (plays, rating, fastest solve) from loading.

Finish textile_row component

They’re currently just placeholders showing the puzzle titles, not even clickable yet. I need to add in the other info as well as make them redirect to textile.html?puzzle_id=<id>.

Prevent JS injection (XSS)

There are already some places currently vulnerable to JS injection that need to be fixed:

  • account page links
  • account page bio

And some places that should implement the fix when they’re introduced:

  • contribution submission

To do so, my current plan is to follow this guide from Medium and implement a method to escape html characters (<,>,&) before submitting text to the database.

Markdown for works and bios

I may want to add support for markdown at some point. After looking into some options I’ve selected remarkable (cdn) as a favorite, though many are similar. However, this is a minor feature.

Session server race issue

Every time a client authenticates against a session id, the session server reads from the session file (12398509j&^[=Kq.json) to check for expiration (session.login), and then writes back to the file with the new login timestamp. If two requests are made at the same time, one of the instances of sessionserver.get_session() can encounter null when reading from the session file.

To prevent this from happening, I will implement a session cache in the server, which is a list of, say, the 15 most recent sessions created or used for authentication. Whenever the session server calls get_session(), the session cache is first used without needing to read from the session file directly.

When a session id is requested that’s not in the session cache, if the corresponding session file exists then it gets read and inserted into the beginning of the cache. If this addition to the cache makes it exceed the maximum cache size, last (oldest) element gets written to a session file and removed from the cache.

Lastly, to protect against server crashes the whole cache gets written to session files intermittently (say, once per hour).

Work submission and fetch

Work submission via the contribute page is mostly functional (just missing error handling), and the component for the account page is ready for insertion once the database connection is finished.

Works will also need to be editable from the account page, and display information from all of the database columns.

Works will then need to be referenced from fragments in the textile win screen.

English example textile

The only example I have at the moment is “Estante cocinero”, which is in Spanish and not very useful since I’ll be pursuing the English site first. Therefore, a priority in addition to finishing site development is getting a working English example to add to the initial database.

Cache server paths entry not set

No error is thrown when calling cache.set(), but whenever the cache server attempts to retrieve the paths for a puzzle, the result always seems to be null. I wonder if the size of the value to be cached is too large?

Escaped puzzle search

My solution for preventing SQL injection (using mysql.escape()) makes the current dp api endpoint for puzzle search unusable. The way search used to work was by tokenizing a search query, inserting each search term into “like” string:

column like '%term_1%' or column like '%term_2%' or ...

This will no longer work because the escape method in the db server converts the whole expression to a string. I will make the following changes to fix this:

  1. Pass the terms as arguments from dbclient
  2. Create a new boolean special member to denote api endpoints with special implementations
  3. Update dbserver.get_query() to check for special endpoints
  4. Create the search_puzzles endpoint handler, which inserts the search terms into an expression like so (the terms will be filtered so as not to include the apostrophe character:
column regexp '.*((term_1)|(term_2)|...).*'

Make textiles into games

  • constrain shape positions (?) This one’s not very important, won’t do in the near future
  • randomize initial shape positions
  • detect win

Featured puzzle component

As of now the index and textile pages both use 90% of the same html tags and js to handle the puzzle container (title, puzzle canvas, tags). All of that code is duplicated and requires being changed in both pages, which is tedious and error-prone. I’ll probably create a featured_puzzle component to be used in both pages.

Mobile hover alternative

Interaction that requires hovering over widgets on a wide screen don’t translate well to a mobile device. It would be better to have some sort of single-vs-double click support; on a wide screen, A on hover and B on click, but on mobile screens, A on first click (select) and B on second click (activate).

Site administrator privileges section

Somewhere in the site, probably in the footer below the creative commons license explanation, will be a section explaining privileges that the site admins have, and what site admins cannot do.

The site admin reserves the right to:

  • Change account usernames. In the event that existing content in the public domain or with proper permission is available from an author that doesn’t have a Textiles Journal account, that work may be added to the site. In this case, that author will be assigned a blank user account to which to attribute the work. If another user has registered that account, they will be assigned a new username and receive an email notification. If the user dislikes the assigned username, they can request an alternative by sending an email to [email protected].
  • Remove uploaded works deemed unfit for publishing on our site (this includes offensive content, and content that violates copyright, for example)

The site admin cannot:

  • View any account passwords; they’re stored in the database as indecipherable hashes.
  • Determine the author of works uploaded and attributed to “anonymous”; no user account data is tied to a work other than the attributed author name.
  • Violate the license assigned to uploaded contributions.

Puzzle collections

The gallery page lacks a lot of functionality. The first step is to enable puzzle collections: top rated puzzles, editor’s picks, most played, etc. In general, these collections will not correspond directly to db tables, but rather be different selected table joins (ex: top rated = order puzzles by rating, pick top 15; most played = group plays by puzzle, order by count, join with puzzles and pick top 15).

Because of this the operations, though called repetitively, may be computationally expensive for the db. Therefore my plan is to consider each collection as a candidate for a view, which I believe could increase the speed greatly, especially in the case of most-played.

EDIT: Views do not save computation; they are recalculated everytime they’re used, I believe... so it appears I don’t really need to use views for this.

Force https connection with AWS

As it turns out, my current configuration for the load balancer and EC2 instance currently allows plaintext HTTP external connections (with clients), but still encrypts all internal connections (with instances). That means I can now turn on my force_https method again and have all connections be fully encrypted again.

Handle user accounts server-side

So far I’ve added a session server to work with the filesystem and manage session expirations, but have not exposed these methods in the HTTP request routes, nor have I tested this. I’ll also need to incorporate the right amount of information into a session (in addition to latest login timestamp) to make it useable for user login and registration.

Textile win screen

Create a screen that is accessible when a user completes a puzzle to show all the fragments contained within it. Also, make the fragments into links that point to the full works.

Repeated authors

Currently if multiple fragments are by the same author for a puzzle, that author’s name gets appended to the authors metadata tag in the featured puzzle card footer. Each author should only appear once.

Account activity section

The history and records sections of accounts are still only filled with example data, so next up is to pull the user’s plays, ratings, and high scores into that section of the account page.

Add hidden field to puzzles table

If I want to be able to test a new textile before making it public I should be able to see how it runs in the browser, which is easiest done by only loading a puzzle for the user if it’s not hidden, or if the user is an admin.

Handle input length caps in the frontend

I’ve already had to make some changes to input lengths since I made them too low initially, and am realizing that users will be likely confused if they type a very long bio for themselves or description of a work, upload it, and then see it got truncated by the SQL server.

The frontend should at least be able to warn the user about these length limits, which will propagate pretty much anywhere there’s user input. For now, that’s: the login and register forms, contributed works, and account information (links, bio).

Literature work page

Lit works could either be shown in a section of the author’s account page, or could be displayed in a new work.html page.

Get a domain name

After looking up available domain names, probably the best I’ve found are:

  • revistatejos.com (es)
  • textilesjournal.org (en)

DNS providers comparison

domains.google.com = $12/yr
ionos.com = $15/yr (with $1 for first year)
godaddy.com = $21/yr (with $11/yr first year)
dnsimple.com = $50/yr (billed monthly)
amazon route 53 = $12/yr

Sendgrid domain setup

Investigate round-robin DNS as a way to have the same domain point to multiple servers and share traffic. EDIT: this should be possible with AWS rt 53.

Enable email server

Currently the email template system is set up as a .json file of html and plaintext versions of each template. However, it will be a pain to edit these in the future, so I will move to creating an html and txt file for each template.

The email server itself has the nodemailer module set up to create and use a transporter with a test account but not with a real one that requires credentials/tokens.

Explain contribution conditions and guidelines

In the contribute page I need to add a section explaining ways to contribute and what it means to submit a contribution. I’ll format it like a Q&A.

Contribution Explanation Draft

What does it mean to contribute?

To publish new textiles we need new literature content! If you’d like your work(s) to be included in an upcoming textile (poems, stories, random thoughts, deep truth, deeper fiction, ...), submit it here. Our curators will review all submissions and create a selection to be included in each new textile publication.

What about copyright?

By default, when you submit your work we assume you’re releasing it with a Creative Commons, Attribution-Share-Alike (CC BY-SA) license. However, in this contribution form you can also select other licenses, which we will display along with your work wherever it’s referenced. We are not accountable if your work gets stolen or a site visitor violates your license by using it elsewhere. We will respect the CC license by linking your account information to anything you contribute, or link it to “Anonymous” otherwise if that’s your indicated preference in the contribution form.

What happens when I submit a contribution?

Firstly, you’ll see a notification at the top of this page.

Next, if you go to your account page you’ll see that the work was published. If you elected to contribute anonymously, it will only be visible to you, and if it gets included in a textile the attributed author will be listed as “Anonymous”.

Lastly, whever your work gets included in a published textile you’ll receive a notification email.

Who can contribute?

You must be a registered user with an activated account. If you have an account already, you should have gotten a confirmation email with the activation code and a link.

What are you allowed to do with my contribution?

We will include all contributions as candidates for new textiles that get published. When contributed literature gets included in a textile, it will be presented in fragments depending on the visual composition of the puzzle. This means your contribution may be presented whole, or in pieces, once, many times, or not at all.

We will not sell your work to any other party, or reproduce it anywhere but this site.

Improve dbserver security

One security issue I’ve built into the db server system is that the user is expected to perform certain account-specific actions on the database through the session server, which then invokes the db server. However, the db server api still has these endpoints available to external users to use if they customize the url parameters. I need to add a property to endpoints to define whether they’re internal or external. If it’s internal, only other modules within the server can access that endpoint.

UPDATE: this is now fixed.

Account delete button appears when not logged in

I forgot to hide the delete-account button on login if the user is not visiting their own account page. It correctly doesn’t work when clicked in this situation, but it shouldn’t show up at all.

Don’t include node_modules in git

I’ve since learned how to limit the size of the git repository by not including any dependencies downloaded to the node_modules/ directory. Rely instead of the package.json and package-lock.json files to keep track of them for when they’re needed.

Add copyright info to the footer, works, and fragments

In the fragment and work components that will eventually be created, encapsulate all titles in a details container:

<details>
    <summary>
        Work Title
    </summary>
    <p>
        copyright info here
    </p>
</details>

In the website footer, add a similar section covering copyright information for the site as a whole.

Site and db administration

My short-term plan is to administrate everything by working directly with the db through an sql terminal. However, it would be much smoother long-term to be able to perform admin actions through the site, by using the people.admin field and corresponding creating db api endpoints.

This is not urgent though.

Puzzle graphics load very slowly

The underlying problem is most definitely the background text path; since it’s a scan of a full page of dense handwriting, the resulting compound path ends up containing thousands of control points. I need to find ways of shrinking the text path:

  • use a raster for the text layer.
    • easy way: convert the text layer to raster using rasterize(), picking a suitable dpi.
    • hard way: store the image in bmp format in the database, picking a suitable resolution
  • wrap paperjs actions in asynchronous blocks so other widgets in the page don’t freeze

Add favicon file

Not very important yet, but the website tab icon can be a sort of cherry on top when it’s near complete.

EDIT: Done.

Force https connection

I just wondered whether the client side could detect if the site location is http or https protocol, and the switch automatically to the more secure https before loading the rest of the page. It turns out this is pretty easy to do, so I’ll add that function as well.

Handle user accounts client-side

So far I’ve added the basic sessionclient.js and cookies.js libraries, but have not incorporated use of them into any of the webpages. I’m still working out how accounts will be handled given the following scenarios:

  • the user was never logged in (has no session cookie or related cookies)
  • the user has logged in before but the session has expired (get new session from server)
  • the user has logged in before and the session is still valid (use session when submitting requests that require account credentials)

Enable accounts page

Load all account data into the accounts page, and make all account data modifiable.

Puzzle shape winding rules

As I was writing the explanation of this issue I figured out the solution, so it’ll be resolved after this comment. Basically, some paths were defined in clockwise order, and others counterclockwise, depending on how I traced them in Inkscape. This caused problems when trying to use them as clipping paths. The solution was to use paper.PathItem.reorient(clockwise=true) whenever encountering a shape defined in counterclockwise order.

Cache server entry expiration

I’m setting up the db server so that collections get added to the memcache for quick access, but with this scenario I realize that cache entries will need a TTL/expiration system so that they can be updated. In the case of a collection, an entry for collection_editors_choice might only need to be updated once per week, while collection_top_played and collection_top_rated would need to be cleared from the cache server more frequently.

EDIT: I forgot there’s already an expires argument in the cache.set(...) method, so I can just customize that argument for different entries.

Hide credentials

This app is not at all secure because all the connection credentials (database, memcached, email server) are stored along with the source code in the same repository. The credentials need to be kept secret by removing them from the github directory and creating environment variables in the server host environment.

Add scale field to puzzle table

Each puzzle will have its own scaling transform when rendering due to inconsistencies in the size of the drawing, in scanning the text and shape paths, then converting to svg, then tracing and aligning, etc.

Migrate from heroku

Some other that the hosted webserver, there were some other resources provisioned through heroku (as in the database and memcache dictionary) which will need to be migrated.

The MySQL database (provided by JawsDB in heroku) actually is hosted by aws, so I’ll just be skipping the middleman in that case.

The memcache server may be a bit less clear to set up (provided by Redis Labs in heroku), but I think aws Elasticache for Memcached should do the trick.

I also can get rid of documentation and source code related to the heroku environment.

About page

Fill in the main content, as well as my own contact card for the right column. The main column will be broken into a number of different secions:

Textiles

You may find yourself wondering, What do textiles have to do with any of this? Well, while the rest of the world uses this word to refer to fabrics, we’ve repurposed it to refer to our new kind of puzzle. A textile consists of a dense patchwork of free-form text as a background, obscured by an opaque cover, and the player/solver/reader can see through the cover via specifically shaped windows. The player moves those shape windows around until each is looking at its corresponding hidden text. Once all the shapes are placed correctly, the textile is solved!

The ways in which one can arrive at the solution are multiple: the shapes together will often reveal some sort of image or scene, and each shape will contain within it a selection of text that matches in some way (by subject matter, symbol, imagery, etc).

The Big Ideas

I’ve felt one of the principle struggles of literature in recent years has been a war waged against new forms of communication and entertainment: photography, movies, television, social media, video games. Each one has offered something new and exciting that simple text has had to compete with. A picture is worth 1000 words, after all. Movies are worth thousands of pictures (not to mention the audio). Social media incorporates multimedia presentation and instant connection. Video games add interaction and the infinity of virtual space.

This has not been strictly a losing battle for literature, however. There are countless ways that artists of letters– authors, journalists, screen writers, poets, song writers– have combated their rival art forms, and have found means of adapting to fit in with new media. The Textiles Journal is but one of these. With this journal we are attempting to create a new medium for literature, taking cues from its rivals: it’s available online, it’s both textual and visual, and it’s interactive.

So, depending on how you see it, one might even call us revolutionary.

Participating

This is still a newborn project with few visitors, few registered accounts, few contributors, a tiny team, missing features, errors,... you get the picture. That said, we’d like all the help we can get! If you’re interested in the site, register an account with us. If you are a writer and are looking for somewhere to share, look no further; see the Contribute page for more details. If you’re up for the challenge you can even send us a whole textile to publish! See How it’s Made for how to do so. If you’re knowledgable in web development and would like to test/review/debug/improve the source, visit the Github page.

The basic takeaway is: if you want to get involved in some way, please do!

How it’s Made

Our methodology for creating a new textile is fairly low-tech and requires no software or equipment purchases. If you’re interested, give it a go yourself and send us the result to [email protected]!

  1. Literature content
    To start you need some text fragments. There are essentially no rules here, though it can’t bee too long since it’ll all need to fit inside the space of the textile. It can be from a single work, or from multiple. A work is a source text that the textile will use, and a fragment is an excerpt that is found verbatim in the textile. Make sure you’re allowed to use the work(s), of course. Keep track of what gets used in the textile so that we can publish it with references to included works.

  2. Shapes
    Next you need some shapes (by the way, steps (1) and (2) can be done simultaneously or in reverse order, too. Not all songs are lyrics with music added after, or all music with lyrics added after). Each shape will act as a piece in the puzzle, and as a window to view the text behind it. The shapes should in some way relate to the text where they belong.

  3. Composition
    Before you can put it all together together, here are some questions to think about. How do the shapes relate to each other? Where should they go? Also, what will go between the shapes? A good textile will probably not just have white space between each area where a shape goes.

  4. Execute
    It’s finally time to create something. There is more than one way to do this step, but I'll describe our specific method here.

    • Get two pieces of blank paper that are not too think (printer paper is good). On one page, draw the shapes with a clearly visible pen that won’t smudge too much. On the other page, draw the text. To make the two pages line up, you can place them in a stack on a light box or over a window, “onion-skinning” as one would do for consecutive frames in 2D animation.
    • Once the pages are done, scan each one to an image (something like a png or jpeg should work). If you don’t have a scanner available I suggest trying Scannable, by Evernote.
    • Each scan is then binarized (turned to a black-or-white image) and vectorized (from pixel raster to scalable geometry). You can use something like the following shell script, which uses ffmpeg and potrace.
#!/bin/bash
# vectorize_img
# Owen Gallagher
# 1 August 2019

# usage to convert image.png to image.svg:    $vectorize_img image png;

#set input file, filetype, and destination directory
if [[ -z $1 ]]
then
	echo 'Error arg1: no input filename included'
	exit 1
else
	if [[ -z $2 ]]
	then
		echo 'Error arg2: no input filetype included'
		exit 2
	fi
fi

img=$1
ext=$2

#convert to bitmap image
ffmpeg -i ${img}.${ext} ${img}.bmp

#vectorize
#customize blacklevel to set threshold for vectorization
potrace --svg --progress --blacklevel 0.5 ${img}.bmp

#see results
open ${img}.svg -a /Applications/Safari.app
  1. Create the SVG
    Import the shapes and text vector (svg) files into an Inkscape project, and resize them so they are properly aligned. You can use the app to modify the shapes as well. We always replace the shapes with simplified ones drawn in Inkscape, to shrink the file size. If you have the patience, you can also simplify the paths of the text, which greatly reduces the file size for us.

  2. Export the SVG
    This step is not necessary, and if you send us the result from step (5) we’ll take care of the rest. However, if you can, it makes things a lot quicker for us if you combine all the text into one path, and keep the shapes each as its own path. Also, don’t use any transforms (be careful with <g> groups; they will often have transforms which need to be applied to child nodes). Then, open the svg file in a text editor, and open a new blank text file also. In the blank text file, paste the path data (<path d="COPY ME”/>) for the text and label it. Then, do the same for each shape.

  3. Send it to us
    Finally, send us the text fragments, the text file with the path data, and (optional) the svg file. We’ll review them, let you know whether we add them to the site, and credit you as the textile designer for it.

Fulfilling the web design rubric

  • design gallery page
  • design account page
  • answer the 4 navigation questions (where now, where from, where to, how)
  • code comments
  • test against html standards
  • written documentation?

Shared EFS between server instances

Looking into the persistence of an https connection, it seems that a connection between a server and a client should remain established through keep-alive messages that are sent from the client. However, I see it highly probable that at some point during a site visit a client temporarily loses connection and the https session closes, which, when reopened, could connect that client to a different server instance.

This introduces a new problem if I scale up to multiple instances because now a user’s session could suddenly disappear from the server if the server that client was connected to suddenly gets swapped with another by the ALB (app load balancer). A way around this issue is to use a shared Elastic File System (EFS), which all instances can share, and in which sessions can be stored.

An alternative would be to just handle the possibility that sessions disappear and require that the client intermittently log in again, but this seems like a worse solution. Plus, the extra cost of an EFS could be mitigated by limiting the number of sessions stored, in addition to their expiration dates.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.