changeset 4:2da10ece826f

add Chat
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 27 Oct 2024 20:39:18 -0600
parents 2c63b10781e1
children a49866b52cc2
files .hgignore src/account.html.luan src/chat.html.luan src/lib/Chat.luan src/lib/Db.luan src/lib/User.luan src/lib/Utils.luan src/private/tools/index.html.luan src/private/tools/run.luan src/private/tools/shell.html.luan
diffstat 10 files changed, 227 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Oct 24 21:43:44 2024 -0600
+++ b/.hgignore	Sun Oct 27 20:39:18 2024 -0600
@@ -2,3 +2,4 @@
 
 err
 local/
+mine/
--- a/src/account.html.luan	Thu Oct 24 21:43:44 2024 -0600
+++ b/src/account.html.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -19,6 +19,7 @@
 <%		header() %>
 		<div content>
 			<h1>Your Account</h1>
+			<p><a href="chat.html">Your Chats</a></p>
 			<p><a href="javascript:logout()">Logout</a></p>
 		</div>
 	</body>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/chat.html.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -0,0 +1,93 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local ipairs = Luan.ipairs or error()
+local pairs = Luan.pairs or error()
+local Table = require "luan:Table.luan"
+local concat = Table.concat or error()
+local Io = require "luan:Io.luan"
+local Http = require "luan:http/Http.luan"
+local Shared = require "site:/lib/Shared.luan"
+local head = Shared.head or error()
+local header = Shared.header or error()
+local User = require "site:/lib/User.luan"
+local current_user = User.current_required or error()
+local get_user_by_id = User.get_by_id or error()
+local get_user_by_email = User.get_by_email or error()
+local Utils = require "site:/lib/Utils.luan"
+local to_set = Utils.to_set or error()
+local Db = require "site:/lib/Db.luan"
+local run_in_transaction = Db.run_in_transaction or error()
+local Chat = require "site:/lib/Chat.luan"
+local chat_search = Chat.search or error()
+
+
+local function other_users(user,chat)
+	local my_id = user.id
+	local t = {}
+	for _, user_id in ipairs(chat.user_ids) do
+		if user_id ~= my_id then
+			local other_user = get_user_by_id(user_id) or error()
+			t[#t+1] = other_user.email
+		end
+	end
+	return concat( t, ", " )
+end
+
+local function get_chat(with)
+	local t = {}
+	local ids = {}
+	for email in pairs(with) do
+		local with_user = get_user_by_email(email) or error()
+		local id = with_user.id
+		t[#t+1] = "+chat_user_ids:"..id
+		ids[#ids+1] = id
+	end
+	local query = concat(t," ")
+	run_in_transaction( function()
+		local chats = chat_search(query)
+		local n = #chats
+		if n == 0 then
+			local chat = Chat.new{
+				user_ids = ids
+			}
+			chat.save()
+			return chat
+		elseif n == 1 then
+			return chats[1]
+		else
+			error("multiple chats for: "..query)
+		end
+	end )
+end
+
+return function()
+	local user = current_user()
+	if user == nil then
+		return
+	end
+	local with = Http.request.parameters.with
+	if with ~= nil then
+		with = to_set(with)
+		with[user.email] = true
+		get_chat(with)
+	end
+	local chats = user.get_chats()
+	Io.stdout = Http.response.text_writer()
+%>
+<!doctype html>
+<html>
+	<head>
+<%		head() %>
+	</head>
+	<body>
+<%		header() %>
+		<div content>
+			<h1>Chat</h1>
+<%	for _, chat in ipairs(chats) do %>
+			<p><%= other_users(user,chat) %></p>
+<%	end %>
+		</div>
+	</body>
+</html>
+<%
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/Chat.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -0,0 +1,60 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local ipairs = Luan.ipairs or error()
+local Time = require "luan:Time.luan"
+local time_now = Time.now or error()
+local Db = require "site:/lib/Db.luan"
+local run_in_transaction = Db.run_in_transaction or error()
+
+
+local Chat = {}
+
+local function from_doc(doc)
+	doc.type == "chat" or error "wrong type"
+	return Chat.new {
+		id = doc.id
+		user_ids = doc.chat_user_ids
+		updated = doc.chat_updated
+	}
+end
+
+local function to_doc(chat)
+	return {
+		type = "chat"
+		id = chat.id
+		chat_user_ids = chat.user_ids or error()
+		chat_updated = chat.updated or error()
+	}
+end
+
+function Chat.new(chat)
+	chat.updated = chat.updated or time_now()
+
+	function chat.save()
+		local doc = to_doc(chat)
+		Db.save(doc)
+		chat.id = doc.id
+	end
+
+	function chat.delete()
+		run_in_transaction( function()
+			local id = chat.id
+			-- Db.delete("chat_user_ids:"..id)
+			Db.delete("id:"..id)
+		end )
+	end
+
+	return chat
+end
+
+function Chat.search(query,sort,rows)
+	rows = rows or 1000000
+	local chats = {}
+	local docs = Db.search(query,1,rows,{sort=sort})
+	for _, doc in ipairs(docs) do
+		chats[#chats+1] = from_doc(doc)
+	end
+	return chats
+end
+
+return Chat
--- a/src/lib/Db.luan	Thu Oct 24 21:43:44 2024 -0600
+++ b/src/lib/Db.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -21,6 +21,9 @@
 
 Db.indexed_fields.user_email = Lucene.type.lowercase
 
+Db.indexed_fields.chat_user_ids = Lucene.type.long
+Db.indexed_fields.chat_updated = Lucene.type.long
+
 function Db.not_in_transaction()
 	logger.error(new_error("not in transaction"))
 end
--- a/src/lib/User.luan	Thu Oct 24 21:43:44 2024 -0600
+++ b/src/lib/User.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -16,6 +16,7 @@
 local Http = require "luan:http/Http.luan"
 local Db = require "site:/lib/Db.luan"
 local run_in_transaction = Db.run_in_transaction or error()
+local Chat = require "site:/lib/Chat.luan"
 local Logging = require "luan:logging/Logging.luan"
 local logger = Logging.logger "User"
 
@@ -48,8 +49,15 @@
 		user.id = doc.id
 	end
 
-	function user.reload()
-		return User.get_by_id(user.id) or error(user.id)
+	function user.delete()
+		run_in_transaction( function()
+			local id = user.id
+			local chats = Chat.search("chat_user_ids:"..id)
+			for _, chat in ipairs(chats) do
+				chat.delete()
+			end
+			Db.delete("id:"..id)
+		end )
 	end
 
 	function user.login()
@@ -60,6 +68,13 @@
 		Http.request.cookies.password = user.password or error()
 	end
 
+	function user.get_chats()
+		return Chat.search("chat_user_ids:"..user.id)
+	end
+
+	function user.get_or_create_chat_with(emails)
+	end
+
 	return user
 end
 
@@ -87,19 +102,23 @@
 	return concat(t)
 end
 
+local function get_by_email(email)
+	local doc = Db.get_document("user_email:"..lucene_quote(email))
+	return doc and from_doc(doc)
+end
+User.get_by_email = get_by_email
+
 function User.get_or_create_by_email(email)
 	return run_in_transaction( function()
-		local doc = Db.get_document("user_email:"..lucene_quote(email))
-		if doc ~= nil then
-			return from_doc(doc)
-		else
-			local user = User.new{
+		local user = get_by_email(email)
+		if user == nil then
+			user = User.new{
 				email = email
 				password = new_password()
 			}
 			user.save()
-			return user
 		end
+		return user
 	end )
 end
 
--- a/src/lib/Utils.luan	Thu Oct 24 21:43:44 2024 -0600
+++ b/src/lib/Utils.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -1,5 +1,8 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
+local type = Luan.type or error()
+local ipairs = Luan.ipairs or error()
+local set_metatable = Luan.set_metatable or error()
 local Http = require "luan:http/Http.luan"
 
 
@@ -10,4 +13,39 @@
 	return request.scheme.."://"..request.headers["Host"]
 end
 
+function Utils.to_list(input)
+	if input == nil then
+		return {}
+	elseif type(input) == "table" then
+		return input
+	else
+		return {input}
+	end
+end
+
+local set_mt = {}
+function set_mt.__index(table,key)
+	return false
+end
+
+local function list_to_set(list)
+	local set = {}
+	for _, v in ipairs(list) do
+		set[v] = true
+	end
+	set_metatable(set,set_mt)
+	return set
+end
+Utils.list_to_set = list_to_set
+
+function Utils.to_set(obj)
+	if obj == nil then
+		return {}
+	elseif type(obj) == "table" then
+		return list_to_set(obj)
+	else
+		return {[obj]=true}
+	end
+end
+
 return Utils
--- a/src/private/tools/index.html.luan	Thu Oct 24 21:43:44 2024 -0600
+++ b/src/private/tools/index.html.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -21,6 +21,8 @@
 			<h1>Private Tools</h1>
 			<p><a href="config.html">configure</a></p>
 			<p><a href="lucene.html">lucene</a></p>
+			<p><a href="shell.html">luan shell</a></p>
+			<p><a href="run">luan batch</a></p>
 		</div>
 	</body>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/private/tools/run.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -0,0 +1,1 @@
+return require("luan:http/tools/Run.luan").respond
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/private/tools/shell.html.luan	Sun Oct 27 20:39:18 2024 -0600
@@ -0,0 +1,1 @@
+return require("luan:http/tools/Shell.luan").respond