aboutsummaryrefslogtreecommitdiff
path: root/lib/migrate.php
blob: 43a003a3c92b941e9c69898749752d07fe58126b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
<?php

// need access to ElggDiskFilestore::make_file_matrix(), which is protected.
// this is a PITA.
class tempFilestore extends ElggDiskFilestore {
	public function make_file_matrix($filename) {
		return parent::make_file_matrix($filename);
	}

}
$filestore = new tempFilestore();



/**
 * Migrates all pics from files to tidypics.
 *
 */
function tidypics_migrate_pics() {
	$limit = 100;
	$r = true;

	// migrate
	// @todo: should this return false since there was no error?
	if (!$users = tidypics_get_user_guids_with_pics_in_files(0, $limit)) {
		return $r;
	}

	//echo "Grabbed " . count($users) . " users\n";
	while (is_array($users) AND count($users) > 0) {
		foreach ($users as $user_guid) {
			// reset the query cache.
			$DB_QUERY_CACHE = array();
			if (!$user = get_entity($user_guid)) {
				continue;
			}

			$r = tidypics_migrate_user_pics($user);
		}

		//echo "Trying to grab $limit more users...\n";
		$offset = $offset + $limit;
		$users = tidypics_get_user_guids_with_pics_in_files($offset, $limit);
	}

	return $r;
}


/**
 * Migrates all pictures owned by a user regardless of
 * if they're group or user files.
 * 
 * @param ElggUser $user User to migrate.
 * @return bool on success
 */
function tidypics_migrate_user_pics(ElggUser $user) {
	global $CONFIG, $filestore;

	// update all entity subtypes in a single go at the end.
	$updated_guids = array();

	if (!$pics = tidypics_get_user_pics_from_files($user_guid) OR count($pics) < 1) {
		return false;
	}

	//echo "{$user->name} ({$user->getGUID()}) has " . count($pics) . " pics.\n";
	
	// get an album to migrate into if it already exists.
	// will create later on if it doesn't.
	$user_album_entities = get_entities_from_metadata('migrated_from_files', true, 'object', 'album', $user->getGUID(), 1);
	$user_album_guid = isset($album_entities[0]) ? $album_entities[0]->getGUID() : false;

	// a list of albums to randomly select a cover for on newly created albums.
	$new_album_guids = array();

	foreach ($pics as $pic) {
		// check that it's not already in tidy pics
		if (false !== strpos($pic->filename, 'image/')) {
			//echo "{$pic->filename} ({$pic->getGUID()}) looks like it's already in tidy pics. Ignoring.\n";
			continue;
		}
	
		// blank some vars
		$group_pic = $group_album_guid = $group_guid = false;
		
		// see if we're doing a group file migration.
		if ($pic->container_guid != $user->getGUID() 
			AND $group = get_entity($pic->container_guid)
			AND $group instanceof ElggGroup
		) {
			//echo "{$pic->getGUID()} is in a group!\n";
			$group_pic = true;
			$group_guid = $group->getGUID();
			
			// yes, this is how you get entities by container_guid.
			// yes, it's wrong, wrong, wrong for this function to work this way.
			$group_album_entities = get_entities('object', 'album', $group_guid);
			
			// get_entities_from_metadata doesn't support container_guid (or owner_guid meaning container_guid)
			// do it the hard way.
			if (is_array($group_album_entities)) {
				foreach ($group_album_entities as $group_album) {
					if ($group_album->migrated_from_files == true) {
						$group_album_guid = $group_album->getGUID();
						break;
					}
				}
			}
			$album_guid = $group_album_guid;
			$group_album_guids[] = $group_album_guid;
		} else {
			$album_guid = $user_album_guid;
		}
		
		//echo "album_guid is $album_guid and group_pic is: $group_pic\n";
		
		// create an album if we need to.
		if (!$album_guid) {
			//echo "Creating new album...\n";
			$album = new ElggObject();
			$album->subtype = 'album';
			$album->new_album = TP_NEW_ALBUM;
			
			if ($group_pic) {
				$album->container_guid = $group_guid;
				$album->owner_guid = $group->owner_guid;
				$album->access_id = $group->group_acl;
				$album->title = $group->name;
			} else {
				$album->container_guid = $user_guid;
				$album->owner_guid = $user->getGUID();
				$album->access_id = ACCESS_DEFAULT;
				$album->title = $user->name;
			}

			if (!$album->save()) {
				//echo "Couldn't migrate pics for {$user->name} ($user_guid)!\n";
				return false;
			}
			$album->migrated_from_files = true;
			$album_guid = $album->getGUID();
			$new_album_guids[] = $album_guid;
			
			// save the album guid as the users
			if (!$group_pic) {
				$user_album_guid = $album_guid;
			}
		}
		
		if (!tidypics_migrate_pic_from_files($pic, $album_guid)) {
			//echo "{$pic->filename} ({$pic->getGUID()}) Couldn't be migrated. Ignoring.\n";
			continue;
		}
	}

	// randomly pic an image to be the cover for the user gallery
	//$album->cover = $pic_guids[array_rand($pic_guids)];
	foreach ($new_album_guids as $guid) {
		tidypics_set_random_cover_pic($guid);
	}
	
	return true;
}


