1 module vibelog.dbcontroller;
2 
3 public import vibelog.config;
4 public import vibelog.post;
5 public import vibelog.user;
6 
7 import vibe.db.mongo.mongo;
8 import vibe.core.log;
9 import vibe.data.bson;
10 
11 import std.exception;
12 
13 
14 class DBController {
15 	private {
16 		MongoDB m_db;
17 		string m_dbname;
18 		MongoCollection m_configs;
19 		MongoCollection m_users;
20 		MongoCollection m_posts;
21 	}
22 
23 	this(string host, ushort port, string dbname)
24 	{
25 		m_db = connectMongoDB(host, port);
26 		m_dbname = dbname;
27 		m_configs = m_db[m_dbname~"."~"configs"];
28 		m_users = m_db[m_dbname~"."~"users"];
29 		m_posts = m_db[m_dbname~"."~"posts"];
30 	}
31 
32 	Config getConfig(string name, bool createdefault = false)
33 	{
34 		auto configbson = m_configs.findOne(["name": Bson(name)]);
35 		if( !configbson.isNull() )
36 			return Config.fromBson(configbson);
37 		enforce(createdefault, "Configuration does not exist.");
38 		auto cfg = new Config;
39 		cfg.name = name;
40 		m_configs.insert(cfg.toBson());
41 		return cfg;
42 	}
43 
44 	void setConfig(Config cfg)
45 	{
46 		Bson update = cfg.toBson();
47 		m_configs.update(["name": Bson(cfg.name)], update);
48 	}
49 
50 	void deleteConfig(string name)
51 	{
52 		m_configs.remove(["name": Bson(name)]);
53 	}
54 
55 	Config[] getAllConfigs()
56 	{
57 		Bson[string] query;
58 		Config[] ret;
59 		foreach( config; m_configs.find(query) ){
60 			auto c = Config.fromBson(config);
61 			ret ~= c;
62 		}
63 		return ret;
64 	}
65 
66 	User[string] getAllUsers()
67 	{
68 		Bson[string] query;
69 		User[string] ret;
70 		foreach( user; m_users.find(query) ){
71 			auto u = User.fromBson(user);
72 			ret[u.username] = u;
73 		}
74 		if( ret.length == 0 ){
75 			auto initial_admin = new User;
76 			initial_admin.username = "admin";
77 			initial_admin.password = generatePasswordHash("admin");
78 			initial_admin.name = "Default Administrator";
79 			initial_admin.groups ~= "admin";
80 			m_users.insert(initial_admin);
81 			ret["admin"] = initial_admin;
82 		}
83 		return ret;
84 	}
85 	
86 	User getUser(BsonObjectID userid)
87 	{
88 		auto userbson = m_users.findOne(["_id": Bson(userid)]);
89 		return User.fromBson(userbson);
90 	}
91 
92 	User getUser(string name)
93 	{
94 		auto userbson = m_users.findOne(["username": Bson(name)]);
95 		if( userbson.isNull() ){
96 			auto id = BsonObjectID.fromHexString(name);
97 			logDebug("%s <-> %s", name, id.toString());
98 			assert(id.toString() == name);
99 			userbson = m_users.findOne(["_id": Bson(id)]);
100 		}
101 		//auto userbson = m_users.findOne(Bson(["name" : Bson(name)]));
102 		return User.fromBson(userbson);
103 	}
104 
105 	BsonObjectID addUser(User user)
106 	{
107 		auto id = BsonObjectID.generate();
108 		Bson userbson = user.toBson();
109 		userbson["_id"] = Bson(id);
110 		m_users.insert(userbson);
111 		return id;
112 	}
113 
114 	void modifyUser(User user)
115 	{
116 		assert(user._id.valid);
117 		Bson update = user.toBson();
118 		m_users.update(["_id": Bson(user._id)], update);
119 	}
120 
121 	void deleteUser(BsonObjectID id)
122 	{
123 		assert(id.valid);
124 		m_users.remove(["_id": Bson(id)]);
125 	}
126 
127 	int countPostsForCategory(string[] categories)
128 	{
129 		int cnt;
130 		getPostsForCategory(categories, 0, (size_t, Post p){ if( p.isPublic ) cnt++; return true; });
131 		return cnt;
132 	}
133 
134 	void getPostsForCategory(string[] categories, int nskip, bool delegate(size_t idx, Post post) del)
135 	{
136 		auto cats = new Bson[categories.length];
137 		foreach( i; 0 .. categories.length ) cats[i] = Bson(categories[i]);
138 		Bson category = Bson(["$in" : Bson(cats)]);
139 		Bson[string] query = ["query" : Bson(["category" : category]), "orderby" : Bson(["_id" : Bson(-1)])];
140 		foreach( idx, post; m_posts.find(query, null, QueryFlags.None, nskip) ){
141 			if( !del(idx, Post.fromBson(post)) )
142 				break;
143 		}
144 	}
145 
146 	void getPublicPostsForCategory(string[] categories, int nskip, bool delegate(size_t idx, Post post) del)
147 	{
148 		auto cats = new Bson[categories.length];
149 		foreach( i; 0 .. categories.length ) cats[i] = Bson(categories[i]);
150 		Bson category = Bson(["$in" : Bson(cats)]);
151 		Bson[string] query = ["query" : Bson(["category" : category, "isPublic": Bson(true)]), "orderby" : Bson(["_id" : Bson(-1)])];
152 		foreach( idx, post; m_posts.find(query, null, QueryFlags.None, nskip) ){
153 			if( !del(idx, Post.fromBson(post)) )
154 				break;
155 		}
156 	}
157 
158 	void getAllPosts(int nskip, bool delegate(size_t idx, Post post) del)
159 	{
160 		Bson[string] query;
161 		Bson[string] extquery = ["query" : Bson(query), "orderby" : Bson(["_id" : Bson(-1)])];
162 		foreach( idx, post; m_posts.find(extquery, null, QueryFlags.None, nskip) ){
163 			if( !del(idx, Post.fromBson(post)) )
164 				break;
165 		}
166 	}
167 
168 
169 	Post getPost(BsonObjectID postid)
170 	{
171 		auto postbson = m_posts.findOne(["_id": Bson(postid)]);
172 		return Post.fromBson(postbson);
173 	}
174 
175 	Post getPost(string name)
176 	{
177 		auto postbson = m_posts.findOne(["slug": Bson(name)]);
178 		if( postbson.isNull() )
179 			postbson = m_posts.findOne(["_id" : Bson(BsonObjectID.fromHexString(name))]);
180 		return Post.fromBson(postbson);
181 	}
182 
183 	bool hasPost(string name)
184 	{
185 		return !m_posts.findOne(["slug": Bson(name)]).isNull();
186 
187 	}
188 
189 	BsonObjectID addPost(Post post)
190 	{
191 		auto id = BsonObjectID.generate();
192 		Bson postbson = post.toBson();
193 		postbson["_id"] = Bson(id);
194 		m_posts.insert(postbson);
195 		return id;
196 	}
197 
198 	void modifyPost(Post post)
199 	{
200 		assert(post.id.valid);
201 		Bson update = post.toBson();
202 		m_posts.update(["_id": Bson(post.id)], update);
203 	}
204 
205 	void deletePost(BsonObjectID id)
206 	{
207 		assert(id.valid);
208 		m_posts.remove(["_id": Bson(id)]);
209 	}
210 
211 
212 	void addComment(BsonObjectID post, Comment comment)
213 	{
214 		Bson cmtbson = comment.toBson();
215 		m_posts.update(["_id": Bson(post)], Bson(["$push" : Bson(["comments" : cmtbson])]));
216 	}
217 }