{"id":18983678,"url":"https://github.com/snapframework/cufp2011","last_synced_at":"2025-07-13T18:42:14.346Z","repository":{"id":66279674,"uuid":"2309725","full_name":"snapframework/cufp2011","owner":"snapframework","description":"Code for the CUFP 2011 Snap Framework Tutorial","archived":false,"fork":false,"pushed_at":"2013-04-15T09:06:14.000Z","size":211,"stargazers_count":21,"open_issues_count":0,"forks_count":1,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-03-25T21:19:31.408Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snapframework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-09-01T19:11:37.000Z","updated_at":"2022-02-09T03:05:51.000Z","dependencies_parsed_at":"2023-02-20T01:30:46.630Z","dependency_job_id":null,"html_url":"https://github.com/snapframework/cufp2011","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapframework%2Fcufp2011","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapframework%2Fcufp2011/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapframework%2Fcufp2011/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snapframework%2Fcufp2011/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snapframework","download_url":"https://codeload.github.com/snapframework/cufp2011/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223713391,"owners_count":17190503,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T16:17:58.520Z","updated_at":"2024-11-08T16:17:59.060Z","avatar_url":"https://github.com/snapframework.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CUFP 2011 Tutorial: Web programming in Haskell with the Snap Framework\n\nThis repository contains code for the CUFP 2011 tutorial\n[The Snap Framework for web applications in Haskell](http://cufp.org/conference/sessions/2011/t7-snap-framework-web-applications-haskell-gregory).\nYou will be building a simplified web application implementing multi-user chat.\n\n\n## Getting started\n\nFrom the project root directory, running `cabal install` should build the\n`snap-chat` and `snap-chat-sample` executables. You can find these executables\nin the `dist/build/` subdirectory. To run the sample application (to see what\nthe result should look like), run\n`dist/build/snap-chat-sample/snap-chat-sample` and point your browser to\n[`http://localhost:8000/`](http://localhost:8000/).\n\nThe sample implementation of the code you're expected to provide can be found\nin the `sample-implementation/` directory; however **please don't peek** unless\nyou get really stuck. We'll be working through the code together.\n\nTest code (so you can test your implementation against the expected result) can\nbe found in the `test/` directory; to run it:\n\n    cd test\n    cabal install\n    ./runTestsAndCoverage.sh\n\n\n## Specifications\n\nSnap Chat is split into three functional components:\n\n  * a data model, consisting of Haskell code for interacting with a chat\n    channel; see `src/Snap/Chat/Types.hs`, `src/Snap/Chat/ChatRoom.hs`, and\n    `src/Snap/Chat/Message.hs` for the implementation here.\n\n  * a JSON API that provides access to the data model; this consists of HTTP\n    `POST` handlers for the URL endpoints:\n\n    * `/api/join`, to join the chat channel\n    * `/api/leave`, to leave the chat channel\n    * `/api/fetch`, to fetch new messages written to the chat channel (using\n      long-polling)\n    * `/api/write`, to write a message to the chat channel.\n\n    These API endpoints will be described in further detail later.\n\n  * an HTML5/Javascript front end that calls the JSON api.\n\nFor brevity and to bound the amount of work students are expected to do in the\nshort tutorial, most of the code is already provided, including all of the\nJavaScript (this is a Haskell tutorial!), the data model code, and all of the\ndatatypes. More advanced students who quickly breeze through the small amount\nof work provided can check out the \"extra credit\" section at the end of this\ndocument.\n\n\n### API documentation\n\nEach of the four API calls (`/api/join`, `/api/leave`, `/api/fetch`,\n`/api/write`) share a similar structure: they all respond only to POST requests\ncontaining a UTF8-encoded JSON document as the request body; i.e. the\n`Content-Type` of the input request is `application/json`, and they all produce\na JSON document as the result. The output responses have the following common\nstructure: either they succeed, producing a document like the following:\n\n    {\n      \"status\": \"ok\",\n      \"session\": \"DF1642....038A=\",\n      \"response\": { ...some json object... }\n    }\n\nWhen they fail, the output document looks like this:\n\n    {\n      \"status\": \"failure\",\n      \"statusCode\": \"some_failure\",\n      \"reason\": \"blah blah blah blah.\"\n    }\n\nThe \"session\" variable above deserves some special mention: upon successfully\njoining the chat room, the user will receive an encrypted session token, which\nwill be used on subsequent requests to re-authenticate the user with the chat\nroom. Upon each response, a fresh session token will be generated. The contents\nof the session token are opaque to the API user, but can be decrypted on the\nserver-side.\n\nThe data type for the encoded session looks like this (see\n`src/Snap/Chat/Internal/API/Types.hs`):\n\n    data EncodedSession = EncodedSession {\n          _sessionToken :: UserToken\n        , _sessionTime  :: EpochTime\n        , _apiUser      :: UserName\n        }\n\nA session will only be considered valid if:\n\n  * the session time is not too old.\n\n  * the user name and user token match what is contained in the chat room data\n    model.\n\n\n#### /api/join\n\nThe \"join\" command is responsible for connecting a user to the chat room with a\ngiven user name.\n\nExample request:\n\n    { \"desiredUserName\": \"george\" }\n\nExample successful response:\n\n    {\n      \"status\": \"ok\",\n      \"session\": \"abc.....def\",\n      \"response\": {}\n    }\n\nExample unsuccessful response:\n\n    {\n      \"status\": \"failure\",\n      \"statusCode\": \"user_already_exists\",\n      \"reason\": \"Cannot log in; a user with that name is already connected \\\n                 to the channel.\"\n    }\n\n\n#### /api/leave\n\nThe \"leave\" command logs the user out of the chat room.\n\nExample request:\n\n    {\n      \"session\": \"abc.....def\",\n      \"requestData\": {}\n    }\n\nExample successful response:\n\n    {\n      \"status\": \"ok\",\n      \"session\": \"abc.....def\",\n      \"response\": {}\n    }\n\n#### /api/fetch\n\nThe \"fetch\" command gets new messages from the chat room, blocking for up to 50\nseconds before it returns with a list of new messages, possibly empty.\n\nExample request:\n\n    {\n      \"session\": \"abc.....def\",\n      \"requestData\": {}\n    }\n\nExample successful response:\n\n    {\n      \"status\": \"ok\",\n      \"session\": \"abc.....def\",\n      \"response\": { \"messages\": [ ...messages... ] }\n    }\n\nThe JSON type of messages is as follows:\n\n    { \"contents\": {\n        \"type\": \u003c\u003cone of \"talk\", \"action\", \"join\", \"leave\"\u003e\u003e,\n        \"text\": \"message text\"\n        },\n      \"user\": \"fred\",\n      \"time\": \u003c\u003cposix timestamp\u003e\u003e\n    }\n\n\n#### /api/write\n\nThe \"write\" command writes a message to the chat room.\n\nExample request:\n\n    {\n      \"session\": \"abc.....def\",\n      \"requestData\": {\n          \"type\": \u003c\u003cone of \"talk\", \"action\"\u003e\u003e,\n          \"text\": \"message text\"\n        }\n    }\n\nExample successful response:\n\n    {\n      \"status\": \"ok\",\n      \"session\": \"abc.....def\",\n      \"response\": {}\n    }\n\n\n## What students must implement\n\nSeveral functions and instances in the source tree have been marked as\n\"toBeImplemented\". Tutorial attendees must implement:\n\n  * `ToJSON` and `FromJSON` instances for the types in\n    `src/Snap/Chat/Internal/API/Types.hs`.\n    \n  * `ToJSON` and `FromJSON` instances for the message types in\n    `src/Snap/Chat/Internal/Types.hs`.\n    \n  * all of the stubbed-out functions in `src/Snap/Chat/API/Handlers.hs`.\n\nYou'll need to use the functions from `src/Snap/Chat/ChatRoom.hs`, which\ncontains all of the \"business logic\" for the chat rooms.\n\n\n## Extra credit\n\nIf you finish early and get bored, here are some ideas for \"extra-credit\"\nassignments:\n\n  * extend the chat channel with a user list\n\n  * add private user-to-user messages\n\n  * support multiple chat rooms\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapframework%2Fcufp2011","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnapframework%2Fcufp2011","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapframework%2Fcufp2011/lists"}