/**
 * Randomly pics an image from an album to be the cover.
 * @return bool on success
 */
function tidypics_set_random_cover_pic($album_guid) {
	global $CONFIG;
	
	if ($album = get_entity($album_guid) AND $album instanceof TidypicsAlbum) {
		$q = "SELECT guid FROM {$CONFIG->dbprefix}entities WHERE container_guid = $album_guid ORDER BY RAND() limit 1";
		$pic = get_data($q);
		
		return $album->cover = $pic[0]->guid;
	}
	
	return false;
}

/**
 * Migrates a single pic from the file repo.
 * @return bool on succes.
 */
function tidypics_migrate_pic_from_files($pic, $album_guid) {
	global $CONFIG, $filestore;

	// get the subtype id.
	$image_subtype_id = get_subtype_id('object', 'image');

	// hold which metadata on the files need to be changes
	// also holds the images we need to move
	$file_md_fields = array('filename', 'thumbnail', 'smallthumb', 'largethumb');

	if (!$user = get_entity($pic->owner_guid)) {
		return false;
	}

	// figure out where to move the files.
	$matrix = $filestore->make_file_matrix($user->username);
	$user_fs_path = $CONFIG->dataroot . $matrix;
	$album_fs_path = $CONFIG->dataroot . $matrix . "image/$album_guid/";
	if (!is_dir($album_fs_path)) {
		if (!mkdir($album_fs_path, 0700, true)) {
			return false;
		}
	}

	// change all the 'file/'s to 'image/'s in certain metadata
	// these are also the files we need to move.
	foreach ($file_md_fields as $md_name) {
		// $pic->$md_name = str_replace('file/', 'image/', $pic->$md_name);
		$old_file = $pic->$md_name;
		$new_file = str_replace('file/', "image/$album_guid", $old_file);

		if (!($old_fp = fopen($user_fs_path . $old_file, 'r') 
		AND $new_fp = fopen($user_fs_path . $new_file, 'w'))) {
			//echo "Could not move {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file}\n";
			continue;
		}

		while (!feof($old_fp)) {
			if (!fputs($new_fp, fread($old_fp, 8192))) {
				//echo "Could not move {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file} (Error writing.)\n";
				break;
			}
		}

		$pic->$md_name = $new_file;
	}
	// update container.
	// this doesn't work...?
	//$pic->container_guid = $album_guid;

	// delete old one.
	unlink($user_fs_path . $old_file);

	$q = "UPDATE {$CONFIG->dbprefix}entities SET subtype = $image_subtype_id, container_guid = $album_guid WHERE guid = {$pic->getGUID()}";
	//echo "Finished moving {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file}\n";

	return update_data($q);
}


/**
 * Grabs all user IDs with images in the files repo.
 * return mixed. False on fail, array of GUIDs on success.
 */
function tidypics_get_user_guids_with_pics_in_files($offset, $limit) {
	global $CONFIG;
	
	//$simpletype_ms_id = add_metastring('simple_type');
	//$image_ms_id = add_metastring('image');
	
	$q = "SELECT DISTINCT e.owner_guid 
		FROM 
			{$CONFIG->dbprefix}entities as e, 
			{$CONFIG->dbprefix}entity_subtypes as st
			
		WHERE st.subtype = 'file'
		AND e.subtype = st.id
		LIMIT $offset, $limit";

	if (!$data = get_data($q)) {
		return false;
	}
	
	// return an array of IDs
	$r = array();
	foreach ($data as $row) {
		$r[] = $row->owner_guid;
	}

	return $r;
}

/**
 * Gets a list of images for a single user.
 * @return array of GUIDs, false on fail.
 */
function tidypics_get_user_pics_from_files($user_guid) {
	if (!$user = get_entity($user_guid) AND $user instanceof ElggUser) {
		return false;
	}

	// @todo Might have to cycle this through with standard while + foreach.
	return get_entities_from_metadata('simpletype', 'image', 'object', 'file', $user_guid, 5000);
}